@symbo.ls/scratch 3.5.0 → 3.6.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.
- package/README.md +54 -1
- package/dist/cjs/factory.js +5 -1
- package/dist/cjs/set.js +3 -0
- package/dist/cjs/system/font.js +8 -5
- package/dist/cjs/system/reset.js +2 -2
- package/dist/cjs/system/theme.js +85 -8
- package/dist/cjs/transforms/index.js +1 -1
- package/dist/cjs/utils/font.js +25 -10
- package/dist/esm/factory.js +5 -1
- package/dist/esm/set.js +3 -0
- package/dist/esm/system/font.js +10 -6
- package/dist/esm/system/reset.js +2 -2
- package/dist/esm/system/theme.js +85 -8
- package/dist/esm/transforms/index.js +1 -1
- package/dist/esm/utils/font.js +25 -10
- package/dist/iife/index.js +131 -28
- package/package.json +7 -7
- package/src/factory.js +4 -1
- package/src/set.js +3 -0
- package/src/system/font.js +10 -6
- package/src/system/reset.js +2 -2
- package/src/system/theme.js +121 -8
- package/src/transforms/index.js +1 -1
- package/src/utils/font.js +21 -10
package/src/system/theme.js
CHANGED
|
@@ -140,25 +140,136 @@ const keySetters = { // eslint-disable-line
|
|
|
140
140
|
'.': (theme, value) => setHelpers(theme, value)
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Recursively generates auto-switching CSS vars from all @-scheme content.
|
|
145
|
+
* - @dark/@light: uses prefers-color-scheme media queries + [data-theme] selectors
|
|
146
|
+
* - Custom @schemes (@ocean, @sunset, etc.): uses [data-theme] selectors only
|
|
147
|
+
* - globalTheme forced: sets non-suffixed vars directly in CSS_VARS
|
|
148
|
+
*
|
|
149
|
+
* @param {Object} schemes - { dark: {...}, light: {...}, ocean: {...} }
|
|
150
|
+
* @param {string} varPrefix - var name prefix (e.g. 'document', 'primary-child')
|
|
151
|
+
* @param {Object} CONFIG - active config
|
|
152
|
+
*/
|
|
153
|
+
const generateAutoVars = (schemes, varPrefix, CONFIG) => {
|
|
154
|
+
const { CSS_VARS } = CONFIG
|
|
155
|
+
if (!CONFIG.CSS_MEDIA_VARS) CONFIG.CSS_MEDIA_VARS = {}
|
|
156
|
+
const MEDIA_VARS = CONFIG.CSS_MEDIA_VARS
|
|
157
|
+
const globalTheme = CONFIG.globalTheme !== undefined ? CONFIG.globalTheme : 'auto'
|
|
158
|
+
|
|
159
|
+
const result = {}
|
|
160
|
+
|
|
161
|
+
// Collect union of all keys across all schemes
|
|
162
|
+
const allKeys = new Set()
|
|
163
|
+
for (const scheme in schemes) {
|
|
164
|
+
if (schemes[scheme]) for (const k of Object.keys(schemes[scheme])) allKeys.add(k)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const param of allKeys) {
|
|
168
|
+
const symb = param.slice(0, 1)
|
|
169
|
+
|
|
170
|
+
// Check if any scheme has an object value for this param
|
|
171
|
+
const hasObject = Object.values(schemes).some(s => isObjectLike(s?.[param]))
|
|
172
|
+
|
|
173
|
+
if (symb === '.' && hasObject) {
|
|
174
|
+
// Dot helper (.color-only, .child, etc.) — recurse
|
|
175
|
+
const helperName = param.slice(1)
|
|
176
|
+
const subSchemes = {}
|
|
177
|
+
for (const scheme in schemes) {
|
|
178
|
+
if (isObjectLike(schemes[scheme]?.[param])) subSchemes[scheme] = schemes[scheme][param]
|
|
179
|
+
}
|
|
180
|
+
result[param] = generateAutoVars(subSchemes, `${varPrefix}-${helperName}`, CONFIG)
|
|
181
|
+
} else if (symb === ':' && hasObject) {
|
|
182
|
+
// Pseudo selector (:hover, ::placeholder) — recurse
|
|
183
|
+
const pseudoName = param.replace(/^:+/, '')
|
|
184
|
+
const subSchemes = {}
|
|
185
|
+
for (const scheme in schemes) {
|
|
186
|
+
if (isObjectLike(schemes[scheme]?.[param])) subSchemes[scheme] = schemes[scheme][param]
|
|
187
|
+
}
|
|
188
|
+
result[param] = generateAutoVars(subSchemes, `${varPrefix}-${pseudoName}`, CONFIG)
|
|
189
|
+
} else if (symb !== '@' && symb !== '.' && symb !== ':') {
|
|
190
|
+
// Regular CSS param — generate auto-switching var
|
|
191
|
+
const autoVar = `--theme-${varPrefix}-${param}`
|
|
192
|
+
|
|
193
|
+
if (globalTheme === 'auto') {
|
|
194
|
+
for (const scheme in schemes) {
|
|
195
|
+
const val = schemes[scheme]?.[param]
|
|
196
|
+
if (val === undefined) continue
|
|
197
|
+
const color = getColor(val, `@${scheme}`)
|
|
198
|
+
if (color === undefined) continue
|
|
199
|
+
|
|
200
|
+
// [data-theme] selector for ALL schemes (custom + standard)
|
|
201
|
+
const selector = `[data-theme="${scheme}"]`
|
|
202
|
+
if (!MEDIA_VARS[selector]) MEDIA_VARS[selector] = {}
|
|
203
|
+
MEDIA_VARS[selector][autoVar] = color
|
|
204
|
+
|
|
205
|
+
// prefers-color-scheme media query only for dark/light
|
|
206
|
+
if (scheme === 'dark' || scheme === 'light') {
|
|
207
|
+
const mq = `@media (prefers-color-scheme: ${scheme})`
|
|
208
|
+
if (!MEDIA_VARS[mq]) MEDIA_VARS[mq] = {}
|
|
209
|
+
MEDIA_VARS[mq][autoVar] = color
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
// Force specific theme — set non-suffixed var directly
|
|
214
|
+
const forced = String(globalTheme).replace(/^'|'$/g, '')
|
|
215
|
+
const source = schemes[forced]?.[param]
|
|
216
|
+
if (source !== undefined) {
|
|
217
|
+
const color = getColor(source, `@${forced}`)
|
|
218
|
+
if (color !== undefined) CSS_VARS[autoVar] = color
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
result[param] = `var(${autoVar})`
|
|
223
|
+
result[`.${param}`] = { [param]: result[param] }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (result.background || result.color || result.backgroundColor) {
|
|
228
|
+
result['.inversed'] = {
|
|
229
|
+
color: result.background || result.backgroundColor,
|
|
230
|
+
background: result.color
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return result
|
|
235
|
+
}
|
|
236
|
+
|
|
143
237
|
export const setMediaTheme = (val, key, suffix, prefers) => {
|
|
144
238
|
const CONFIG = getActiveConfig()
|
|
145
239
|
const { CSS_VARS } = CONFIG
|
|
146
240
|
const theme = { value: val }
|
|
241
|
+
const isTopLevel = !suffix && !prefers
|
|
147
242
|
|
|
148
243
|
if (isObjectLike(val)) {
|
|
244
|
+
// At top level: collect all @-schemes and generate auto-switching vars
|
|
245
|
+
if (isTopLevel && CONFIG.useVariable) {
|
|
246
|
+
const schemes = {}
|
|
247
|
+
for (const param in val) {
|
|
248
|
+
if (param.startsWith('@') && isObjectLike(val[param])) {
|
|
249
|
+
schemes[param.slice(1)] = val[param]
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (Object.keys(schemes).length) {
|
|
254
|
+
const autoResult = generateAutoVars(schemes, key, CONFIG)
|
|
255
|
+
Object.assign(theme, autoResult)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
149
259
|
for (const param in val) {
|
|
150
260
|
const symb = param.slice(0, 1)
|
|
151
261
|
const value = val[param]
|
|
152
262
|
if (symb === '@' || symb === ':' || symb === '.') {
|
|
153
263
|
const hasPrefers = symb === '@' && param
|
|
154
264
|
theme[param] = setMediaTheme(value, key, param, prefers || hasPrefers)
|
|
155
|
-
} else {
|
|
265
|
+
} else if (!isTopLevel) {
|
|
156
266
|
const color = getColor(value, prefers)
|
|
157
267
|
const metaSuffixes = [...new Set([prefers, suffix].filter(v => v).map(v => v.slice(1)))]
|
|
158
268
|
const varmetaSuffixName = metaSuffixes.length ? '-' + metaSuffixes.join('-') : ''
|
|
159
269
|
const CSSVar = `--theme-${key}${varmetaSuffixName}-${param}`
|
|
160
270
|
if (CONFIG.useVariable) {
|
|
161
|
-
|
|
271
|
+
// Suffixed vars (--theme-key-dark-param) only when opted in
|
|
272
|
+
if (CONFIG.useThemeSuffixedVars) CSS_VARS[CSSVar] = color
|
|
162
273
|
theme[param] = `var(${CSSVar})`
|
|
163
274
|
} else {
|
|
164
275
|
theme[param] = color
|
|
@@ -167,7 +278,8 @@ export const setMediaTheme = (val, key, suffix, prefers) => {
|
|
|
167
278
|
}
|
|
168
279
|
}
|
|
169
280
|
|
|
170
|
-
|
|
281
|
+
// Only add .inversed if not already set by generateAutoVars
|
|
282
|
+
if (!theme['.inversed'] && (theme.background || theme.color || theme.backgroundColor)) {
|
|
171
283
|
theme['.inversed'] = {
|
|
172
284
|
color: theme.background || theme.backgroundColor,
|
|
173
285
|
background: theme.color
|
|
@@ -192,9 +304,8 @@ const recursiveTheme = val => {
|
|
|
192
304
|
const symb = param.slice(0, 1)
|
|
193
305
|
if (isObjectLike(val[param])) {
|
|
194
306
|
if (symb === '@') {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
obj[media] = recursiveTheme(val[param])
|
|
307
|
+
// Skip all @-schemes — CSS vars + data-theme handle switching
|
|
308
|
+
continue
|
|
198
309
|
} else if (symb === ':') {
|
|
199
310
|
obj[`&${param}`] = recursiveTheme(val[param])
|
|
200
311
|
}
|
|
@@ -239,8 +350,10 @@ export const getMediaTheme = (value, modifier) => {
|
|
|
239
350
|
const [themeName, ...themeModifiers] = isArray(value) ? value : value.split(' ')
|
|
240
351
|
let themeValue = activeConfig.THEME[themeName]
|
|
241
352
|
|
|
242
|
-
if (themeValue &&
|
|
243
|
-
themeValue = findModifier(themeValue, themeModifiers
|
|
353
|
+
if (themeValue && themeModifiers.length) {
|
|
354
|
+
themeValue = findModifier(themeValue, themeModifiers)
|
|
355
|
+
} else if (themeValue && modifier) {
|
|
356
|
+
themeValue = findModifier(themeValue, modifier)
|
|
244
357
|
}
|
|
245
358
|
|
|
246
359
|
const resolvedTheme = recursiveTheme(themeValue)
|
package/src/transforms/index.js
CHANGED
|
@@ -246,7 +246,7 @@ export function transformSize(propertyName, val, props = {}, opts = {}) {
|
|
|
246
246
|
|
|
247
247
|
const shouldScaleBoxSize = props.scaleBoxSize
|
|
248
248
|
const isBoxSize = checkIfBoxSize(propertyName)
|
|
249
|
-
if (!shouldScaleBoxSize && isBoxSize) {
|
|
249
|
+
if (!shouldScaleBoxSize && isBoxSize && !opts.ratio) {
|
|
250
250
|
value = splitSpacedValue(value)
|
|
251
251
|
}
|
|
252
252
|
}
|
package/src/utils/font.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
export const resolveFileUrl = (url, files) => {
|
|
4
|
+
if (!url || !files) return null
|
|
5
|
+
try { new URL(url); return null } catch (e) { }
|
|
6
|
+
const file = files[url]
|
|
7
|
+
if (file) return file.content && file.content.src
|
|
8
|
+
return null
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
export const getDefaultOrFirstKey = (LIBRARY, key) => {
|
|
4
12
|
if (LIBRARY[key]) return LIBRARY[key].value
|
|
5
13
|
if (LIBRARY.default) return LIBRARY[LIBRARY.default].value
|
|
@@ -53,11 +61,12 @@ export const setCustomFontMedia = (
|
|
|
53
61
|
) => `@font-face {${setCustomFont(name, url, weight, options)}
|
|
54
62
|
}`
|
|
55
63
|
|
|
56
|
-
export const getFontFaceEach = (name, weights) => {
|
|
64
|
+
export const getFontFaceEach = (name, weights, files) => {
|
|
57
65
|
const keys = Object.keys(weights)
|
|
58
66
|
return keys.map((key) => {
|
|
59
67
|
const { url, fontWeight } = weights[key]
|
|
60
|
-
|
|
68
|
+
const resolvedUrl = resolveFileUrl(url, files) || url
|
|
69
|
+
return setCustomFont(name, resolvedUrl, fontWeight)
|
|
61
70
|
})
|
|
62
71
|
}
|
|
63
72
|
|
|
@@ -66,22 +75,24 @@ export const getFontFace = (LIBRARY) => {
|
|
|
66
75
|
return keys.map((key) => getFontFaceEach(key, LIBRARY[key].value))
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
export const getFontFaceEachString = (name, weights) => {
|
|
78
|
+
export const getFontFaceEachString = (name, weights, files) => {
|
|
70
79
|
if (weights && weights.isVariable) {
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
const url = resolveFileUrl(weights.url, files) || weights.url
|
|
81
|
+
if (isGoogleFontsUrl(url)) {
|
|
82
|
+
return setFontImport(url)
|
|
73
83
|
}
|
|
74
|
-
return setCustomFontMedia(name,
|
|
84
|
+
return setCustomFontMedia(name, url, weights.fontWeight, {
|
|
75
85
|
fontStretch: weights.fontStretch,
|
|
76
86
|
fontDisplay: weights.fontDisplay || 'swap'
|
|
77
87
|
})
|
|
78
88
|
}
|
|
79
89
|
const isArr = weights[0]
|
|
80
|
-
if (isArr) return getFontFaceEach(name, weights).map(setInCustomFontMedia)
|
|
81
|
-
|
|
90
|
+
if (isArr) return getFontFaceEach(name, weights, files).map(setInCustomFontMedia)
|
|
91
|
+
const url = resolveFileUrl(weights.url, files) || weights.url
|
|
92
|
+
return setCustomFontMedia(name, url)
|
|
82
93
|
}
|
|
83
94
|
|
|
84
|
-
export const getFontFaceString = (LIBRARY) => {
|
|
95
|
+
export const getFontFaceString = (LIBRARY, files) => {
|
|
85
96
|
const keys = Object.keys(LIBRARY)
|
|
86
|
-
return keys.map((key) => getFontFaceEachString(key, LIBRARY[key].value))
|
|
97
|
+
return keys.map((key) => getFontFaceEachString(key, LIBRARY[key].value, files))
|
|
87
98
|
}
|