From 2b8cb4f05bcd8e00264b56a366bacdb48be50ce4 Mon Sep 17 00:00:00 2001 From: indaco Date: Sun, 22 Oct 2023 19:19:17 +0200 Subject: [PATCH 1/9] feat: generate json for style dictionary --- build/props.js | 6 ++++++ build/to-style-dictionary.js | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 build/to-style-dictionary.js diff --git a/build/props.js b/build/props.js index fc8a4f06..47659fb5 100644 --- a/build/props.js +++ b/build/props.js @@ -22,6 +22,7 @@ import {buildPropsStylesheet} from './to-stylesheet.js' import {toTokens} from './to-tokens.js' import {toObject} from './to-object.js' import {toFigmaTokens} from './to-figmatokens.js' +import {toStyleDictionary} from './to-style-dictionary.js' const [,,prefix='',useWhere,customSubject='',filePrefix=''] = process.argv @@ -77,6 +78,11 @@ const designtokens = toTokens(jsonbundle) const JSONtokens = fs.createWriteStream('../open-props.tokens.json') JSONtokens.end(JSON.stringify(Object.fromEntries(designtokens), null, 2)) +// gen style-dictionary tokens +const styledictionary = toStyleDictionary(designtokens) +const JSONStyleDictionaryTokens = fs.createWriteStream('../open-props.style-dictionary-tokens.json') +JSONStyleDictionaryTokens.end(JSON.stringify(styledictionary, null, 2)) + // gen figma tokens const figmatokens = toFigmaTokens(jsonbundle) const FigmaTokens = fs.createWriteStream('../open-props.figma-tokens.json') diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js new file mode 100644 index 00000000..d0680b1f --- /dev/null +++ b/build/to-style-dictionary.js @@ -0,0 +1,27 @@ +export const toStyleDictionary = (designtokens) => { + const tokens = Object.fromEntries(designtokens); + + const transformedJson = {}; + + for (const item in tokens) { + const tokenInfo = tokens[item]; + + const keyWithoutPrefix = item.replace('--', ''); + const keyParts = keyWithoutPrefix.split('-'); + const mainKey = + keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0]; + const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0; + + const { $value, $type, ...meta } = tokenInfo; + const value = $value; + const type = $type; + + if (!transformedJson[mainKey]) { + transformedJson[mainKey] = {}; + } + + transformedJson[mainKey][index] = { value, type, ...meta }; + } + + return transformedJson; +}; From b57e2688f496ab10ceb99f79dffe948491571b58 Mon Sep 17 00:00:00 2001 From: indaco Date: Mon, 23 Oct 2023 16:47:11 +0200 Subject: [PATCH 2/9] chore: update package-lock.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e0659ae..1efa6ab6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-props", - "version": "1.5.16", + "version": "1.6.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "open-props", - "version": "1.5.16", + "version": "1.6.8", "license": "MIT", "devDependencies": { "ava": "^3.15.0", From 77c6534b72e4b6d9c42424d2ab3016c93bf471fb Mon Sep 17 00:00:00 2001 From: indaco Date: Mon, 23 Oct 2023 16:49:26 +0200 Subject: [PATCH 3/9] refactor(build/to-style-dictionary.js): maintains code consistency with others --- build/props.js | 6 +- build/to-style-dictionary.js | 119 +++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 21 deletions(-) diff --git a/build/props.js b/build/props.js index 47659fb5..c8f74e25 100644 --- a/build/props.js +++ b/build/props.js @@ -79,9 +79,9 @@ const JSONtokens = fs.createWriteStream('../open-props.tokens.json') JSONtokens.end(JSON.stringify(Object.fromEntries(designtokens), null, 2)) // gen style-dictionary tokens -const styledictionary = toStyleDictionary(designtokens) -const JSONStyleDictionaryTokens = fs.createWriteStream('../open-props.style-dictionary-tokens.json') -JSONStyleDictionaryTokens.end(JSON.stringify(styledictionary, null, 2)) +const styledictionarytokens = toStyleDictionary(jsonbundle) +const StyleDictionaryTokens = fs.createWriteStream('../open-props.style-dictionary-tokens.json') +StyleDictionaryTokens.end(JSON.stringify(styledictionarytokens, null, 2)) // gen figma tokens const figmatokens = toFigmaTokens(jsonbundle) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index d0680b1f..453d80f4 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -1,27 +1,110 @@ -export const toStyleDictionary = (designtokens) => { - const tokens = Object.fromEntries(designtokens); +import * as Colors from '../src/props.colors.js' - const transformedJson = {}; +const dictionaryMap = { + "size-relative": "relative", + "size-fluid": "fluid", + "size-header": "header", + "size-content": "content", + "border-size": "size", + "radius-conditional": "conditional", + "radius-blob": "blob" +}; - for (const item in tokens) { - const tokenInfo = tokens[item]; +const mapToDictionaryKey = (value) => dictionaryMap[value] || value; - const keyWithoutPrefix = item.replace('--', ''); - const keyParts = keyWithoutPrefix.split('-'); - const mainKey = - keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0]; - const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0; +const getTypeKey = (metaType) => { + if (metaType === "size" || metaType === "border-radius") { + return metaType === "size" ? "size" : "radius" + } else if (metaType === "border-width") { + return "border" + } + return metaType +}; - const { $value, $type, ...meta } = tokenInfo; - const value = $value; - const type = $type; +const createTokenObject = ({ + baseObj, + mainKey, + metaType, + dictionarykey, + index, + token +}) => { + // Determine if the main key should be handled separately + const shouldHandleMainKey = mainKey !== dictionarykey + // Determine the type key based on metaType + const typeKey = getTypeKey(metaType) - if (!transformedJson[mainKey]) { - transformedJson[mainKey] = {}; - } + // Initialize the typeKey in the baseObj if it doesn't exist + baseObj[typeKey] = baseObj[typeKey] || {} + // Define the target object + const targetObj = baseObj[typeKey] - transformedJson[mainKey][index] = { value, type, ...meta }; + if(typeKey === "size" || typeKey === "radius") { + if(shouldHandleMainKey){ + // Handle main key separately + targetObj[dictionarykey] = targetObj[dictionarykey] || {} + targetObj[dictionarykey][index] = { + value: token, + type: metaType + } + } else { + // Handle main key directly + targetObj[index] = { + value: token, + type: metaType + } + } + } else { + // Handle all other types + targetObj[dictionarykey] = targetObj[dictionarykey] || {} + targetObj[dictionarykey][index] = { + value: token, + type: metaType + } } - return transformedJson; + return baseObj }; + +export const toStyleDictionary = props => { + const styledictionarytokens = {} + + const colors = Object.keys(Colors) + .filter(exportName => exportName !== "default") + .map(hueName => hueName.toLowerCase()) + + props.forEach(([key, token]) => { + const meta = {} + + const isLength = key.includes('size') && !key.includes('border-size') + const isBorder = key.includes('border-size') + const isRadius = key.includes('radius') + const isShadow = key.includes('shadow') + const isColor = colors.some(color => key.includes(color)) + + if (isLength) meta.type = 'size' + else if (isBorder) meta.type = 'border-width' + else if (isRadius) meta.type = 'border-radius' + else if (isShadow) meta.type = 'box-shadow' + else if (isColor) meta.type = 'color' + else meta.type = 'other' + + const keyWithoutPrefix = key.replace('--', '') + const keyParts = keyWithoutPrefix.split('-') + const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0] + const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0 + + const dictionarykey = mapToDictionaryKey(mainKey) + + createTokenObject({ + baseObj: styledictionarytokens, + mainKey: mainKey, + metaType: meta.type, + dictionarykey: dictionarykey, + index: index, + token: token + }) + }) + + return styledictionarytokens +} \ No newline at end of file From cb1ff54281163328e27612294752d0e456dd3c75 Mon Sep 17 00:00:00 2001 From: indaco Date: Mon, 23 Oct 2023 18:44:24 +0200 Subject: [PATCH 4/9] fix(build/to-style-dictionary.js): references to existing tokens --- build/to-style-dictionary.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index 453d80f4..807af565 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -21,6 +21,37 @@ const getTypeKey = (metaType) => { return metaType }; +const countOccurrences = (str, letter) => (str.match(new RegExp(letter, 'g')) || []).length; + +const cssVarUsageRegex = /var\(--([a-zA-Z0-9-]+)\)/g + +/* https://www.30secondsofcode.org/js/s/replace-last-occurrence/ */ +const replaceLast = (str, pattern, replacement) => { + const match = + typeof pattern === 'string' + ? pattern + : (str.match(new RegExp(pattern.source, 'g')) || []).slice(-1)[0] + if (!match) return str + const last = str.lastIndexOf(match) + return last !== -1 + ? `${str.slice(0, last)}${replacement}${str.slice(last + match.length)}` + : str +}; + +const cssVarToTokenReference = (input) => { + if (input.toString().indexOf("var") !== -1) { + + return input.replace(cssVarUsageRegex, (match, variableName) => { + if (countOccurrences(variableName, '-') > 1) { + const varParts = replaceLast(variableName, '-', '.'); + return `{${varParts}.value}`; + } + return `{${variableName.replace("-", ".")}.value}`; + }); + } + return input; +}; + const createTokenObject = ({ baseObj, mainKey, @@ -102,7 +133,7 @@ export const toStyleDictionary = props => { metaType: meta.type, dictionarykey: dictionarykey, index: index, - token: token + token: cssVarToTokenReference(token) }) }) From 3a44bc5b8d3f02983af1978bfadb4da9e301147f Mon Sep 17 00:00:00 2001 From: indaco Date: Mon, 23 Oct 2023 19:03:44 +0200 Subject: [PATCH 5/9] chore: add export entry for `open-props.style-dictionary-tokens.json` --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index eca9bf84..64a78e94 100644 --- a/package.json +++ b/package.json @@ -171,6 +171,7 @@ "./json": "./open-props.tokens.json", "./tokens": "./open-props.tokens.json", "./design-tokens": "./open-props.tokens.json", + "./style-dictionary-tokens": "./open-props.style-dictionary-tokens.json", "./postcss/brand": "./src/extra/brand.css", "./postcss/theme": "./src/extra/theme.css", "./postcss/theme-dark": "./src/extra/theme-dark.css", From 85baffafd5780e0fcf5a46a49a693154e19e2941 Mon Sep 17 00:00:00 2001 From: indaco Date: Tue, 24 Oct 2023 08:39:22 +0200 Subject: [PATCH 6/9] feat(build/to-style-dictionary.js): nested tokens for 'other' meta types --- build/to-style-dictionary.js | 69 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index 807af565..608812e8 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -60,42 +60,45 @@ const createTokenObject = ({ index, token }) => { - // Determine if the main key should be handled separately - const shouldHandleMainKey = mainKey !== dictionarykey - // Determine the type key based on metaType - const typeKey = getTypeKey(metaType) - - // Initialize the typeKey in the baseObj if it doesn't exist - baseObj[typeKey] = baseObj[typeKey] || {} - // Define the target object - const targetObj = baseObj[typeKey] - - if(typeKey === "size" || typeKey === "radius") { - if(shouldHandleMainKey){ - // Handle main key separately - targetObj[dictionarykey] = targetObj[dictionarykey] || {} - targetObj[dictionarykey][index] = { - value: token, - type: metaType - } - } else { - // Handle main key directly - targetObj[index] = { - value: token, - type: metaType - } - } + const typeKey = getTypeKey(metaType); + const targetObj = baseObj[typeKey] = baseObj[typeKey] || {}; + + if (typeKey === "size" || typeKey === "radius") { + const shouldReplace = mainKey !== dictionarykey + handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace); + } else if (typeKey !== "other") { + handleKey(targetObj, dictionarykey, index, token, metaType, true); } else { - // Handle all other types - targetObj[dictionarykey] = targetObj[dictionarykey] || {} - targetObj[dictionarykey][index] = { - value: token, - type: metaType - } + handleOtherTypes(targetObj, dictionarykey, index, token, metaType); } - return baseObj -}; + return baseObj; +} + +// Handle cases where meta.type != "other" +function handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace) { + if (shouldReplace) { + targetObj[dictionarykey] = targetObj[dictionarykey] || {}; + targetObj[dictionarykey][index] = { value: token, type: metaType }; + } else { + targetObj[index] = { value: token, type: metaType }; + } +} + +// Handle cases where meta.type = "other" +function handleOtherTypes(targetObj, dictionarykey, index, token, metaType) { + const keyParts = dictionarykey.split("-"); + if (keyParts.length > 1) { + const groupName = keyParts[0]; + targetObj[groupName] = targetObj[groupName] || {}; + targetObj[groupName][index] = { value: token, type: metaType }; + + const rest = keyParts.slice(1); + const subKey = rest.join("-"); + targetObj[groupName][subKey] = targetObj[groupName][subKey] || {}; + targetObj[groupName][subKey][index] = { value: token, type: metaType }; + } +} export const toStyleDictionary = props => { const styledictionarytokens = {} From 017ea51537bee5cc649e5a7ca53b949f80aa0b51 Mon Sep 17 00:00:00 2001 From: indaco Date: Tue, 24 Oct 2023 08:41:18 +0200 Subject: [PATCH 7/9] refactor(build/to-style-dictionary.js): replace the forEach loop with reduce --- build/to-style-dictionary.js | 71 +++++++++++++++++------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index 608812e8..e962de49 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -101,44 +101,39 @@ function handleOtherTypes(targetObj, dictionarykey, index, token, metaType) { } export const toStyleDictionary = props => { - const styledictionarytokens = {} - const colors = Object.keys(Colors) - .filter(exportName => exportName !== "default") - .map(hueName => hueName.toLowerCase()) - - props.forEach(([key, token]) => { - const meta = {} - - const isLength = key.includes('size') && !key.includes('border-size') - const isBorder = key.includes('border-size') - const isRadius = key.includes('radius') - const isShadow = key.includes('shadow') - const isColor = colors.some(color => key.includes(color)) - - if (isLength) meta.type = 'size' - else if (isBorder) meta.type = 'border-width' - else if (isRadius) meta.type = 'border-radius' - else if (isShadow) meta.type = 'box-shadow' - else if (isColor) meta.type = 'color' - else meta.type = 'other' - - const keyWithoutPrefix = key.replace('--', '') - const keyParts = keyWithoutPrefix.split('-') - const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0] - const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0 - - const dictionarykey = mapToDictionaryKey(mainKey) - - createTokenObject({ + .filter(exportName => exportName !== "default") + .map(hueName => hueName.toLowerCase()) + + return props.reduce((styledictionarytokens, [key, token]) => { + const meta = {}; + const isLength = key.includes('size') && !key.includes('border-size'); + const isBorder = key.includes('border-size'); + const isRadius = key.includes('radius'); + const isShadow = key.includes('shadow'); + const isColor = colors.some(color => key.includes(color)); + + if (isLength) meta.type = 'size'; + else if (isBorder) meta.type = 'border-width'; + else if (isRadius) meta.type = 'border-radius'; + else if (isShadow) meta.type = 'box-shadow'; + else if (isColor) meta.type = 'color'; + else meta.type = 'other'; + + const keyWithoutPrefix = key.replace('--', ''); + const keyParts = keyWithoutPrefix.split('-'); + const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0]; + const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0; + + const dictionarykey = mapToDictionaryKey(mainKey); + + return createTokenObject({ baseObj: styledictionarytokens, - mainKey: mainKey, + mainKey, metaType: meta.type, - dictionarykey: dictionarykey, - index: index, - token: cssVarToTokenReference(token) - }) - }) - - return styledictionarytokens -} \ No newline at end of file + dictionarykey, + index, + token: cssVarToTokenReference(token), + }); + }, {}); +} From 1c2efc4ddcae09f9421c1c01b7741c0a58123090 Mon Sep 17 00:00:00 2001 From: indaco Date: Tue, 24 Oct 2023 08:51:32 +0200 Subject: [PATCH 8/9] style(build/to-style-dictionary.js): adhere to the formatting style of the code --- build/to-style-dictionary.js | 108 ++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index e962de49..d22157b2 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -8,9 +8,9 @@ const dictionaryMap = { "border-size": "size", "radius-conditional": "conditional", "radius-blob": "blob" -}; +} -const mapToDictionaryKey = (value) => dictionaryMap[value] || value; +const mapToDictionaryKey = (value) => dictionaryMap[value] || value const getTypeKey = (metaType) => { if (metaType === "size" || metaType === "border-radius") { @@ -19,9 +19,9 @@ const getTypeKey = (metaType) => { return "border" } return metaType -}; +} -const countOccurrences = (str, letter) => (str.match(new RegExp(letter, 'g')) || []).length; +const countOccurrences = (str, letter) => (str.match(new RegExp(letter, 'g')) || []).length const cssVarUsageRegex = /var\(--([a-zA-Z0-9-]+)\)/g @@ -36,21 +36,20 @@ const replaceLast = (str, pattern, replacement) => { return last !== -1 ? `${str.slice(0, last)}${replacement}${str.slice(last + match.length)}` : str -}; +} const cssVarToTokenReference = (input) => { if (input.toString().indexOf("var") !== -1) { - return input.replace(cssVarUsageRegex, (match, variableName) => { if (countOccurrences(variableName, '-') > 1) { - const varParts = replaceLast(variableName, '-', '.'); - return `{${varParts}.value}`; + const varParts = replaceLast(variableName, '-', '.') + return `{${varParts}.value}` } - return `{${variableName.replace("-", ".")}.value}`; - }); + return `{${variableName.replace("-", ".")}.value}` + }) } - return input; -}; + return input +} const createTokenObject = ({ baseObj, @@ -60,43 +59,45 @@ const createTokenObject = ({ index, token }) => { - const typeKey = getTypeKey(metaType); - const targetObj = baseObj[typeKey] = baseObj[typeKey] || {}; + const typeKey = getTypeKey(metaType) + const targetObj = baseObj[typeKey] = baseObj[typeKey] || {} if (typeKey === "size" || typeKey === "radius") { const shouldReplace = mainKey !== dictionarykey - handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace); + handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace) } else if (typeKey !== "other") { - handleKey(targetObj, dictionarykey, index, token, metaType, true); + handleKey(targetObj, dictionarykey, index, token, metaType, true) } else { - handleOtherTypes(targetObj, dictionarykey, index, token, metaType); + handleOtherTypes(targetObj, dictionarykey, index, token, metaType) } - return baseObj; + return baseObj } // Handle cases where meta.type != "other" function handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace) { if (shouldReplace) { - targetObj[dictionarykey] = targetObj[dictionarykey] || {}; - targetObj[dictionarykey][index] = { value: token, type: metaType }; + targetObj[dictionarykey] = targetObj[dictionarykey] || {} + targetObj[dictionarykey][index] = { value: token, type: metaType } } else { - targetObj[index] = { value: token, type: metaType }; + targetObj[index] = { value: token, type: metaType } } } // Handle cases where meta.type = "other" function handleOtherTypes(targetObj, dictionarykey, index, token, metaType) { - const keyParts = dictionarykey.split("-"); + const keyParts = dictionarykey.split("-") + if (keyParts.length > 1) { - const groupName = keyParts[0]; - targetObj[groupName] = targetObj[groupName] || {}; - targetObj[groupName][index] = { value: token, type: metaType }; - - const rest = keyParts.slice(1); - const subKey = rest.join("-"); - targetObj[groupName][subKey] = targetObj[groupName][subKey] || {}; - targetObj[groupName][subKey][index] = { value: token, type: metaType }; + const groupName = keyParts[0] + targetObj[groupName] = targetObj[groupName] || {} + targetObj[groupName][index] = { value: token, type: metaType } + + const rest = keyParts.slice(1) + const subKey = rest.join("-") + + targetObj[groupName][subKey] = targetObj[groupName][subKey] || {} + targetObj[groupName][subKey][index] = { value: token, type: metaType } } } @@ -106,26 +107,27 @@ export const toStyleDictionary = props => { .map(hueName => hueName.toLowerCase()) return props.reduce((styledictionarytokens, [key, token]) => { - const meta = {}; - const isLength = key.includes('size') && !key.includes('border-size'); - const isBorder = key.includes('border-size'); - const isRadius = key.includes('radius'); - const isShadow = key.includes('shadow'); - const isColor = colors.some(color => key.includes(color)); - - if (isLength) meta.type = 'size'; - else if (isBorder) meta.type = 'border-width'; - else if (isRadius) meta.type = 'border-radius'; - else if (isShadow) meta.type = 'box-shadow'; - else if (isColor) meta.type = 'color'; - else meta.type = 'other'; - - const keyWithoutPrefix = key.replace('--', ''); - const keyParts = keyWithoutPrefix.split('-'); - const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0]; - const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0; - - const dictionarykey = mapToDictionaryKey(mainKey); + const meta = {} + + const isLength = key.includes('size') && !key.includes('border-size') + const isBorder = key.includes('border-size') + const isRadius = key.includes('radius') + const isShadow = key.includes('shadow') + const isColor = colors.some(color => key.includes(color)) + + if (isLength) meta.type = 'size' + else if (isBorder) meta.type = 'border-width' + else if (isRadius) meta.type = 'border-radius' + else if (isShadow) meta.type = 'box-shadow' + else if (isColor) meta.type = 'color' + else meta.type = 'other' + + const keyWithoutPrefix = key.replace('--', '') + const keyParts = keyWithoutPrefix.split('-') + const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0] + const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0 + + const dictionarykey = mapToDictionaryKey(mainKey) return createTokenObject({ baseObj: styledictionarytokens, @@ -133,7 +135,7 @@ export const toStyleDictionary = props => { metaType: meta.type, dictionarykey, index, - token: cssVarToTokenReference(token), - }); - }, {}); + token: cssVarToTokenReference(token) + }) + }, {}) } From 8b0d2779a7d6b1acc5b99b9a3a7251ee88f38fb8 Mon Sep 17 00:00:00 2001 From: indaco Date: Tue, 24 Oct 2023 10:21:58 +0200 Subject: [PATCH 9/9] fix(build/to-style-dictionary.js): references to existing tokens when nested --- build/to-style-dictionary.js | 43 ++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/build/to-style-dictionary.js b/build/to-style-dictionary.js index d22157b2..875aa319 100644 --- a/build/to-style-dictionary.js +++ b/build/to-style-dictionary.js @@ -1,5 +1,6 @@ import * as Colors from '../src/props.colors.js' +// Mapping of CSS variable names to dictionary keys const dictionaryMap = { "size-relative": "relative", "size-fluid": "fluid", @@ -10,8 +11,10 @@ const dictionaryMap = { "radius-blob": "blob" } +// Map a value to a dictionary key using the dictionaryMap const mapToDictionaryKey = (value) => dictionaryMap[value] || value +// Determine the type key based on the metaType const getTypeKey = (metaType) => { if (metaType === "size" || metaType === "border-radius") { return metaType === "size" ? "size" : "radius" @@ -21,10 +24,13 @@ const getTypeKey = (metaType) => { return metaType } +// Count the occurrences of a character in a string const countOccurrences = (str, letter) => (str.match(new RegExp(letter, 'g')) || []).length +// Regular expression to match CSS variable usages const cssVarUsageRegex = /var\(--([a-zA-Z0-9-]+)\)/g +// Replace the last occurrence of a pattern with a replacement /* https://www.30secondsofcode.org/js/s/replace-last-occurrence/ */ const replaceLast = (str, pattern, replacement) => { const match = @@ -38,19 +44,31 @@ const replaceLast = (str, pattern, replacement) => { : str } -const cssVarToTokenReference = (input) => { - if (input.toString().indexOf("var") !== -1) { - return input.replace(cssVarUsageRegex, (match, variableName) => { - if (countOccurrences(variableName, '-') > 1) { - const varParts = replaceLast(variableName, '-', '.') - return `{${varParts}.value}` - } - return `{${variableName.replace("-", ".")}.value}` - }) +// Helper function to convert CSS variable name to token reference +const tokenizeCSSVar = (variableName, metaType) => { + const tokenName = replaceLast(variableName, '-', '.') + const hyphenCount = countOccurrences(variableName, '-') + + if (hyphenCount > 2 && metaType === "other") { + const [firstPart, ...restParts] = tokenName.split('-') + return `{${metaType}.${firstPart}.${restParts.join('-')}.value}` } - return input -} + return `{${tokenName}.value}` +}; + +// Convert CSS variable usages to token references +const cssVarToToken = (input, metaType) => { + if (!input.toString().includes("var")) { + return input + } + + return input.replace(cssVarUsageRegex, (match, variableName) => { + return tokenizeCSSVar(variableName, metaType) + }) +}; + +// Create a token object based on metaType and dictionary key const createTokenObject = ({ baseObj, mainKey, @@ -101,6 +119,7 @@ function handleOtherTypes(targetObj, dictionarykey, index, token, metaType) { } } +// Generate a style dictionary export const toStyleDictionary = props => { const colors = Object.keys(Colors) .filter(exportName => exportName !== "default") @@ -135,7 +154,7 @@ export const toStyleDictionary = props => { metaType: meta.type, dictionarykey, index, - token: cssVarToTokenReference(token) + token: cssVarToToken(token, meta.type) }) }, {}) }