1 | import * as Colors from '../src/props.colors.js'
|
2 |
|
3 |
|
4 | const dictionaryMap = {
|
5 | "size-relative": "relative",
|
6 | "size-fluid": "fluid",
|
7 | "size-header": "header",
|
8 | "size-content": "content",
|
9 | "border-size": "size",
|
10 | "radius-conditional": "conditional",
|
11 | "radius-blob": "blob"
|
12 | }
|
13 |
|
14 |
|
15 | const mapToDictionaryKey = (value) => dictionaryMap[value] || value
|
16 |
|
17 |
|
18 | const getTypeKey = (metaType) => {
|
19 | if (metaType === "size" || metaType === "border-radius") {
|
20 | return metaType === "size" ? "size" : "radius"
|
21 | } else if (metaType === "border-width") {
|
22 | return "border"
|
23 | }
|
24 | return metaType
|
25 | }
|
26 |
|
27 |
|
28 | const countOccurrences = (str, letter) => (str.match(new RegExp(letter, 'g')) || []).length
|
29 |
|
30 |
|
31 | const cssVarUsageRegex = /var\(--([a-zA-Z0-9-]+)\)/g
|
32 |
|
33 |
|
34 |
|
35 | const replaceLast = (str, pattern, replacement) => {
|
36 | const match =
|
37 | typeof pattern === 'string'
|
38 | ? pattern
|
39 | : (str.match(new RegExp(pattern.source, 'g')) || []).slice(-1)[0]
|
40 | if (!match) return str
|
41 | const last = str.lastIndexOf(match)
|
42 | return last !== -1
|
43 | ? `${str.slice(0, last)}${replacement}${str.slice(last + match.length)}`
|
44 | : str
|
45 | }
|
46 |
|
47 |
|
48 | const tokenizeCSSVar = (variableName, metaType) => {
|
49 | const tokenName = replaceLast(variableName, '-', '.')
|
50 | const hyphenCount = countOccurrences(variableName, '-')
|
51 |
|
52 | if (hyphenCount > 2 && metaType === "other") {
|
53 | const [firstPart, ...restParts] = tokenName.split('-')
|
54 | return `{${metaType}.${firstPart}.${restParts.join('-')}.value}`
|
55 | }
|
56 |
|
57 | return `{${tokenName}.value}`
|
58 | };
|
59 |
|
60 |
|
61 | const cssVarToToken = (input, metaType) => {
|
62 | if (!input.toString().includes("var")) {
|
63 | return input
|
64 | }
|
65 |
|
66 | return input.replace(cssVarUsageRegex, (match, variableName) => {
|
67 | return tokenizeCSSVar(variableName, metaType)
|
68 | })
|
69 | };
|
70 |
|
71 |
|
72 | const createTokenObject = ({
|
73 | baseObj,
|
74 | mainKey,
|
75 | metaType,
|
76 | dictionarykey,
|
77 | index,
|
78 | token
|
79 | }) => {
|
80 | const typeKey = getTypeKey(metaType)
|
81 | const targetObj = baseObj[typeKey] = baseObj[typeKey] || {}
|
82 |
|
83 | if (typeKey === "size" || typeKey === "radius") {
|
84 | const shouldReplace = mainKey !== dictionarykey
|
85 | handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace)
|
86 | } else if (typeKey !== "other") {
|
87 | handleKey(targetObj, dictionarykey, index, token, metaType, true)
|
88 | } else {
|
89 | handleOtherTypes(targetObj, dictionarykey, index, token, metaType)
|
90 | }
|
91 |
|
92 | return baseObj
|
93 | }
|
94 |
|
95 |
|
96 | function handleKey(targetObj, dictionarykey, index, token, metaType, shouldReplace) {
|
97 | if (shouldReplace) {
|
98 | targetObj[dictionarykey] = targetObj[dictionarykey] || {}
|
99 | targetObj[dictionarykey][index] = { value: token, type: metaType }
|
100 | } else {
|
101 | targetObj[index] = { value: token, type: metaType }
|
102 | }
|
103 | }
|
104 |
|
105 |
|
106 | function handleOtherTypes(targetObj, dictionarykey, index, token, metaType) {
|
107 | const keyParts = dictionarykey.split("-")
|
108 |
|
109 | if (keyParts.length > 1) {
|
110 | const groupName = keyParts[0]
|
111 | targetObj[groupName] = targetObj[groupName] || {}
|
112 | targetObj[groupName][index] = { value: token, type: metaType }
|
113 |
|
114 | const rest = keyParts.slice(1)
|
115 | const subKey = rest.join("-")
|
116 |
|
117 | targetObj[groupName][subKey] = targetObj[groupName][subKey] || {}
|
118 | targetObj[groupName][subKey][index] = { value: token, type: metaType }
|
119 | }
|
120 | }
|
121 |
|
122 |
|
123 | export const toStyleDictionary = props => {
|
124 | const colors = Object.keys(Colors)
|
125 | .filter(exportName => exportName !== "default")
|
126 | .map(hueName => hueName.toLowerCase())
|
127 |
|
128 | return props.reduce((styledictionarytokens, [key, token]) => {
|
129 | const meta = {}
|
130 |
|
131 | const isLength = key.includes('size') && !key.includes('border-size')
|
132 | const isBorder = key.includes('border-size')
|
133 | const isRadius = key.includes('radius')
|
134 | const isShadow = key.includes('shadow')
|
135 | const isColor = colors.some(color => key.includes(color))
|
136 |
|
137 | if (isLength) meta.type = 'size'
|
138 | else if (isBorder) meta.type = 'border-width'
|
139 | else if (isRadius) meta.type = 'border-radius'
|
140 | else if (isShadow) meta.type = 'box-shadow'
|
141 | else if (isColor) meta.type = 'color'
|
142 | else meta.type = 'other'
|
143 |
|
144 | const keyWithoutPrefix = key.replace('--', '')
|
145 | const keyParts = keyWithoutPrefix.split('-')
|
146 | const mainKey = keyParts.length > 1 ? keyParts.slice(0, -1).join('-') : keyParts[0]
|
147 | const index = keyParts.length > 1 ? keyParts[keyParts.length - 1] : 0
|
148 |
|
149 | const dictionarykey = mapToDictionaryKey(mainKey)
|
150 |
|
151 | return createTokenObject({
|
152 | baseObj: styledictionarytokens,
|
153 | mainKey,
|
154 | metaType: meta.type,
|
155 | dictionarykey,
|
156 | index,
|
157 | token: cssVarToToken(token, meta.type)
|
158 | })
|
159 | }, {})
|
160 | }
|