mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add design metrics tokens and tooling
This commit is contained in:
1 parent
0795393fb2
commit
afffb5c01e
12 files changed
+498
-24
No files matched your search
@@ -0,0 +1,208 @@
|
||||
const TOKEN_FALLBACKS = {
|
||||
"--grid-card-min-width": "20rem",
|
||||
"--popover-backdrop-blur": "12px",
|
||||
"--toast-translate": "0.75rem",
|
||||
"--sidebar-mobile-gutter": "3rem",
|
||||
"--popup-padding-inline": "1rem",
|
||||
"--popup-padding-block": "0.75rem",
|
||||
};
|
||||
|
||||
function resolveDocument(documentRef) {
|
||||
if (documentRef && typeof documentRef === "object") {
|
||||
return documentRef;
|
||||
}
|
||||
return typeof globalThis.document === "object" ? globalThis.document : null;
|
||||
}
|
||||
|
||||
function readComputedStyle(documentRef) {
|
||||
const doc = resolveDocument(documentRef);
|
||||
if (!doc || !doc.documentElement) {
|
||||
return null;
|
||||
}
|
||||
const view = doc.defaultView || globalThis;
|
||||
if (!view || typeof view.getComputedStyle !== "function") {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return view.getComputedStyle(doc.documentElement);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readTokenFallback(tokenName) {
|
||||
const fallback = TOKEN_FALLBACKS[tokenName];
|
||||
return typeof fallback === "string" ? fallback : "";
|
||||
}
|
||||
|
||||
function sanitizeTokenName(tokenName) {
|
||||
return typeof tokenName === "string" && tokenName.trim().startsWith("--")
|
||||
? tokenName.trim()
|
||||
: "";
|
||||
}
|
||||
|
||||
function normalizeTokenValue(value) {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
export function readDesignToken(tokenName, { documentRef } = {}) {
|
||||
const token = sanitizeTokenName(tokenName);
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const doc = resolveDocument(documentRef);
|
||||
const computed = readComputedStyle(doc);
|
||||
if (computed) {
|
||||
const computedValue = normalizeTokenValue(computed.getPropertyValue(token));
|
||||
if (computedValue) {
|
||||
return computedValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (doc?.documentElement?.style) {
|
||||
const inlineValue = normalizeTokenValue(
|
||||
doc.documentElement.style.getPropertyValue(token),
|
||||
);
|
||||
if (inlineValue) {
|
||||
return inlineValue;
|
||||
}
|
||||
}
|
||||
|
||||
return readTokenFallback(token);
|
||||
}
|
||||
|
||||
function parsePixelValue(value) {
|
||||
const numeric = Number.parseFloat(value);
|
||||
return Number.isFinite(numeric) ? numeric : 0;
|
||||
}
|
||||
|
||||
function convertLengthToPixels(value, documentRef) {
|
||||
const raw = normalizeTokenValue(value);
|
||||
if (!raw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (/^-?\d*\.?\d+px$/i.test(raw)) {
|
||||
return parsePixelValue(raw);
|
||||
}
|
||||
|
||||
if (/^-?\d*\.?\d+rem$/i.test(raw)) {
|
||||
const rem = parsePixelValue(raw);
|
||||
const doc = resolveDocument(documentRef);
|
||||
let base = 16;
|
||||
const view = doc?.defaultView || globalThis;
|
||||
if (doc?.documentElement && view && typeof view.getComputedStyle === "function") {
|
||||
try {
|
||||
const computed = view.getComputedStyle(doc.documentElement);
|
||||
const fontSize = normalizeTokenValue(computed?.fontSize || "");
|
||||
const parsed = parsePixelValue(fontSize);
|
||||
if (parsed > 0) {
|
||||
base = parsed;
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore computed style errors and fall back to defaults.
|
||||
}
|
||||
}
|
||||
return rem * base;
|
||||
}
|
||||
|
||||
const doc = resolveDocument(documentRef);
|
||||
if (doc?.createElement && doc?.body) {
|
||||
try {
|
||||
const probe = doc.createElement("div");
|
||||
probe.style.position = "absolute";
|
||||
probe.style.visibility = "hidden";
|
||||
probe.style.width = "0";
|
||||
probe.style.height = raw;
|
||||
doc.body.appendChild(probe);
|
||||
const measured = probe.offsetHeight;
|
||||
doc.body.removeChild(probe);
|
||||
if (Number.isFinite(measured)) {
|
||||
return measured;
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore measurement errors and fall through to numeric parsing.
|
||||
}
|
||||
}
|
||||
|
||||
return parsePixelValue(raw);
|
||||
}
|
||||
|
||||
export function readDesignTokenAsPixels(tokenName, options = {}) {
|
||||
const raw = readDesignToken(tokenName, options);
|
||||
return convertLengthToPixels(raw, options.documentRef);
|
||||
}
|
||||
|
||||
export function getGridCardMinWidth(options = {}) {
|
||||
return readDesignToken("--grid-card-min-width", options);
|
||||
}
|
||||
|
||||
export function getGridCardMinWidthPx(options = {}) {
|
||||
return readDesignTokenAsPixels("--grid-card-min-width", options);
|
||||
}
|
||||
|
||||
export function getPopoverBackdropBlur(options = {}) {
|
||||
return readDesignToken("--popover-backdrop-blur", options);
|
||||
}
|
||||
|
||||
export function getToastTranslate(options = {}) {
|
||||
return readDesignToken("--toast-translate", options);
|
||||
}
|
||||
|
||||
export function getToastTranslatePx(options = {}) {
|
||||
return readDesignTokenAsPixels("--toast-translate", options);
|
||||
}
|
||||
|
||||
export function getSidebarMobileGutter(options = {}) {
|
||||
return readDesignToken("--sidebar-mobile-gutter", options);
|
||||
}
|
||||
|
||||
export function getSidebarMobileGutterPx(options = {}) {
|
||||
return readDesignTokenAsPixels("--sidebar-mobile-gutter", options);
|
||||
}
|
||||
|
||||
export function getPopupPaddingInline(options = {}) {
|
||||
return readDesignToken("--popup-padding-inline", options);
|
||||
}
|
||||
|
||||
export function getPopupPaddingInlinePx(options = {}) {
|
||||
return readDesignTokenAsPixels("--popup-padding-inline", options);
|
||||
}
|
||||
|
||||
export function getPopupPaddingBlock(options = {}) {
|
||||
return readDesignToken("--popup-padding-block", options);
|
||||
}
|
||||
|
||||
export function getPopupPaddingBlockPx(options = {}) {
|
||||
return readDesignTokenAsPixels("--popup-padding-block", options);
|
||||
}
|
||||
|
||||
export function getPopupOffsetPx(options = {}) {
|
||||
const inlinePadding = getPopupPaddingInlinePx(options);
|
||||
return inlinePadding > 0 ? inlinePadding / 2 : 0;
|
||||
}
|
||||
|
||||
export function getPopupViewportPaddingPx(options = {}) {
|
||||
return getPopupPaddingInlinePx(options);
|
||||
}
|
||||
|
||||
export const designMetrics = {
|
||||
readDesignToken,
|
||||
readDesignTokenAsPixels,
|
||||
getGridCardMinWidth,
|
||||
getGridCardMinWidthPx,
|
||||
getPopoverBackdropBlur,
|
||||
getToastTranslate,
|
||||
getToastTranslatePx,
|
||||
getSidebarMobileGutter,
|
||||
getSidebarMobileGutterPx,
|
||||
getPopupPaddingInline,
|
||||
getPopupPaddingInlinePx,
|
||||
getPopupPaddingBlock,
|
||||
getPopupPaddingBlockPx,
|
||||
getPopupOffsetPx,
|
||||
getPopupViewportPaddingPx,
|
||||
};
|
||||
|
||||
export default designMetrics;
|
||||
Reference in new issue
Block a user