@symbo.ls/scratch 3.14.2 → 3.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/index.cjs +1 -0
  3. package/dist/cjs/src/defaultConfig/animation.cjs +1 -0
  4. package/dist/cjs/src/defaultConfig/cases.cjs +1 -0
  5. package/dist/cjs/src/defaultConfig/class.cjs +1 -0
  6. package/dist/cjs/src/defaultConfig/color.cjs +1 -0
  7. package/dist/cjs/src/defaultConfig/document.cjs +1 -0
  8. package/dist/cjs/src/defaultConfig/font-family.cjs +1 -0
  9. package/dist/cjs/src/defaultConfig/font.cjs +1 -0
  10. package/dist/cjs/src/defaultConfig/grid.cjs +1 -0
  11. package/dist/cjs/src/defaultConfig/icons.cjs +1 -0
  12. package/dist/cjs/src/defaultConfig/index.cjs +1 -0
  13. package/dist/cjs/src/defaultConfig/media.cjs +1 -0
  14. package/dist/cjs/src/defaultConfig/responsive.cjs +1 -0
  15. package/dist/cjs/src/defaultConfig/sequence.cjs +1 -0
  16. package/dist/cjs/src/defaultConfig/shadow.cjs +1 -0
  17. package/dist/cjs/src/defaultConfig/spacing.cjs +1 -0
  18. package/dist/cjs/src/defaultConfig/svg.cjs +1 -0
  19. package/dist/cjs/src/defaultConfig/templates.cjs +1 -0
  20. package/dist/cjs/src/defaultConfig/theme.cjs +1 -0
  21. package/dist/cjs/src/defaultConfig/timing.cjs +1 -0
  22. package/dist/cjs/src/defaultConfig/typography.cjs +1 -0
  23. package/dist/cjs/src/defaultConfig/unit.cjs +1 -0
  24. package/dist/cjs/src/factory.cjs +1 -0
  25. package/dist/cjs/src/index.cjs +1 -0
  26. package/dist/cjs/src/set.cjs +1 -0
  27. package/dist/cjs/src/system/color.cjs +1 -0
  28. package/dist/cjs/src/system/document.cjs +1 -0
  29. package/dist/cjs/src/system/font.cjs +1 -0
  30. package/dist/cjs/src/system/index.cjs +1 -0
  31. package/dist/cjs/src/system/reset.cjs +1 -0
  32. package/dist/cjs/src/system/shadow.cjs +1 -0
  33. package/dist/cjs/src/system/spacing.cjs +1 -0
  34. package/dist/cjs/src/system/svg.cjs +1 -0
  35. package/dist/cjs/src/system/theme.cjs +1 -0
  36. package/dist/cjs/src/system/timing.cjs +1 -0
  37. package/dist/cjs/src/system/typography.cjs +1 -0
  38. package/dist/cjs/src/tests/index.cjs +1 -0
  39. package/dist/cjs/src/transforms/index.cjs +1 -0
  40. package/dist/cjs/src/utils/color.cjs +1 -0
  41. package/dist/cjs/src/utils/font.cjs +9 -0
  42. package/dist/cjs/src/utils/index.cjs +1 -0
  43. package/dist/cjs/src/utils/sequence.cjs +1 -0
  44. package/dist/cjs/src/utils/sprite.cjs +1 -0
  45. package/dist/cjs/src/utils/theme.cjs +1 -0
  46. package/dist/cjs/src/utils/unit.cjs +1 -0
  47. package/dist/cjs/src/utils/var.cjs +1 -0
  48. package/dist/esm/index.js +1 -0
  49. package/dist/esm/src/defaultConfig/animation.js +1 -0
  50. package/dist/esm/src/defaultConfig/cases.js +1 -0
  51. package/dist/esm/src/defaultConfig/class.js +1 -0
  52. package/dist/esm/src/defaultConfig/color.js +1 -0
  53. package/dist/esm/src/defaultConfig/document.js +1 -0
  54. package/dist/esm/src/defaultConfig/font-family.js +1 -0
  55. package/dist/esm/src/defaultConfig/font.js +1 -0
  56. package/dist/esm/src/defaultConfig/grid.js +1 -0
  57. package/dist/esm/src/defaultConfig/icons.js +1 -0
  58. package/dist/esm/src/defaultConfig/index.js +1 -0
  59. package/dist/esm/src/defaultConfig/media.js +1 -0
  60. package/dist/esm/src/defaultConfig/responsive.js +1 -0
  61. package/dist/esm/src/defaultConfig/sequence.js +1 -0
  62. package/dist/esm/src/defaultConfig/shadow.js +1 -0
  63. package/dist/esm/src/defaultConfig/spacing.js +1 -0
  64. package/dist/esm/src/defaultConfig/svg.js +1 -0
  65. package/dist/esm/src/defaultConfig/templates.js +1 -0
  66. package/dist/esm/src/defaultConfig/theme.js +1 -0
  67. package/dist/esm/src/defaultConfig/timing.js +1 -0
  68. package/dist/esm/src/defaultConfig/typography.js +1 -0
  69. package/dist/esm/src/defaultConfig/unit.js +1 -0
  70. package/dist/esm/src/factory.js +1 -0
  71. package/dist/esm/src/index.js +1 -0
  72. package/dist/esm/src/set.js +1 -0
  73. package/dist/esm/src/system/color.js +1 -0
  74. package/dist/esm/src/system/document.js +1 -0
  75. package/dist/esm/src/system/font.js +1 -0
  76. package/dist/esm/src/system/index.js +1 -0
  77. package/dist/esm/src/system/reset.js +1 -0
  78. package/dist/esm/src/system/shadow.js +1 -0
  79. package/dist/esm/src/system/spacing.js +1 -0
  80. package/dist/esm/src/system/svg.js +1 -0
  81. package/dist/esm/src/system/theme.js +1 -0
  82. package/dist/esm/src/system/timing.js +1 -0
  83. package/dist/esm/src/system/typography.js +1 -0
  84. package/dist/esm/src/tests/index.js +1 -0
  85. package/dist/esm/src/transforms/index.js +1 -0
  86. package/dist/esm/src/utils/color.js +1 -0
  87. package/dist/esm/src/utils/font.js +9 -0
  88. package/dist/esm/src/utils/index.js +1 -0
  89. package/dist/esm/src/utils/sequence.js +1 -0
  90. package/dist/esm/src/utils/sprite.js +1 -0
  91. package/dist/esm/src/utils/theme.js +1 -0
  92. package/dist/esm/src/utils/unit.js +1 -0
  93. package/dist/esm/src/utils/var.js +1 -0
  94. package/package.json +16 -15
  95. package/index.js +0 -1
  96. package/src/defaultConfig/animation.js +0 -3
  97. package/src/defaultConfig/cases.js +0 -3
  98. package/src/defaultConfig/class.js +0 -6
  99. package/src/defaultConfig/color.js +0 -9
  100. package/src/defaultConfig/document.js +0 -3
  101. package/src/defaultConfig/font-family.js +0 -15
  102. package/src/defaultConfig/font.js +0 -12
  103. package/src/defaultConfig/grid.js +0 -5
  104. package/src/defaultConfig/icons.js +0 -4
  105. package/src/defaultConfig/index.js +0 -24
  106. package/src/defaultConfig/media.js +0 -10
  107. package/src/defaultConfig/responsive.js +0 -29
  108. package/src/defaultConfig/sequence.js +0 -24
  109. package/src/defaultConfig/shadow.js +0 -3
  110. package/src/defaultConfig/spacing.js +0 -19
  111. package/src/defaultConfig/svg.js +0 -4
  112. package/src/defaultConfig/templates.js +0 -3
  113. package/src/defaultConfig/theme.js +0 -13
  114. package/src/defaultConfig/timing.js +0 -18
  115. package/src/defaultConfig/typography.js +0 -22
  116. package/src/defaultConfig/unit.js +0 -5
  117. package/src/factory.js +0 -135
  118. package/src/index.js +0 -24
  119. package/src/set.js +0 -353
  120. package/src/system/color.js +0 -327
  121. package/src/system/document.js +0 -16
  122. package/src/system/font.js +0 -66
  123. package/src/system/index.js +0 -12
  124. package/src/system/reset.js +0 -119
  125. package/src/system/shadow.js +0 -107
  126. package/src/system/spacing.js +0 -152
  127. package/src/system/svg.js +0 -132
  128. package/src/system/theme.js +0 -454
  129. package/src/system/timing.js +0 -32
  130. package/src/system/typography.js +0 -110
  131. package/src/tests/index.js +0 -4
  132. package/src/transforms/index.js +0 -270
  133. package/src/utils/color.js +0 -269
  134. package/src/utils/font.js +0 -116
  135. package/src/utils/index.js +0 -9
  136. package/src/utils/sequence.js +0 -386
  137. package/src/utils/sprite.js +0 -107
  138. package/src/utils/theme.js +0 -8
  139. package/src/utils/unit.js +0 -72
  140. package/src/utils/var.js +0 -129
@@ -1,386 +0,0 @@
1
- 'use strict'
2
-
3
- import { isString } from '@symbo.ls/utils'
4
- import { toDashCase } from '@symbo.ls/utils'
5
- import { getActiveConfig } from '../factory.js'
6
- import { CSS_UNITS, isScalingUnit } from './unit.js'
7
- import { isCSSVar } from './color.js'
8
-
9
- export const numToLetterMap = {
10
- '-6': 'U',
11
- '-5': 'V',
12
- '-4': 'W',
13
- '-3': 'X',
14
- '-2': 'Y',
15
- '-1': 'Z',
16
- 0: 'A',
17
- 1: 'B',
18
- 2: 'C',
19
- 3: 'D',
20
- 4: 'E',
21
- 5: 'F',
22
- 6: 'G',
23
- 7: 'H',
24
- 8: 'I',
25
- 9: 'J',
26
- 10: 'K',
27
- 11: 'L',
28
- 12: 'M',
29
- 13: 'N',
30
- 14: 'O',
31
- 15: 'P',
32
- 16: 'Q',
33
- 17: 'R',
34
- 18: 'S',
35
- 19: 'T'
36
- }
37
-
38
- const setSequenceValue = (props, sequenceProps) => {
39
- const { key, variable, value, scaling, index, scalingVariable } = props
40
- sequenceProps.sequence[key] = {
41
- key,
42
- decimal: ~~(value * 100) / 100,
43
- val: ~~value,
44
- scaling,
45
- index,
46
- scalingVariable,
47
- variable
48
- }
49
- sequenceProps.scales[key] = scaling
50
- const varUnit = VIEWPORT_UNITS.has(sequenceProps.unit) ? 'rem' : sequenceProps.unit
51
- sequenceProps.vars[variable] = scaling + varUnit
52
- }
53
-
54
- export const getFnPrefixAndValue = (val) => {
55
- if (!val.includes('(')) return val
56
- const prefix = val.split('(')[0]
57
- const value = val.slice(val.indexOf('(') + 1, val.lastIndexOf(')'))
58
- return [prefix, value]
59
- }
60
-
61
- const VIEWPORT_UNITS = new Set(['vw', 'vh', 'vmin', 'vmax', 'svw', 'svh', 'lvw', 'lvh', 'dvw', 'dvh'])
62
-
63
- export const setScalingVar = (key, sequenceProps) => {
64
- const { base, type, unit: rawUnit } = sequenceProps
65
- const unit = VIEWPORT_UNITS.has(rawUnit) ? 'rem' : rawUnit
66
-
67
- const defaultVal = (isScalingUnit(unit) ? 1 : base) + unit
68
-
69
- if (key === 0) return defaultVal
70
-
71
- const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
72
- const prefix = '--' + vp + (type && type.replace('.', '-'))
73
- const ratioVar = `${prefix}-ratio`
74
-
75
- if (key > 0) {
76
- const prevLetterKey = numToLetterMap[key - 1]
77
- return `calc(var(${prefix}-${prevLetterKey}) * var(${ratioVar}))`
78
- }
79
- if (key < 0) {
80
- const nextLetterKey = numToLetterMap[key + 1]
81
- const absKey = Math.abs(key)
82
- const phiPow = Math.pow(PHI, 2 * absKey)
83
- const prevAscKey = numToLetterMap[absKey]
84
- // Clamp: max(current / ratio, normalized * ratio^n / phi^2n)
85
- // current chain: A / ratio^n
86
- // normalized: A * ratio^n / phi^(2n) = ASC mirror / phi^(2n)
87
- if (prevAscKey) {
88
- return `max(calc(var(${prefix}-${nextLetterKey}) / var(${ratioVar})), calc(var(${prefix}-${prevAscKey}) / ${phiPow.toFixed(4)}))`
89
- }
90
- return `calc(var(${prefix}-${nextLetterKey}) / var(${ratioVar}))`
91
- }
92
- }
93
-
94
- export const setSubScalingVar = (index, arr, variable, sequenceProps) => {
95
- const { type } = sequenceProps
96
- const skipMiddle = index === 2 && arr.length === 2
97
- const indexMapWithLength = skipMiddle ? index + 1 : index
98
-
99
- const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
100
- const prefix = '--' + vp + (type && type.replace('.', '-'))
101
- const subRatioVarPrefix = `${prefix}-sub-ratio-`
102
-
103
- return `calc(var(${variable}) * var(${subRatioVarPrefix + indexMapWithLength}))`
104
- }
105
-
106
- export const getSubratioDifference = (base, ratio) => {
107
- const diff = base * ratio - base
108
- const subRatio = diff / 1.618
109
- const first = base * ratio - subRatio
110
- const second = base + subRatio
111
- const middle = (first + second) / 2
112
- return [first, middle, second]
113
- }
114
-
115
- export const getSubratio = (base, ratio) => {
116
- return getSubratioDifference(base, ratio).map((v) => v / base)
117
- }
118
-
119
- export const generateSubSequence = (props, sequenceProps) => {
120
- const { key, base, value, ratio, variable, index } = props
121
-
122
- const next = value * ratio
123
- const diffRounded = ~~next - ~~value
124
-
125
- let arr
126
- const [first, middle, second] = getSubratioDifference(value, ratio)
127
- if (diffRounded > 16) arr = [first, middle, second]
128
- else arr = [first, second]
129
-
130
- arr.forEach((v, k) => {
131
- const scaling = ~~((v / base) * 1000) / 1000
132
- const newVar = variable + (k + 1)
133
- const newIndex = index + (k + 1) / 10
134
- const scalingVariable = setSubScalingVar(
135
- k + 1,
136
- arr,
137
- variable,
138
- sequenceProps
139
- )
140
-
141
- const props = {
142
- key: key + (k + 1),
143
- variable: newVar,
144
- value: v,
145
- scaling,
146
- scalingVariable,
147
- index: newIndex
148
- }
149
-
150
- setSequenceValue(props, sequenceProps)
151
- })
152
- }
153
-
154
- const PHI = 1.618
155
-
156
- const switchSequenceOnNegative = (key, base, ratio) => {
157
- if (key >= 0) return base * Math.pow(ratio, key)
158
-
159
- // DESC: clamp between current and normalized to preserve proportions
160
- // Below golden ratio: use current (1/ratio^n) — nothing changes
161
- // Above golden ratio: use normalized (ratio^n / phi^2n) — proportion stays constant
162
- const absKey = Math.abs(key)
163
- const current = base * Math.pow(ratio, key) // base / ratio^n
164
- const normalized = base * Math.pow(ratio, absKey) / Math.pow(PHI, 2 * absKey) // base * ratio^n / phi^(2n)
165
- return Math.max(current, normalized)
166
- }
167
-
168
- export const generateSequence = (sequenceProps) => {
169
- const { type, base, ratio, range, subSequence } = sequenceProps
170
- const n = Math.abs(range[0]) + Math.abs(range[1])
171
- const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
172
- const prefix = '--' + vp + (type && type.replace('.', '-')) + '-'
173
-
174
- for (let i = 0; i <= n; i++) {
175
- const key = range[1] - i
176
- const letterKey = numToLetterMap[key]
177
- const value = switchSequenceOnNegative(key, base, ratio)
178
- const scaling = ~~((value / base) * 100) / 100
179
- const variable = prefix + letterKey
180
- const scalingVariable = setScalingVar(key, sequenceProps)
181
-
182
- const props = {
183
- key: letterKey,
184
- variable,
185
- value,
186
- base,
187
- scaling,
188
- scalingVariable,
189
- ratio,
190
- index: key
191
- }
192
-
193
- setSequenceValue(props, sequenceProps)
194
-
195
- if (subSequence) generateSubSequence(props, sequenceProps)
196
- }
197
- return sequenceProps
198
- }
199
-
200
- export const generateSequencePosition = (sequenceProps, position = 0) => {
201
- const { type, base, ratio, subSequence } = sequenceProps
202
- const letterKey = isString(position) ? position : numToLetterMap[position]
203
- const index = isString(position)
204
- ? Object.entries(numToLetterMap).find(
205
- ([, value]) => value === position
206
- )?.[0]
207
- : position
208
-
209
- if (!letterKey) {
210
- console.warn(`Position ${position} is out of range in numToLetterMap`)
211
- return null
212
- }
213
-
214
- const result = {
215
- sequence: {},
216
- scales: {},
217
- vars: {},
218
- ...sequenceProps
219
- }
220
-
221
- const value = base * Math.pow(ratio, index)
222
- const scaling = ~~((value / base) * 100) / 100
223
- const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
224
- const prefix = '--' + vp + (type && type.replace('.', '-')) + '-'
225
- const variable = prefix + letterKey
226
- const scalingVariable = setScalingVar(index, sequenceProps)
227
-
228
- const props = {
229
- key: letterKey,
230
- variable,
231
- value,
232
- base,
233
- scaling,
234
- scalingVariable,
235
- ratio,
236
- index
237
- }
238
-
239
- setSequenceValue(props, result)
240
-
241
- if (subSequence) {
242
- generateSubSequence(props, result)
243
- }
244
-
245
- return result
246
- }
247
-
248
- export const getSequenceValue = (value = 'A', sequenceProps) => {
249
- const CONFIG = getActiveConfig()
250
- const { unit: UNIT } = CONFIG
251
-
252
- if (isString(value) && isCSSVar(value)) return `var(${value})`
253
-
254
- const { sequence, unit = UNIT.default, useVariable } = sequenceProps
255
-
256
- const startsWithDashOrLetterRegex = /^-?[a-zA-Z]/i
257
- const startsWithDashOrLetter = startsWithDashOrLetterRegex.test(value)
258
-
259
- const hasUnits = CSS_UNITS.some((unit) => value.includes(unit))
260
- if (hasUnits || !startsWithDashOrLetter) return value
261
-
262
- const skipArr = [
263
- 'none',
264
- 'auto',
265
- 'max-content',
266
- 'min-content',
267
- 'fit-content',
268
- 'inherit',
269
- 'initial',
270
- 'unset',
271
- 'revert',
272
- 'revert-layer'
273
- ]
274
- if (skipArr.includes(value)) return value
275
-
276
- const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
277
- const prefix = `--${vp}${toDashCase(sequenceProps.type.replace('.', '-'))}-`
278
- const letterVal = value.toUpperCase()
279
- const isNegative = letterVal.slice(0, 1) === '-' ? '-' : ''
280
- let absValue = isNegative ? letterVal.slice(1) : letterVal
281
-
282
- let mediaName = ''
283
- if (absValue.includes('_')) {
284
- mediaName = '_' + absValue.split('_')[1].toLowerCase()
285
- absValue = absValue.split('_')[0]
286
- }
287
-
288
- const varValue = (v) =>
289
- startsWithDashOrLetterRegex.test(v) ? `var(${prefix}${v}${mediaName})` : v
290
- if (absValue.includes('+')) {
291
- const [first, second] = absValue.split('+')
292
- const joint = `${varValue(first)} + ${varValue(second)}`
293
- return isNegative ? `calc((${joint}) * -1)` : `calc(${joint})`
294
- } else if (absValue.includes('*')) {
295
- const [first, second] = absValue.split('*')
296
- const joint = `${varValue(first)} * ${varValue(second)}`
297
- return isNegative ? `calc((${joint}) * -1)` : `calc(${joint})`
298
- } else if (absValue.includes('-')) {
299
- // TODO: check this
300
- // check for the first char
301
- const [first, second] = absValue.split('-')
302
- const joint = `${varValue(first)} - ${varValue(second)}`
303
- return isNegative ? `calc((${joint}) * -1)` : `calc(${joint})`
304
- }
305
-
306
- // if subsequence is not set but value is applied
307
- if (!sequence[absValue] && absValue.length === 2) {
308
- if (CONFIG.verbose)
309
- console.warn(
310
- absValue,
311
- '- value is not found because `subSequence` is set to false'
312
- )
313
- absValue = absValue.slice(0, 1)
314
- }
315
-
316
- if (useVariable || CONFIG.useVariable) {
317
- const varValue = `var(${prefix}${absValue}${mediaName})`
318
- return isNegative ? `calc(${varValue} * -1)` : varValue
319
- }
320
-
321
- const sequenceItem = sequence ? sequence[absValue] : null
322
- if (!sequenceItem) return console.warn("can't find", sequence, absValue)
323
-
324
- if (unit === 'ms' || unit === 's') {
325
- return isNegative + sequenceItem.val + unit
326
- }
327
-
328
- return isNegative + sequenceItem.scaling + unit
329
- }
330
-
331
- export const getSequenceValueBySymbols = (value, sequenceProps) => {
332
- const mathArr = ['+', '-', '*', '/', ','].filter((v) =>
333
- value.includes(v + ' ')
334
- )
335
- if (!mathArr.length) return value
336
-
337
- // Tokenize the expression preserving all operators, then resolve each token
338
- const symbolRegex = /(\s*[+\-*/,]\s*)/
339
- const tokens = value.split(symbolRegex)
340
- return tokens.map((token) => {
341
- const trimmed = token.trim()
342
- if (!trimmed || ['+', '-', '*', '/', ','].includes(trimmed)) return token
343
- return getSequenceValue(trimmed, sequenceProps)
344
- }).join('')
345
- }
346
-
347
- export const getSequenceValuePropertyPair = (
348
- value,
349
- propertyName,
350
- sequenceProps,
351
- fnPrefix
352
- ) => {
353
- if (typeof value !== 'string') {
354
- const CONFIG = getActiveConfig()
355
- if (CONFIG.verbose) console.warn(propertyName, value, 'is not a string')
356
- return { [propertyName]: value }
357
- }
358
-
359
- if (value === '-' || value === '') return {}
360
-
361
- if (!fnPrefix && value.includes('(')) {
362
- const fnArr = getFnPrefixAndValue(value)
363
- fnPrefix = fnArr[0]
364
- value = fnArr[1]
365
- }
366
-
367
- const mathArr = ['+', '-', '*', '/', ','].filter((v) =>
368
- value.includes(v + ' ')
369
- )
370
- if (mathArr.length) {
371
- value = getSequenceValueBySymbols(value, sequenceProps)
372
- } else value = getSequenceValue(value, sequenceProps)
373
-
374
- return { [propertyName]: fnPrefix ? `${fnPrefix}(${value})` : value }
375
- }
376
-
377
- export const findHeadingLetter = (h1Matches, index) =>
378
- numToLetterMap[h1Matches - index]
379
-
380
- export const findHeadings = (propertyNames) => {
381
- const { h1Matches, sequence } = propertyNames
382
- return new Array(6).fill(null).map((_, i) => {
383
- const findLetter = findHeadingLetter(h1Matches, i)
384
- return sequence[findLetter]
385
- })
386
- }
@@ -1,107 +0,0 @@
1
- 'use strict'
2
-
3
- import { isArray, isNotProduction, isString } from '@symbo.ls/utils'
4
- import { getActiveConfig } from '../factory.js'
5
-
6
- const isDev = isNotProduction()
7
-
8
- export const generateSprite = (icons) => {
9
- const CONFIG = getActiveConfig()
10
-
11
- let sprite = ''
12
-
13
- for (const key in icons) {
14
- if (CONFIG.__svgCache[key]) continue
15
- else CONFIG.__svgCache[key] = true
16
- sprite += icons[key]
17
- }
18
-
19
- return sprite
20
- }
21
-
22
- const parseRootAttributes = (htmlString) => {
23
- const val = htmlString && (htmlString.default || htmlString)
24
- if (!isString(val)) {
25
- if (isDev) console.warn('parseRootAttributes:', val, 'is not a string')
26
- return {} // empty attrs — caller destructures `width`/`height`, must not crash
27
- }
28
-
29
- const match = val.match(/<svg\s+(.*?)>/)
30
- if (!match || !match[1]) {
31
- return {}
32
- }
33
-
34
- const attrString = match[1]
35
- const attrs = attrString.match(
36
- /(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?/gm
37
- )
38
- if (!attrs) return {} // attr regex sometimes returns null on minimal SVG; same safety
39
- return attrs.reduce((acc, attr) => {
40
- const [key, value] = attr.split('=')
41
- acc[key] = value.replace(/['"]/g, '')
42
- return acc
43
- }, {})
44
- }
45
-
46
- // Rewrite every internal id="…" + url(#…) reference inside an SVG body
47
- // with a deterministic suffix derived from the symbol key + the original
48
- // id. Same input SVG + same key → same output, every render.
49
- //
50
- // Previous behavior had three bugs that compounded:
51
- // 1. `idRegex` had no `g` flag, so `.replace(idRegex, …)` only swapped
52
- // the FIRST `id="…"` match. SVGs with multiple ids (filters,
53
- // gradients, masks, clipPaths) lost references.
54
- // 2. `Math.random()` was the per-iteration suffix, so the same SVG got
55
- // different ids on every call → SSR-rendered DOM never matched the
56
- // hydrate pass and one symbol's filter could fail to match its url().
57
- // 3. Each iteration reset `replacedCode = code` (instead of chaining),
58
- // so even though the loop ran N times it only ever produced one
59
- // single-id swap.
60
- const replaceIdsAndUrls = (code, key) => {
61
- const ids = []
62
- code.replace(/id="([^"]*)"/g, (_, id) => { ids.push(id); return _ })
63
- if (!ids.length) return code
64
-
65
- let replacedCode = code
66
- for (const origId of ids) {
67
- const escaped = origId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
68
- const newId = `${key}-${origId}`
69
- replacedCode = replacedCode
70
- .replace(new RegExp(`id="${escaped}"`, 'g'), `id="${newId}"`)
71
- .replace(new RegExp(`url\\(#${escaped}\\)`, 'g'), `url(#${newId})`)
72
- .replace(new RegExp(`xlink:href="#${escaped}"`, 'g'), `xlink:href="#${newId}"`)
73
- .replace(new RegExp(`href="#${escaped}"`, 'g'), `href="#${newId}"`)
74
- }
75
- return replacedCode
76
- }
77
-
78
- export const convertSvgToSymbol = (key, code) => {
79
- const extractAttrs = parseRootAttributes(code)
80
- const { width, height } = extractAttrs
81
-
82
- const viewBox = extractAttrs.viewBox || `0 0 ${width || 24} ${height || 24}`
83
- const xmlns = 'http://www.w3.org/2000/svg'
84
-
85
- const replacedCode = replaceIdsAndUrls(code, key)
86
-
87
- let symbol = replacedCode.replace(
88
- '<svg',
89
- `<symbol id="${key}" xmlns="${xmlns}" viewBox="${viewBox}"`
90
- )
91
-
92
- symbol = symbol.replace(/width="[^"]*"/, '')
93
- symbol = symbol.replace(/height="[^"]*"/, '')
94
- symbol = symbol.replace('</svg', '</symbol')
95
- symbol = expandSvgSelfClosing(symbol)
96
- return symbol
97
- }
98
-
99
- // SVG elements that are void in SVG but not in HTML.
100
- // HTML parser treats <line .../> as <line ...> (ignores /), nesting siblings.
101
- // Fix: expand self-closing tags to explicit open+close for HTML parser compat.
102
- const SVG_VOID_TAGS = 'line|circle|ellipse|rect|polyline|polygon|path|stop|use|image'
103
- const SVG_SELF_CLOSING_RE = new RegExp(
104
- `<(${SVG_VOID_TAGS})\\b([^>]*?)\\s*/>`,
105
- 'g'
106
- )
107
- const expandSvgSelfClosing = (str) => str.replace(SVG_SELF_CLOSING_RE, '<$1$2></$1>')
@@ -1,8 +0,0 @@
1
- 'use strict'
2
-
3
- export const returnSubThemeOrDefault = (orig, theme) => {
4
- if (!orig) return
5
- if (orig.themes && orig.themes[theme]) return orig.themes[theme]
6
- if (orig[theme]) return [orig, orig[theme]]
7
- return orig
8
- }
package/src/utils/unit.js DELETED
@@ -1,72 +0,0 @@
1
- 'use strict'
2
-
3
- export const isScalingUnit = (unit) => {
4
- return (
5
- unit === 'em' ||
6
- unit === 'rem' ||
7
- unit === 'vw' ||
8
- unit === 'vh' ||
9
- unit === 'vmax' ||
10
- unit === 'vmin'
11
- )
12
- }
13
-
14
- export const CSS_UNITS = [
15
- // Absolute
16
- 'px',
17
- 'cm',
18
- 'mm',
19
- 'in',
20
- 'pt',
21
- 'pc',
22
-
23
- // Font-relative
24
- 'em',
25
- 'rem',
26
- 'ex',
27
- 'cap',
28
- 'ch',
29
- 'ic',
30
- 'lh',
31
- 'rlh',
32
-
33
- // Viewport-relative
34
- '%',
35
- 'vw',
36
- 'vh',
37
- 'vmin',
38
- 'vmax',
39
- 'svw',
40
- 'svh',
41
- 'lvw',
42
- 'lvh',
43
- 'dvw',
44
- 'dvh',
45
-
46
- // Container query units
47
- 'cqw',
48
- 'cqh',
49
- 'cqi',
50
- 'cqb',
51
- 'cqmin',
52
- 'cqmax',
53
-
54
- // Angle
55
- 'deg',
56
- 'rad',
57
- 'grad',
58
- 'turn',
59
-
60
- // Time
61
- 's',
62
- 'ms',
63
-
64
- // Resolution
65
- 'dpi',
66
- 'dpcm',
67
- 'dppx',
68
-
69
- // Grid fractional
70
- 'fr',
71
- 'auto'
72
- ]
package/src/utils/var.js DELETED
@@ -1,129 +0,0 @@
1
- 'use strict'
2
-
3
- import { isObjectLike } from '@symbo.ls/utils'
4
- import { getActiveConfig } from '../factory.js'
5
- import { getSubratio } from './sequence.js'
6
- import { isScalingUnit } from './unit.js'
7
-
8
- export const setVariables = (result, key) => {
9
- const CONFIG = getActiveConfig()
10
- const { cssVars: CSS_VARS } = CONFIG
11
- if (isObjectLike(result.value)) {
12
- // TODO: handle nested object variables
13
- } else {
14
- CSS_VARS[result.var] = result.value
15
- }
16
- }
17
-
18
- export const applySequenceGlobalVars = (vars, obj, options) => {
19
- const CONFIG = getActiveConfig()
20
- const { unit: UNIT } = CONFIG
21
- const unit = obj.unit || UNIT.default
22
- const { base, ratio, type } = obj
23
- const vp = obj.varPrefix ? obj.varPrefix + '-' : ''
24
- const prefix = '--' + vp + (type && type.replace('.', '-'))
25
- vars[`${prefix}-base`] = base
26
- vars[`${prefix}-unit`] = unit
27
- const ratioVar = `${prefix}-ratio`
28
- vars[ratioVar] = ratio
29
-
30
- const [first, middle, second] = getSubratio(base, ratio)
31
- vars[`${prefix}-sub-ratio-1`] = `calc(var(${prefix}-ratio) * ${first / ratio})`
32
- vars[`${prefix}-sub-ratio-2`] = `calc(var(${prefix}-ratio) * ${middle / ratio})`
33
- vars[`${prefix}-sub-ratio-3`] = `calc(var(${prefix}-ratio) * ${second / ratio})`
34
-
35
- // vars[`${prefix}-sub-ratio-1`] = first
36
- // vars[`${prefix}-sub-ratio-2`] = middle
37
- // vars[`${prefix}-sub-ratio-3`] = second
38
- }
39
-
40
- // Viewport units are applied to root fontSize only; tokens use 'rem' instead
41
- const VIEWPORT_UNITS = new Set(['vw', 'vh', 'vmin', 'vmax', 'svw', 'svh', 'lvw', 'lvh', 'dvw', 'dvh'])
42
-
43
- export const applySequenceVars = (FACTORY, options = {}) => {
44
- const CONFIG = getActiveConfig()
45
- const { unit: UNIT, timing: TIMING, cssVars: CSS_VARS } = CONFIG
46
-
47
- const rawUnit = FACTORY.unit || UNIT.default
48
- const unit = VIEWPORT_UNITS.has(rawUnit) ? 'rem' : rawUnit
49
- const { mediaRegenerate, sequence, scales } = FACTORY
50
-
51
- if (!mediaRegenerate) {
52
- applySequenceGlobalVars(CSS_VARS, FACTORY, options)
53
- }
54
-
55
- for (const key in sequence) {
56
- const item = sequence[key]
57
-
58
- const value = (FACTORY.type === TIMING.type
59
- ? sequence[key].val
60
- : scales[key]
61
- ) + unit
62
-
63
- if (!mediaRegenerate) {
64
- CSS_VARS[item.variable + '_default'] = value
65
- CSS_VARS[item.variable] = item.scalingVariable
66
- continue
67
- }
68
-
69
- if (options.useDefault === false) {
70
- CSS_VARS[item.variable] = value
71
- } else {
72
- CSS_VARS[item.variable + '_default'] = value
73
- CSS_VARS[item.variable] = `var(${item.variable + '_default'})`
74
- }
75
- }
76
- }
77
-
78
- export const applyMediaSequenceVars = (FACTORY, media, options = {}) => {
79
- const CONFIG = getActiveConfig()
80
- const { unit: UNIT, media: MEDIA, cssVars: CSS_VARS } = CONFIG
81
-
82
- const mediaName = media.slice(1)
83
-
84
- const mediaConfig = FACTORY[media]
85
- const rawMediaUnit = mediaConfig.unit || FACTORY.unit || UNIT.default
86
- const unit = VIEWPORT_UNITS.has(rawMediaUnit) ? 'rem' : rawMediaUnit
87
- const { mediaRegenerate } = FACTORY
88
- const { sequence, scales } = mediaConfig
89
-
90
- const query = MEDIA[mediaName]
91
- if (!query && CONFIG.verbose) console.warn('Can\'t find media query ', query)
92
-
93
- // if mediaRegenerate is not applied ratio and and sequence sizes
94
- // will be applied using CSS vars
95
- if (!mediaRegenerate) {
96
- let underMediaQuery = CSS_VARS[`@media ${query}`]
97
- if (!underMediaQuery) underMediaQuery = CSS_VARS[`@media ${query}`] = {}
98
- applySequenceGlobalVars(underMediaQuery, mediaConfig, options)
99
-
100
- // If unit changed, override token vars with new unit values
101
- const parentUnit = FACTORY.unit || UNIT.default
102
- if (unit !== parentUnit && sequence) {
103
- for (const key in sequence) {
104
- const item = sequence[key]
105
- const value = scales[key] + unit
106
- underMediaQuery[item.variable + '_default'] = value
107
- underMediaQuery[item.variable] = value
108
- }
109
- }
110
- return
111
- }
112
-
113
- for (const key in sequence) {
114
- const item = sequence[key]
115
-
116
- const value = (isScalingUnit(unit)
117
- ? scales[key]
118
- : sequence[key].val
119
- ) + unit
120
-
121
- if (!query && CONFIG.verbose) console.warn('Can\'t find query ', query)
122
-
123
- let underMediaQuery = CSS_VARS[`@media ${query}`]
124
- if (!underMediaQuery) underMediaQuery = CSS_VARS[`@media ${query}`] = {}
125
-
126
- underMediaQuery[item.variable] = `var(${item.variable + '_' + mediaName})`
127
- CSS_VARS[item.variable + '_' + mediaName] = value
128
- }
129
- }