From b8a5c2ca504b6ab462f768b423a392269fe481c6 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Mon, 5 Jan 2026 09:57:57 -0600 Subject: [PATCH 1/3] fix: update semantic token values in table --- .../docTokenTable/docTokenTable.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx index d163553ac..8c787c940 100644 --- a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx +++ b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx @@ -11,6 +11,9 @@ interface Token { [key: string]: TokenEntry | Token; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type CoreTokens = Record; + interface DocTokenTableProps { category: string; tier: string; @@ -80,11 +83,50 @@ const formattedCategoryName = { const DocTokenTable: React.FC = ({ category, tier, use }) => { const [pineTokens, setPineTokens] = useState(null); + const [coreTokens, setCoreTokens] = useState(null); + + // Resolve a reference like {color.grey.100} to its actual value from core tokens + const resolveReference = (value: string, cores: CoreTokens): string => { + if (typeof value !== 'string') return value; + + // Match references like {color.grey.100} or {font-size.100} + const refMatch = value.match(/^\{([^}]+)\}$/); + if (!refMatch || !cores) return value; + + const refPath = refMatch[1]; // e.g., "color.grey.100" or "font-size.100" + const parts = refPath.split('.'); + + // Navigate through the core tokens to find the value + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let current: any = cores; + for (const part of parts) { + if (current && typeof current === 'object' && part in current) { + current = current[part]; + } else { + // If we can't find the path, return the original reference + return value; + } + } + + // If we found a token entry with a value, return it + if (current && typeof current === 'object' && 'value' in current) { + return current.value; + } + + return value; + }; useEffect(() => { const loadTokens = async () => { try { const tokenModule = await import(`../../../../../node_modules/@kajabi-ui/styles/dist/tokens/${tier}.json`); + + // Also load core tokens when viewing semantic tier + if (tier === 'semantic') { + const coreModule = await import(`../../../../../node_modules/@kajabi-ui/styles/dist/tokens/core.json`); + setCoreTokens(coreModule.default as CoreTokens); + } + const categories = categoryLookup[category]?.[tier] || null; if (categories) { const tempTokens: Token[] = []; @@ -164,6 +206,11 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => } } + // Resolve references to actual values for semantic tier + if (tier === 'semantic' && coreTokens && cssPropertyValue) { + cssPropertyValue = resolveReference(cssPropertyValue, coreTokens); + } + let style: React.CSSProperties = {}; // Render "Aa" preview only for text-based styles let previewDiv =
Aa
; From f111f12cab4c273c71a70c82f792b16d814d421c Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Mon, 5 Jan 2026 10:10:15 -0600 Subject: [PATCH 2/3] fix: resolve nested token values --- .../docTokenTable/docTokenTable.tsx | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx index 8c787c940..10911e1b3 100644 --- a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx +++ b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx @@ -85,15 +85,9 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => const [pineTokens, setPineTokens] = useState(null); const [coreTokens, setCoreTokens] = useState(null); - // Resolve a reference like {color.grey.100} to its actual value from core tokens - const resolveReference = (value: string, cores: CoreTokens): string => { - if (typeof value !== 'string') return value; - - // Match references like {color.grey.100} or {font-size.100} - const refMatch = value.match(/^\{([^}]+)\}$/); - if (!refMatch || !cores) return value; - - const refPath = refMatch[1]; // e.g., "color.grey.100" or "font-size.100" + // Look up a single reference path in the core tokens + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const lookupCoreValue = (refPath: string, cores: CoreTokens): any => { const parts = refPath.split('.'); // Navigate through the core tokens to find the value @@ -103,8 +97,7 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => if (current && typeof current === 'object' && part in current) { current = current[part]; } else { - // If we can't find the path, return the original reference - return value; + return null; // Path not found } } @@ -113,7 +106,51 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => return current.value; } - return value; + return null; + }; + + // Convert a complex value (like box-shadow object) to a string + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const complexValueToString = (value: any): string => { + if (typeof value === 'string') return value; + + // Handle box-shadow array of objects + if (Array.isArray(value)) { + return value.map(item => { + if (typeof item === 'object' && item !== null) { + // Box shadow object: { x, y, blur, spread, color, type } + const { x, y, blur, spread, color } = item; + return `${x} ${y} ${blur} ${spread} ${color}`.trim(); + } + return String(item); + }).join(', '); + } + + // Handle single box-shadow object + if (typeof value === 'object' && value !== null) { + const { x, y, blur, spread, color } = value; + if (x !== undefined) { + return `${x} ${y} ${blur} ${spread} ${color}`.trim(); + } + // For other objects, try to extract values + return Object.values(value).filter(v => v !== 'dropShadow').join(' '); + } + + return String(value); + }; + + // Resolve references in a value string to actual core values + const resolveReferences = (value: string, cores: CoreTokens): string => { + if (typeof value !== 'string') return String(value); + + // Replace all references like {color.grey.100} with their resolved values + return value.replace(/\{([^}]+)\}/g, (match, refPath) => { + const resolvedValue = lookupCoreValue(refPath, cores); + if (resolvedValue !== null) { + return complexValueToString(resolvedValue); + } + return match; // Keep original if not found + }); }; useEffect(() => { @@ -208,7 +245,7 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => // Resolve references to actual values for semantic tier if (tier === 'semantic' && coreTokens && cssPropertyValue) { - cssPropertyValue = resolveReference(cssPropertyValue, coreTokens); + cssPropertyValue = resolveReferences(cssPropertyValue, coreTokens); } let style: React.CSSProperties = {}; From 105f6c2f0f3d733dbc8a1d4a326ee82b90e92bc9 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Mon, 5 Jan 2026 10:28:07 -0600 Subject: [PATCH 3/3] fix: resolve Box-shadow property destructuring may produce "undefined" in output --- .../docTokenTable/docTokenTable.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx index 10911e1b3..20eff5acc 100644 --- a/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx +++ b/libs/doc-components/src/components/docTokenTable/docTokenTable.tsx @@ -114,13 +114,20 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => const complexValueToString = (value: any): string => { if (typeof value === 'string') return value; + // Helper to build box-shadow string from object, filtering out missing values + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const boxShadowObjectToString = (obj: any): string => { + const { x, y, blur, spread, color } = obj; + return [x, y, blur, spread, color] + .filter(v => v != null && v !== '') + .join(' '); + }; + // Handle box-shadow array of objects if (Array.isArray(value)) { return value.map(item => { if (typeof item === 'object' && item !== null) { - // Box shadow object: { x, y, blur, spread, color, type } - const { x, y, blur, spread, color } = item; - return `${x} ${y} ${blur} ${spread} ${color}`.trim(); + return boxShadowObjectToString(item); } return String(item); }).join(', '); @@ -128,12 +135,14 @@ const DocTokenTable: React.FC = ({ category, tier, use }) => // Handle single box-shadow object if (typeof value === 'object' && value !== null) { - const { x, y, blur, spread, color } = value; + const { x } = value; if (x !== undefined) { - return `${x} ${y} ${blur} ${spread} ${color}`.trim(); + return boxShadowObjectToString(value); } // For other objects, try to extract values - return Object.values(value).filter(v => v !== 'dropShadow').join(' '); + return Object.values(value) + .filter(v => v != null && v !== '' && v !== 'dropShadow') + .join(' '); } return String(value);