@symbo.ls/scratch 3.8.9 → 3.14.1

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 (119) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/defaultConfig/animation.js +4 -2
  3. package/dist/cjs/defaultConfig/cases.js +4 -2
  4. package/dist/cjs/defaultConfig/class.js +4 -2
  5. package/dist/cjs/defaultConfig/color.js +6 -9
  6. package/dist/cjs/defaultConfig/document.js +4 -2
  7. package/dist/cjs/defaultConfig/font-family.js +8 -12
  8. package/dist/cjs/defaultConfig/font.js +4 -11
  9. package/dist/cjs/defaultConfig/grid.js +5 -3
  10. package/dist/cjs/defaultConfig/icons.js +6 -4
  11. package/dist/cjs/defaultConfig/index.js +200 -24
  12. package/dist/cjs/defaultConfig/media.js +4 -2
  13. package/dist/cjs/defaultConfig/responsive.js +6 -4
  14. package/dist/cjs/defaultConfig/sequence.js +4 -2
  15. package/dist/cjs/defaultConfig/shadow.js +4 -2
  16. package/dist/cjs/defaultConfig/spacing.js +56 -7
  17. package/dist/cjs/defaultConfig/svg.js +6 -4
  18. package/dist/cjs/defaultConfig/templates.js +4 -2
  19. package/dist/cjs/defaultConfig/theme.js +4 -14
  20. package/dist/cjs/defaultConfig/timing.js +36 -5
  21. package/dist/cjs/defaultConfig/typography.js +36 -5
  22. package/dist/cjs/defaultConfig/unit.js +4 -2
  23. package/dist/cjs/factory.js +341 -40
  24. package/dist/cjs/index.js +6333 -11
  25. package/dist/cjs/package.json +4 -0
  26. package/dist/cjs/set.js +5614 -158
  27. package/dist/cjs/system/color.js +4481 -104
  28. package/dist/cjs/system/document.js +4371 -11
  29. package/dist/cjs/system/font.js +4401 -28
  30. package/dist/cjs/system/index.js +5748 -11
  31. package/dist/cjs/system/reset.js +4445 -21
  32. package/dist/cjs/system/shadow.js +4832 -41
  33. package/dist/cjs/system/spacing.js +4752 -39
  34. package/dist/cjs/system/svg.js +4437 -47
  35. package/dist/cjs/system/theme.js +4526 -335
  36. package/dist/cjs/system/timing.js +4695 -19
  37. package/dist/cjs/system/typography.js +4755 -33
  38. package/dist/cjs/tests/index.js +4 -2
  39. package/dist/cjs/transforms/index.js +5019 -134
  40. package/dist/cjs/utils/color.js +47 -66
  41. package/dist/cjs/utils/font.js +25 -46
  42. package/dist/cjs/utils/index.js +5068 -8
  43. package/dist/cjs/utils/sequence.js +4423 -35
  44. package/dist/cjs/utils/sprite.js +353 -12
  45. package/dist/cjs/utils/theme.js +3 -1
  46. package/dist/cjs/utils/unit.js +4 -2
  47. package/dist/cjs/utils/var.js +4390 -42
  48. package/index.js +1 -0
  49. package/package.json +11 -14
  50. package/src/defaultConfig/class.js +2 -1
  51. package/src/defaultConfig/font-family.js +3 -3
  52. package/src/defaultConfig/icons.js +1 -1
  53. package/src/defaultConfig/svg.js +1 -1
  54. package/src/defaultConfig/timing.js +1 -1
  55. package/src/factory.js +85 -13
  56. package/src/index.js +16 -5
  57. package/src/set.js +156 -63
  58. package/src/system/color.js +113 -12
  59. package/src/system/document.js +3 -3
  60. package/src/system/font.js +5 -5
  61. package/src/system/reset.js +41 -8
  62. package/src/system/shadow.js +4 -3
  63. package/src/system/spacing.js +3 -3
  64. package/src/system/svg.js +42 -5
  65. package/src/system/theme.js +87 -64
  66. package/src/system/timing.js +2 -2
  67. package/src/system/typography.js +12 -3
  68. package/src/transforms/index.js +4 -4
  69. package/src/utils/color.js +2 -1
  70. package/src/utils/font.js +7 -1
  71. package/src/utils/sequence.js +46 -29
  72. package/src/utils/sprite.js +44 -16
  73. package/src/utils/var.js +27 -9
  74. package/dist/esm/defaultConfig/animation.js +0 -4
  75. package/dist/esm/defaultConfig/cases.js +0 -4
  76. package/dist/esm/defaultConfig/class.js +0 -5
  77. package/dist/esm/defaultConfig/color.js +0 -11
  78. package/dist/esm/defaultConfig/document.js +0 -4
  79. package/dist/esm/defaultConfig/font-family.js +0 -18
  80. package/dist/esm/defaultConfig/font.js +0 -13
  81. package/dist/esm/defaultConfig/grid.js +0 -5
  82. package/dist/esm/defaultConfig/icons.js +0 -6
  83. package/dist/esm/defaultConfig/index.js +0 -25
  84. package/dist/esm/defaultConfig/media.js +0 -9
  85. package/dist/esm/defaultConfig/responsive.js +0 -30
  86. package/dist/esm/defaultConfig/sequence.js +0 -29
  87. package/dist/esm/defaultConfig/shadow.js +0 -4
  88. package/dist/esm/defaultConfig/spacing.js +0 -18
  89. package/dist/esm/defaultConfig/svg.js +0 -6
  90. package/dist/esm/defaultConfig/templates.js +0 -4
  91. package/dist/esm/defaultConfig/theme.js +0 -16
  92. package/dist/esm/defaultConfig/timing.js +0 -17
  93. package/dist/esm/defaultConfig/typography.js +0 -21
  94. package/dist/esm/defaultConfig/unit.js +0 -6
  95. package/dist/esm/factory.js +0 -60
  96. package/dist/esm/index.js +0 -12
  97. package/dist/esm/set.js +0 -219
  98. package/dist/esm/system/color.js +0 -193
  99. package/dist/esm/system/document.js +0 -16
  100. package/dist/esm/system/font.js +0 -58
  101. package/dist/esm/system/index.js +0 -10
  102. package/dist/esm/system/reset.js +0 -67
  103. package/dist/esm/system/shadow.js +0 -91
  104. package/dist/esm/system/spacing.js +0 -121
  105. package/dist/esm/system/svg.js +0 -86
  106. package/dist/esm/system/theme.js +0 -480
  107. package/dist/esm/system/timing.js +0 -32
  108. package/dist/esm/system/typography.js +0 -85
  109. package/dist/esm/tests/index.js +0 -8
  110. package/dist/esm/transforms/index.js +0 -216
  111. package/dist/esm/utils/color.js +0 -192
  112. package/dist/esm/utils/font.js +0 -92
  113. package/dist/esm/utils/index.js +0 -7
  114. package/dist/esm/utils/sequence.js +0 -303
  115. package/dist/esm/utils/sprite.js +0 -65
  116. package/dist/esm/utils/theme.js +0 -9
  117. package/dist/esm/utils/unit.js +0 -59
  118. package/dist/esm/utils/var.js +0 -82
  119. package/dist/iife/index.js +0 -3204
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
- import { toCamelCase } from '@symbo.ls/smbls-utils'
3
+ import { toCamelCase } from '@symbo.ls/utils'
4
4
  import { getActiveConfig } from '../factory.js'
5
5
  import {
6
6
  applySequenceVars,
7
7
  generateSequence,
8
8
  getSequenceValuePropertyPair
9
- } from '../utils'
9
+ } from '../utils/index.js'
10
10
 
11
11
  export const applyTimingSequence = () => {
12
12
  const CONFIG = getActiveConfig()
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- import { merge } from '@domql/utils'
3
+ import { merge } from '@symbo.ls/utils'
4
4
  import { getActiveConfig } from '../factory.js'
5
5
 
6
6
  import {
@@ -9,7 +9,7 @@ import {
9
9
  findHeadings,
10
10
  generateSequence,
11
11
  getSequenceValuePropertyPair
12
- } from '../utils'
12
+ } from '../utils/index.js'
13
13
 
14
14
  export const runThroughMedia = FACTORY => {
15
15
  const CONFIG = getActiveConfig()
@@ -35,14 +35,23 @@ export const runThroughMedia = FACTORY => {
35
35
  unit
36
36
  })
37
37
 
38
+ const VIEWPORT_UNITS = new Set(['vw', 'vh', 'vmin', 'vmax', 'svw', 'svh', 'lvw', 'lvh', 'dvw', 'dvh'])
39
+ const inheritedUnit = mediaValue.unit || unit
40
+ const mediaUnit = (!mediaValue.unit && VIEWPORT_UNITS.has(unit)) ? 'rem' : inheritedUnit
38
41
  const query = MEDIA[mediaName]
39
42
  const media =
40
43
  '@media ' + (query === 'print' ? `${query}` : `screen and ${query}`)
41
44
  TYPOGRAPHY.templates[media] = {
42
- fontSize: mediaValue.base / TYPOGRAPHY.browserDefault + unit
45
+ fontSize: mediaValue.base / TYPOGRAPHY.browserDefault + mediaUnit
43
46
  }
44
47
 
45
48
  if (!mediaRegenerate) {
49
+ merge(mediaValue, {
50
+ sequence: {},
51
+ scales: {},
52
+ vars: {}
53
+ })
54
+ generateSequence(mediaValue)
46
55
  applyMediaSequenceVars(FACTORY, prop)
47
56
  continue
48
57
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- import { isString, isObject, exec } from '@domql/utils'
4
- import { getActiveConfig } from '../factory'
3
+ import { isString, isObject, exec } from '@symbo.ls/utils'
4
+ import { getActiveConfig } from '../factory.js'
5
5
  import {
6
6
  getSpacingByKey,
7
7
  getColor,
@@ -12,7 +12,7 @@ import {
12
12
  getSpacingBasedOnRatio,
13
13
  checkIfBoxSize,
14
14
  splitSpacedValue
15
- } from '../system'
15
+ } from '../system/index.js'
16
16
  import {
17
17
  getFnPrefixAndValue,
18
18
  isResolvedColor,
@@ -20,7 +20,7 @@ import {
20
20
  CSS_NATIVE_COLOR_REGEX,
21
21
  splitTopLevelCommas,
22
22
  parseColorToken
23
- } from '../utils'
23
+ } from '../utils/index.js'
24
24
 
25
25
  const BORDER_STYLES = new Set([
26
26
  'none', 'hidden', 'dotted', 'dashed', 'solid', 'double',
@@ -6,7 +6,7 @@ import {
6
6
  isString,
7
7
  isNumber,
8
8
  isNotProduction
9
- } from '@domql/utils'
9
+ } from '@symbo.ls/utils'
10
10
 
11
11
  export const colorStringToRgbaArray = color => {
12
12
  if (color === '') return [0, 0, 0, 0]
@@ -175,6 +175,7 @@ export const isCSSVar = (v) => v.charCodeAt(0) === 45 && v.charCodeAt(1) === 45
175
175
  export const CSS_NATIVE_COLOR_REGEX = /(?:rgba?\(|hsla?\(|#[0-9a-fA-F]{3,8}\b)/
176
176
 
177
177
  // Regex for Symbols color token: colorName[.opacity][+/-/=tone]
178
+ // Supports hyphenated names like 'highlight-reversed', 'canvas-card', 'line-highlight'
178
179
  // +N or -N = relative shade, =N = absolute lightness percentage
179
180
  const COLOR_TOKEN_REGEX = /^([a-zA-Z]\w*)(?:\.(\d+))?(?:([+-]\d+|=\d+))?$/
180
181
 
package/src/utils/font.js CHANGED
@@ -16,6 +16,9 @@ export const getDefaultOrFirstKey = (LIBRARY, key) => {
16
16
  }
17
17
 
18
18
  export const getFontFormat = (url) => {
19
+ // Tolerate missing urls — a font weight entry without a `url` should produce
20
+ // no `format(...)` hint rather than crashing the entire CSS pipeline.
21
+ if (typeof url !== 'string' || !url) return null
19
22
  const ext = url.split(/[#?]/)[0].split('.').pop().trim()
20
23
  if (['woff2', 'woff', 'ttf', 'otf', 'eot'].includes(ext)) return ext
21
24
  return null
@@ -30,7 +33,10 @@ export const setFontImport = (url) => `@import url('${url}');`
30
33
  export const setInCustomFontMedia = (str) => `@font-face { ${str} }`
31
34
 
32
35
  export const setCustomFont = (name, url, weight, options = {}) => {
33
- const urls = Array.isArray(url) ? url : [url]
36
+ // Filter out undefined / empty entries so a missing weight URL doesn't
37
+ // emit a broken `url('undefined')` rule or crash on .split downstream.
38
+ const rawUrls = Array.isArray(url) ? url : [url]
39
+ const urls = rawUrls.filter((u) => typeof u === 'string' && u)
34
40
  const srcList = urls.map((u) => {
35
41
  const format = getFontFormat(u)
36
42
  const formatStr = format ? ` format('${format}')` : ''
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- import { isString } from '@domql/utils'
4
- import { toDashCase } from '@symbo.ls/smbls-utils'
3
+ import { isString } from '@symbo.ls/utils'
4
+ import { toDashCase } from '@symbo.ls/utils'
5
5
  import { getActiveConfig } from '../factory.js'
6
6
  import { CSS_UNITS, isScalingUnit } from './unit.js'
7
7
  import { isCSSVar } from './color.js'
@@ -47,7 +47,8 @@ const setSequenceValue = (props, sequenceProps) => {
47
47
  variable
48
48
  }
49
49
  sequenceProps.scales[key] = scaling
50
- sequenceProps.vars[variable] = scaling + sequenceProps.unit
50
+ const varUnit = VIEWPORT_UNITS.has(sequenceProps.unit) ? 'rem' : sequenceProps.unit
51
+ sequenceProps.vars[variable] = scaling + varUnit
51
52
  }
52
53
 
53
54
  export const getFnPrefixAndValue = (val) => {
@@ -57,14 +58,18 @@ export const getFnPrefixAndValue = (val) => {
57
58
  return [prefix, value]
58
59
  }
59
60
 
61
+ const VIEWPORT_UNITS = new Set(['vw', 'vh', 'vmin', 'vmax', 'svw', 'svh', 'lvw', 'lvh', 'dvw', 'dvh'])
62
+
60
63
  export const setScalingVar = (key, sequenceProps) => {
61
- const { base, type, unit } = sequenceProps
64
+ const { base, type, unit: rawUnit } = sequenceProps
65
+ const unit = VIEWPORT_UNITS.has(rawUnit) ? 'rem' : rawUnit
62
66
 
63
67
  const defaultVal = (isScalingUnit(unit) ? 1 : base) + unit
64
68
 
65
69
  if (key === 0) return defaultVal
66
70
 
67
- const prefix = '--' + (type && type.replace('.', '-'))
71
+ const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
72
+ const prefix = '--' + vp + (type && type.replace('.', '-'))
68
73
  const ratioVar = `${prefix}-ratio`
69
74
 
70
75
  if (key > 0) {
@@ -73,6 +78,15 @@ export const setScalingVar = (key, sequenceProps) => {
73
78
  }
74
79
  if (key < 0) {
75
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
+ }
76
90
  return `calc(var(${prefix}-${nextLetterKey}) / var(${ratioVar}))`
77
91
  }
78
92
  }
@@ -82,7 +96,8 @@ export const setSubScalingVar = (index, arr, variable, sequenceProps) => {
82
96
  const skipMiddle = index === 2 && arr.length === 2
83
97
  const indexMapWithLength = skipMiddle ? index + 1 : index
84
98
 
85
- const prefix = '--' + (type && type.replace('.', '-'))
99
+ const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
100
+ const prefix = '--' + vp + (type && type.replace('.', '-'))
86
101
  const subRatioVarPrefix = `${prefix}-sub-ratio-`
87
102
 
88
103
  return `calc(var(${variable}) * var(${subRatioVarPrefix + indexMapWithLength}))`
@@ -136,24 +151,25 @@ export const generateSubSequence = (props, sequenceProps) => {
136
151
  })
137
152
  }
138
153
 
154
+ const PHI = 1.618
155
+
139
156
  const switchSequenceOnNegative = (key, base, ratio) => {
140
- // const values = Object.values(SEQUENCE)
141
- // const index = values.indexOf(ratio)
142
- // const diffRatio = ratio / SPACING.ratio
143
- // const total = values[values.length - 1] - values[0]
144
- // const avg = total / 2
145
- // const diff = avg - ratio
146
- // const scale = total / ratio
147
- // const finalDiff = avg + avg / diffRatio
148
-
149
- // if (key < 0) return base * Math.pow(avg, key)
150
- return base * Math.pow(ratio, key)
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)
151
166
  }
152
167
 
153
168
  export const generateSequence = (sequenceProps) => {
154
169
  const { type, base, ratio, range, subSequence } = sequenceProps
155
170
  const n = Math.abs(range[0]) + Math.abs(range[1])
156
- const prefix = '--' + (type && type.replace('.', '-')) + '-'
171
+ const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
172
+ const prefix = '--' + vp + (type && type.replace('.', '-')) + '-'
157
173
 
158
174
  for (let i = 0; i <= n; i++) {
159
175
  const key = range[1] - i
@@ -204,7 +220,8 @@ export const generateSequencePosition = (sequenceProps, position = 0) => {
204
220
 
205
221
  const value = base * Math.pow(ratio, index)
206
222
  const scaling = ~~((value / base) * 100) / 100
207
- const prefix = '--' + (type && type.replace('.', '-')) + '-'
223
+ const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
224
+ const prefix = '--' + vp + (type && type.replace('.', '-')) + '-'
208
225
  const variable = prefix + letterKey
209
226
  const scalingVariable = setScalingVar(index, sequenceProps)
210
227
 
@@ -256,7 +273,8 @@ export const getSequenceValue = (value = 'A', sequenceProps) => {
256
273
  ]
257
274
  if (skipArr.includes(value)) return value
258
275
 
259
- const prefix = `--${toDashCase(sequenceProps.type.replace('.', '-'))}-`
276
+ const vp = sequenceProps.varPrefix ? sequenceProps.varPrefix + '-' : ''
277
+ const prefix = `--${vp}${toDashCase(sequenceProps.type.replace('.', '-'))}-`
260
278
  const letterVal = value.toUpperCase()
261
279
  const isNegative = letterVal.slice(0, 1) === '-' ? '-' : ''
262
280
  let absValue = isNegative ? letterVal.slice(1) : letterVal
@@ -316,15 +334,14 @@ export const getSequenceValueBySymbols = (value, sequenceProps) => {
316
334
  )
317
335
  if (!mathArr.length) return value
318
336
 
319
- return mathArr
320
- .map((symbol) => {
321
- const valuesArr = value.split(symbol + ' ').map((v) => v.trim())
322
- const transformedValues = valuesArr.map((v) => {
323
- return getSequenceValue(v, sequenceProps)
324
- })
325
- return transformedValues.join(' ' + symbol + ' ')
326
- })
327
- .join('')
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('')
328
345
  }
329
346
 
330
347
  export const getSequenceValuePropertyPair = (
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- import { isArray, isNotProduction, isString } from '@domql/utils'
4
- import { getActiveConfig } from '../factory'
3
+ import { isArray, isNotProduction, isString } from '@symbo.ls/utils'
4
+ import { getActiveConfig } from '../factory.js'
5
5
 
6
6
  const isDev = isNotProduction()
7
7
 
@@ -11,8 +11,8 @@ export const generateSprite = (icons) => {
11
11
  let sprite = ''
12
12
 
13
13
  for (const key in icons) {
14
- if (CONFIG.__svg_cache[key]) continue
15
- else CONFIG.__svg_cache[key] = true
14
+ if (CONFIG.__svgCache[key]) continue
15
+ else CONFIG.__svgCache[key] = true
16
16
  sprite += icons[key]
17
17
  }
18
18
 
@@ -20,10 +20,10 @@ export const generateSprite = (icons) => {
20
20
  }
21
21
 
22
22
  const parseRootAttributes = (htmlString) => {
23
- const val = htmlString.default || htmlString
23
+ const val = htmlString && (htmlString.default || htmlString)
24
24
  if (!isString(val)) {
25
25
  if (isDev) console.warn('parseRootAttributes:', val, 'is not a string')
26
- return
26
+ return {} // empty attrs — caller destructures `width`/`height`, must not crash
27
27
  }
28
28
 
29
29
  const match = val.match(/<svg\s+(.*?)>/)
@@ -35,6 +35,7 @@ const parseRootAttributes = (htmlString) => {
35
35
  const attrs = attrString.match(
36
36
  /(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?/gm
37
37
  )
38
+ if (!attrs) return {} // attr regex sometimes returns null on minimal SVG; same safety
38
39
  return attrs.reduce((acc, attr) => {
39
40
  const [key, value] = attr.split('=')
40
41
  acc[key] = value.replace(/['"]/g, '')
@@ -42,18 +43,34 @@ const parseRootAttributes = (htmlString) => {
42
43
  }, {})
43
44
  }
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.
45
60
  const replaceIdsAndUrls = (code, key) => {
46
- const idRegex = /id="([^"]*)"/
47
- const urlRegex = /url\(#([^)]*)\)/g
48
- const matches = code.match(/id="([^"]*)"/g)
61
+ const ids = []
62
+ code.replace(/id="([^"]*)"/g, (_, id) => { ids.push(id); return _ })
63
+ if (!ids.length) return code
64
+
49
65
  let replacedCode = code
50
- if (isArray(matches)) {
51
- matches.forEach(() => {
52
- const randomKey = Math.floor(Math.random() * 100000)
53
- replacedCode = code
54
- .replace(idRegex, `id="${key}-${randomKey}"`)
55
- .replace(urlRegex, `url(#${key}-${randomKey})`)
56
- })
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}"`)
57
74
  }
58
75
  return replacedCode
59
76
  }
@@ -75,5 +92,16 @@ export const convertSvgToSymbol = (key, code) => {
75
92
  symbol = symbol.replace(/width="[^"]*"/, '')
76
93
  symbol = symbol.replace(/height="[^"]*"/, '')
77
94
  symbol = symbol.replace('</svg', '</symbol')
95
+ symbol = expandSvgSelfClosing(symbol)
78
96
  return symbol
79
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>')
package/src/utils/var.js CHANGED
@@ -1,13 +1,13 @@
1
1
  'use strict'
2
2
 
3
- import { isObjectLike } from '@domql/utils'
3
+ import { isObjectLike } from '@symbo.ls/utils'
4
4
  import { getActiveConfig } from '../factory.js'
5
5
  import { getSubratio } from './sequence.js'
6
6
  import { isScalingUnit } from './unit.js'
7
7
 
8
8
  export const setVariables = (result, key) => {
9
9
  const CONFIG = getActiveConfig()
10
- const { CSS_VARS } = CONFIG
10
+ const { cssVars: CSS_VARS } = CONFIG
11
11
  if (isObjectLike(result.value)) {
12
12
  // TODO: handle nested object variables
13
13
  } else {
@@ -20,7 +20,8 @@ export const applySequenceGlobalVars = (vars, obj, options) => {
20
20
  const { unit: UNIT } = CONFIG
21
21
  const unit = obj.unit || UNIT.default
22
22
  const { base, ratio, type } = obj
23
- const prefix = '--' + (type && type.replace('.', '-'))
23
+ const vp = obj.varPrefix ? obj.varPrefix + '-' : ''
24
+ const prefix = '--' + vp + (type && type.replace('.', '-'))
24
25
  vars[`${prefix}-base`] = base
25
26
  vars[`${prefix}-unit`] = unit
26
27
  const ratioVar = `${prefix}-ratio`
@@ -36,11 +37,15 @@ export const applySequenceGlobalVars = (vars, obj, options) => {
36
37
  // vars[`${prefix}-sub-ratio-3`] = second
37
38
  }
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
+
39
43
  export const applySequenceVars = (FACTORY, options = {}) => {
40
44
  const CONFIG = getActiveConfig()
41
- const { unit: UNIT, timing: TIMING, CSS_VARS } = CONFIG
45
+ const { unit: UNIT, timing: TIMING, cssVars: CSS_VARS } = CONFIG
42
46
 
43
- const unit = FACTORY.unit || UNIT.default
47
+ const rawUnit = FACTORY.unit || UNIT.default
48
+ const unit = VIEWPORT_UNITS.has(rawUnit) ? 'rem' : rawUnit
44
49
  const { mediaRegenerate, sequence, scales } = FACTORY
45
50
 
46
51
  if (!mediaRegenerate) {
@@ -72,13 +77,15 @@ export const applySequenceVars = (FACTORY, options = {}) => {
72
77
 
73
78
  export const applyMediaSequenceVars = (FACTORY, media, options = {}) => {
74
79
  const CONFIG = getActiveConfig()
75
- const { unit: UNIT, media: MEDIA, CSS_VARS } = CONFIG
80
+ const { unit: UNIT, media: MEDIA, cssVars: CSS_VARS } = CONFIG
76
81
 
77
82
  const mediaName = media.slice(1)
78
83
 
79
- const unit = FACTORY.unit || UNIT.default
84
+ const mediaConfig = FACTORY[media]
85
+ const rawMediaUnit = mediaConfig.unit || FACTORY.unit || UNIT.default
86
+ const unit = VIEWPORT_UNITS.has(rawMediaUnit) ? 'rem' : rawMediaUnit
80
87
  const { mediaRegenerate } = FACTORY
81
- const { sequence, scales } = FACTORY[media]
88
+ const { sequence, scales } = mediaConfig
82
89
 
83
90
  const query = MEDIA[mediaName]
84
91
  if (!query && CONFIG.verbose) console.warn('Can\'t find media query ', query)
@@ -88,7 +95,18 @@ export const applyMediaSequenceVars = (FACTORY, media, options = {}) => {
88
95
  if (!mediaRegenerate) {
89
96
  let underMediaQuery = CSS_VARS[`@media ${query}`]
90
97
  if (!underMediaQuery) underMediaQuery = CSS_VARS[`@media ${query}`] = {}
91
- applySequenceGlobalVars(underMediaQuery, FACTORY[media], options)
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
+ }
92
110
  return
93
111
  }
94
112
 
@@ -1,4 +0,0 @@
1
- const animation = {};
2
- export {
3
- animation
4
- };
@@ -1,4 +0,0 @@
1
- const cases = {};
2
- export {
3
- cases
4
- };
@@ -1,5 +0,0 @@
1
- const defaultProps = {};
2
- const CLASS = defaultProps;
3
- export {
4
- CLASS
5
- };
@@ -1,11 +0,0 @@
1
- var proto = {
2
- // eslint-disable-line
3
- name: "",
4
- value: ""
5
- };
6
- const color = {};
7
- const gradient = {};
8
- export {
9
- color,
10
- gradient
11
- };
@@ -1,4 +0,0 @@
1
- const document = {};
2
- export {
3
- document
4
- };
@@ -1,18 +0,0 @@
1
- var defaultFont = {
2
- // eslint-disable-line
3
- name: "",
4
- family: "",
5
- type: ""
6
- };
7
- const font_family = {};
8
- const font_family_types = {
9
- "sans-serif": "Helvetica, Arial, sans-serif, --system-default",
10
- serif: "Times New Roman, Georgia, serif, --system-default",
11
- monospace: "Courier New, monospace, --system-default"
12
- };
13
- const font_face = {};
14
- export {
15
- font_face,
16
- font_family,
17
- font_family_types
18
- };
@@ -1,13 +0,0 @@
1
- var defFont = {
2
- // eslint-disable-line
3
- name: "",
4
- url: "",
5
- fontStyle: "",
6
- fontWeight: 500,
7
- fontStretch: "normal",
8
- fontOpticalSizing: "auto"
9
- };
10
- const font = {};
11
- export {
12
- font
13
- };
@@ -1,5 +0,0 @@
1
- const defaultProps = {};
2
- const grid = defaultProps;
3
- export {
4
- grid
5
- };
@@ -1,6 +0,0 @@
1
- const icons = {};
2
- const semantic_icons = {};
3
- export {
4
- icons,
5
- semantic_icons
6
- };
@@ -1,25 +0,0 @@
1
- export * from "./sequence.js";
2
- export * from "./unit.js";
3
- export * from "./typography.js";
4
- export * from "./font.js";
5
- export * from "./font-family.js";
6
- export * from "./media.js";
7
- export * from "./spacing.js";
8
- export * from "./color.js";
9
- export * from "./theme.js";
10
- export * from "./shadow.js";
11
- export * from "./icons.js";
12
- export * from "./timing.js";
13
- export * from "./document.js";
14
- export * from "./responsive.js";
15
- export * from "./animation.js";
16
- export * from "./svg.js";
17
- export * from "./templates.js";
18
- export * from "./grid.js";
19
- export * from "./class.js";
20
- const reset = {};
21
- const vars = {};
22
- export {
23
- reset,
24
- vars
25
- };
@@ -1,9 +0,0 @@
1
- const media = {
2
- tv: "(min-width: 2780px)",
3
- light: "(prefers-color-scheme: light)",
4
- dark: "(prefers-color-scheme: dark)",
5
- print: "print"
6
- };
7
- export {
8
- media
9
- };
@@ -1,30 +0,0 @@
1
- const breakpoints = {
2
- screenL: 1920,
3
- screenM: 1680,
4
- screenS: 1440,
5
- tabletL: 1366,
6
- tabletM: 1280,
7
- tabletS: 1024,
8
- mobileL: 768,
9
- mobileM: 560,
10
- mobileS: 480,
11
- mobileXS: 375
12
- };
13
- const devices = {
14
- screenXXL: [2560, 1440],
15
- screenXL: [2240, 1260],
16
- screenL: [1920, 1024],
17
- screenM: [1680, 1024],
18
- screenS: [1440, 720],
19
- tabletL: [1366, 926],
20
- tabletM: [1280, 768],
21
- tabletS: [1024, 768],
22
- mobileL: [768, 375],
23
- mobileM: [560, 768],
24
- mobileS: [480, 768],
25
- mobileXS: [375, 768]
26
- };
27
- export {
28
- breakpoints,
29
- devices
30
- };
@@ -1,29 +0,0 @@
1
- const sequence = {
2
- "minor-second": 1.067,
3
- "major-second": 1.125,
4
- "minor-third": 1.2,
5
- "major-third": 1.25,
6
- "perfect-fourth": 1.333,
7
- "augmented-fourth": 1.414,
8
- "perfect-fifth": 1.5,
9
- "minor-sixth": 1.6,
10
- phi: 1.618,
11
- // golden-ratio
12
- "major-sixth": 1.667,
13
- "square-root-3": 1.732,
14
- // theodorus
15
- "minor-seventh": 1.778,
16
- "major-seventh": 1.875,
17
- octave: 2,
18
- "square-root-5": 2.23,
19
- // pythagoras
20
- "major-tenth": 2.5,
21
- "major-eleventh": 2.667,
22
- "major-twelfth": 3,
23
- pi: 3.14,
24
- // archimedes
25
- "double-octave": 4
26
- };
27
- export {
28
- sequence
29
- };
@@ -1,4 +0,0 @@
1
- const shadow = {};
2
- export {
3
- shadow
4
- };