@symbo.ls/scratch 3.8.0 → 3.8.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 CHANGED
@@ -29,7 +29,8 @@ set({
29
29
  font: {},
30
30
  font_family: {},
31
31
  timing: {},
32
- reset: {}
32
+ reset: {},
33
+ vars: {}
33
34
  }, {
34
35
  // options
35
36
  })
@@ -86,6 +87,54 @@ Generated CSS:
86
87
 
87
88
  When `true`, also generates suffixed variables like `--theme-document-dark-background` alongside the non-suffixed `--theme-document-background`. Disabled by default to reduce CSS variable count.
88
89
 
90
+ ## CSS Custom Properties (vars)
91
+
92
+ Define initial CSS custom properties in the design system:
93
+
94
+ ```javascript
95
+ set({
96
+ vars: {
97
+ '--header-height': '60px',
98
+ 'sidebar-width': '280px', // auto-prefixed to --sidebar-width
99
+ 'gap': '1rem' // becomes --gap
100
+ }
101
+ })
102
+ ```
103
+
104
+ Each entry is written to `:root` CSS custom properties. Keys without `--` prefix get it added automatically. Values can be referenced in component props: `padding: '--gap'` → `var(--gap)`.
105
+
106
+ ## Font — Array URL Support
107
+
108
+ Font definitions support array URLs for multiple format fallbacks:
109
+
110
+ ```javascript
111
+ set({
112
+ font: {
113
+ Exo2: [
114
+ {
115
+ url: ['Exo2-Medium.woff2', 'Exo2-Medium.woff'],
116
+ fontWeight: '500',
117
+ fontStyle: 'normal',
118
+ fontDisplay: 'swap'
119
+ }
120
+ ]
121
+ }
122
+ })
123
+ ```
124
+
125
+ Generates comma-separated `src` with auto-detected formats:
126
+
127
+ ```css
128
+ @font-face {
129
+ font-family: 'Exo2';
130
+ font-style: normal;
131
+ font-weight: 500;
132
+ font-display: swap;
133
+ src: url('Exo2-Medium.woff2') format('woff2'),
134
+ url('Exo2-Medium.woff') format('woff');
135
+ }
136
+ ```
137
+
89
138
  Read more at [docs](https://www.symbols.app/developersdesign-system)
90
139
 
91
140
  ### TODO:
@@ -19,7 +19,8 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var defaultConfig_exports = {};
21
21
  __export(defaultConfig_exports, {
22
- reset: () => reset
22
+ reset: () => reset,
23
+ vars: () => vars
23
24
  });
24
25
  module.exports = __toCommonJS(defaultConfig_exports);
25
26
  __reExport(defaultConfig_exports, require("./sequence.js"), module.exports);
@@ -36,10 +37,10 @@ __reExport(defaultConfig_exports, require("./icons.js"), module.exports);
36
37
  __reExport(defaultConfig_exports, require("./timing.js"), module.exports);
37
38
  __reExport(defaultConfig_exports, require("./document.js"), module.exports);
38
39
  __reExport(defaultConfig_exports, require("./responsive.js"), module.exports);
39
- __reExport(defaultConfig_exports, require("./cases.js"), module.exports);
40
40
  __reExport(defaultConfig_exports, require("./animation.js"), module.exports);
41
41
  __reExport(defaultConfig_exports, require("./svg.js"), module.exports);
42
42
  __reExport(defaultConfig_exports, require("./templates.js"), module.exports);
43
43
  __reExport(defaultConfig_exports, require("./grid.js"), module.exports);
44
44
  __reExport(defaultConfig_exports, require("./class.js"), module.exports);
45
45
  const reset = {};
46
+ const vars = {};
package/dist/cjs/set.js CHANGED
@@ -28,11 +28,14 @@ module.exports = __toCommonJS(set_exports);
28
28
  var import_factory = require("./factory.js");
29
29
  var import_system = require("./system");
30
30
  var import_utils = require("@domql/utils");
31
- const setCases = (val, key) => {
32
- if ((0, import_utils.isFunction)(val)) return val();
31
+ const setVars = (val, key) => {
32
+ const CONFIG = (0, import_factory.getActiveConfig)();
33
+ const { CSS_VARS } = CONFIG;
34
+ const varName = key.startsWith("--") ? key : `--${key}`;
35
+ CSS_VARS[varName] = val;
33
36
  return val;
34
37
  };
35
- const setSameValue = (val, key) => val;
38
+ const asIs = (val) => val;
36
39
  const VALUE_TRANSFORMERS = {
37
40
  color: import_system.setColor,
38
41
  gradient: import_system.setGradient,
@@ -41,21 +44,21 @@ const VALUE_TRANSFORMERS = {
41
44
  fontfamily: import_system.setFontFamily,
42
45
  theme: import_system.setTheme,
43
46
  icons: import_system.setSvgIcon,
44
- semantic_icons: setSameValue,
45
- semanticicons: setSameValue,
47
+ semantic_icons: asIs,
48
+ semanticicons: asIs,
46
49
  svg: import_system.setSVG,
47
- svg_data: setSameValue,
48
- typography: setSameValue,
49
- cases: setCases,
50
+ svg_data: asIs,
51
+ typography: asIs,
50
52
  shadow: import_system.setShadow,
51
- spacing: setSameValue,
52
- media: setSameValue,
53
- grid: setSameValue,
54
- class: setSameValue,
55
- timing: setSameValue,
56
- reset: setSameValue,
57
- unit: setSameValue,
58
- animation: setSameValue
53
+ spacing: asIs,
54
+ media: asIs,
55
+ grid: asIs,
56
+ class: asIs,
57
+ timing: asIs,
58
+ reset: asIs,
59
+ unit: asIs,
60
+ animation: asIs,
61
+ vars: setVars
59
62
  };
60
63
  const setValue = (factoryName, value, key) => {
61
64
  const CONFIG = (0, import_factory.getActiveConfig)();
@@ -67,10 +70,12 @@ const setValue = (factoryName, value, key) => {
67
70
  FACTORY2[key] = result;
68
71
  return FACTORY2;
69
72
  } catch (error) {
70
- if (CONFIG.verbose) console.warn("Error setting", lowerName, "value", value, key, error);
73
+ if (CONFIG.verbose)
74
+ console.warn("Error setting", lowerName, "value", value, key, error);
71
75
  }
72
76
  }
73
- if (CONFIG.verbose) console.warn("Can not find", lowerName, "method in scratch");
77
+ if (CONFIG.verbose)
78
+ console.warn("Can not find", lowerName, "method in scratch");
74
79
  };
75
80
  const setEach = (factoryName, props) => {
76
81
  const CONFIG = (0, import_factory.getActiveConfig)();
@@ -80,7 +85,15 @@ const setEach = (factoryName, props) => {
80
85
  try {
81
86
  return setValue(lowerName, props[key], key);
82
87
  } catch (error) {
83
- if (CONFIG.verbose) console.warn("Error setting", lowerName, "value", props[key], key, error);
88
+ if (CONFIG.verbose)
89
+ console.warn(
90
+ "Error setting",
91
+ lowerName,
92
+ "value",
93
+ props[key],
94
+ key,
95
+ error
96
+ );
84
97
  }
85
98
  });
86
99
  return CONFIG[lowerName] || CONFIG[factoryName];
@@ -115,6 +128,7 @@ const set = (recivedConfig, options = SET_OPTIONS) => {
115
128
  useDefaultConfig,
116
129
  semanticIcons,
117
130
  SEMANTIC_ICONS,
131
+ // deprecated
118
132
  semantic_icons,
119
133
  files,
120
134
  ...config
@@ -131,7 +145,8 @@ const set = (recivedConfig, options = SET_OPTIONS) => {
131
145
  if (useIconSprite !== void 0) CONFIG.useIconSprite = useIconSprite;
132
146
  if (useDocumentTheme !== void 0) CONFIG.useDocumentTheme = useDocumentTheme;
133
147
  if (globalTheme !== void 0) CONFIG.globalTheme = globalTheme;
134
- if (recivedConfig.useThemeSuffixedVars !== void 0) CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
148
+ if (recivedConfig.useThemeSuffixedVars !== void 0)
149
+ CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
135
150
  if (useDefaultConfig !== void 0) CONFIG.useDefaultConfig = useDefaultConfig;
136
151
  const _semanticIcons = semanticIcons || SEMANTIC_ICONS || semantic_icons;
137
152
  if (_semanticIcons !== void 0) {
@@ -40,7 +40,12 @@ const getColor = (value, key, config) => {
40
40
  [name, alpha, tone] = value;
41
41
  } else {
42
42
  const parsed = (0, import_utils2.parseColorToken)(value);
43
- if (!parsed) return value;
43
+ if (!parsed) {
44
+ const { color: COLOR2, gradient: GRADIENT2 } = CONFIG;
45
+ const directVal = GRADIENT2[value] || COLOR2[value];
46
+ if (directVal) return CONFIG.useVariable ? `var(${directVal.var})` : directVal.value;
47
+ return value;
48
+ }
44
49
  if (parsed.passthrough) return parsed.passthrough;
45
50
  if (parsed.cssVar) return `var(${parsed.cssVar})`;
46
51
  name = parsed.name;
@@ -45,8 +45,12 @@ const setFont = (val, key) => {
45
45
  } else if (val[0]) {
46
46
  fontFace = (0, import_utils2.getFontFaceEach)(key, val, CONFIG.files);
47
47
  } else {
48
- const url = (0, import_utils2.resolveFileUrl)(val.url, CONFIG.files) || val.url;
49
- fontFace = (0, import_utils2.setCustomFontMedia)(key, url);
48
+ const url = Array.isArray(val.url) ? val.url.map((u) => (0, import_utils2.resolveFileUrl)(u, CONFIG.files) || u) : (0, import_utils2.resolveFileUrl)(val.url, CONFIG.files) || val.url;
49
+ fontFace = (0, import_utils2.setCustomFontMedia)(key, url, val.fontWeight, {
50
+ fontStyle: val.fontStyle,
51
+ fontDisplay: val.fontDisplay,
52
+ fontStretch: val.fontStretch
53
+ });
50
54
  }
51
55
  return { var: CSSvar, value: val, fontFace };
52
56
  };
@@ -268,6 +268,8 @@ const recursiveTheme = (val) => {
268
268
  continue;
269
269
  } else if (symb === ":") {
270
270
  obj[`&${param}`] = recursiveTheme(val[param]);
271
+ } else if (symb === ".") {
272
+ obj[`&${param}`] = recursiveTheme(val[param]);
271
273
  }
272
274
  } else obj[param] = val[param];
273
275
  }
@@ -58,24 +58,28 @@ const isGoogleFontsUrl = (url) => url && (url.includes("fonts.googleapis.com") |
58
58
  const setFontImport = (url) => `@import url('${url}');`;
59
59
  const setInCustomFontMedia = (str) => `@font-face { ${str} }`;
60
60
  const setCustomFont = (name, url, weight, options = {}) => {
61
- const format = getFontFormat(url);
62
- const formatStr = format ? ` format('${format}')` : "";
61
+ const urls = Array.isArray(url) ? url : [url];
62
+ const srcList = urls.map((u) => {
63
+ const format = getFontFormat(u);
64
+ const formatStr = format ? ` format('${format}')` : "";
65
+ return `url('${u}')${formatStr}`;
66
+ }).join(",\n ");
63
67
  return `
64
68
  font-family: '${name}';
65
- font-style: normal;${weight ? `
69
+ font-style: ${options.fontStyle || "normal"};${weight ? `
66
70
  font-weight: ${weight};` : ""}${options.fontStretch ? `
67
71
  font-stretch: ${options.fontStretch};` : ""}${options.fontDisplay ? `
68
72
  font-display: ${options.fontDisplay};` : ""}
69
- src: url('${url}')${formatStr};`;
73
+ src: ${srcList};`;
70
74
  };
71
75
  const setCustomFontMedia = (name, url, weight, options) => `@font-face {${setCustomFont(name, url, weight, options)}
72
76
  }`;
73
77
  const getFontFaceEach = (name, weights, files) => {
74
78
  const keys = Object.keys(weights);
75
79
  return keys.map((key) => {
76
- const { url, fontWeight } = weights[key];
77
- const resolvedUrl = resolveFileUrl(url, files) || url;
78
- return setCustomFont(name, resolvedUrl, fontWeight);
80
+ const { url, fontWeight, fontStyle, fontDisplay, fontStretch } = weights[key];
81
+ const resolvedUrl = Array.isArray(url) ? url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(url, files) || url;
82
+ return setCustomFont(name, resolvedUrl, fontWeight, { fontStyle, fontDisplay, fontStretch });
79
83
  });
80
84
  };
81
85
  const getFontFace = (LIBRARY) => {
@@ -95,8 +99,12 @@ const getFontFaceEachString = (name, weights, files) => {
95
99
  }
96
100
  const isArr = weights[0];
97
101
  if (isArr) return getFontFaceEach(name, weights, files).map(setInCustomFontMedia);
98
- const url = resolveFileUrl(weights.url, files) || weights.url;
99
- return setCustomFontMedia(name, url);
102
+ const url = Array.isArray(weights.url) ? weights.url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(weights.url, files) || weights.url;
103
+ return setCustomFontMedia(name, url, weights.fontWeight, {
104
+ fontStyle: weights.fontStyle,
105
+ fontDisplay: weights.fontDisplay,
106
+ fontStretch: weights.fontStretch
107
+ });
100
108
  };
101
109
  const getFontFaceString = (LIBRARY, files) => {
102
110
  const keys = Object.keys(LIBRARY);
@@ -12,13 +12,14 @@ export * from "./icons.js";
12
12
  export * from "./timing.js";
13
13
  export * from "./document.js";
14
14
  export * from "./responsive.js";
15
- export * from "./cases.js";
16
15
  export * from "./animation.js";
17
16
  export * from "./svg.js";
18
17
  export * from "./templates.js";
19
18
  export * from "./grid.js";
20
19
  export * from "./class.js";
21
20
  const reset = {};
21
+ const vars = {};
22
22
  export {
23
- reset
23
+ reset,
24
+ vars
24
25
  };
package/dist/esm/set.js CHANGED
@@ -14,12 +14,15 @@ import {
14
14
  applyDocument,
15
15
  setShadow
16
16
  } from "./system";
17
- import { isFunction, deepMerge } from "@domql/utils";
18
- const setCases = (val, key) => {
19
- if (isFunction(val)) return val();
17
+ import { deepMerge } from "@domql/utils";
18
+ const setVars = (val, key) => {
19
+ const CONFIG = getActiveConfig();
20
+ const { CSS_VARS } = CONFIG;
21
+ const varName = key.startsWith("--") ? key : `--${key}`;
22
+ CSS_VARS[varName] = val;
20
23
  return val;
21
24
  };
22
- const setSameValue = (val, key) => val;
25
+ const asIs = (val) => val;
23
26
  const VALUE_TRANSFORMERS = {
24
27
  color: setColor,
25
28
  gradient: setGradient,
@@ -28,21 +31,21 @@ const VALUE_TRANSFORMERS = {
28
31
  fontfamily: setFontFamily,
29
32
  theme: setTheme,
30
33
  icons: setSvgIcon,
31
- semantic_icons: setSameValue,
32
- semanticicons: setSameValue,
34
+ semantic_icons: asIs,
35
+ semanticicons: asIs,
33
36
  svg: setSVG,
34
- svg_data: setSameValue,
35
- typography: setSameValue,
36
- cases: setCases,
37
+ svg_data: asIs,
38
+ typography: asIs,
37
39
  shadow: setShadow,
38
- spacing: setSameValue,
39
- media: setSameValue,
40
- grid: setSameValue,
41
- class: setSameValue,
42
- timing: setSameValue,
43
- reset: setSameValue,
44
- unit: setSameValue,
45
- animation: setSameValue
40
+ spacing: asIs,
41
+ media: asIs,
42
+ grid: asIs,
43
+ class: asIs,
44
+ timing: asIs,
45
+ reset: asIs,
46
+ unit: asIs,
47
+ animation: asIs,
48
+ vars: setVars
46
49
  };
47
50
  const setValue = (factoryName, value, key) => {
48
51
  const CONFIG = getActiveConfig();
@@ -54,10 +57,12 @@ const setValue = (factoryName, value, key) => {
54
57
  FACTORY2[key] = result;
55
58
  return FACTORY2;
56
59
  } catch (error) {
57
- if (CONFIG.verbose) console.warn("Error setting", lowerName, "value", value, key, error);
60
+ if (CONFIG.verbose)
61
+ console.warn("Error setting", lowerName, "value", value, key, error);
58
62
  }
59
63
  }
60
- if (CONFIG.verbose) console.warn("Can not find", lowerName, "method in scratch");
64
+ if (CONFIG.verbose)
65
+ console.warn("Can not find", lowerName, "method in scratch");
61
66
  };
62
67
  const setEach = (factoryName, props) => {
63
68
  const CONFIG = getActiveConfig();
@@ -67,7 +72,15 @@ const setEach = (factoryName, props) => {
67
72
  try {
68
73
  return setValue(lowerName, props[key], key);
69
74
  } catch (error) {
70
- if (CONFIG.verbose) console.warn("Error setting", lowerName, "value", props[key], key, error);
75
+ if (CONFIG.verbose)
76
+ console.warn(
77
+ "Error setting",
78
+ lowerName,
79
+ "value",
80
+ props[key],
81
+ key,
82
+ error
83
+ );
71
84
  }
72
85
  });
73
86
  return CONFIG[lowerName] || CONFIG[factoryName];
@@ -102,6 +115,7 @@ const set = (recivedConfig, options = SET_OPTIONS) => {
102
115
  useDefaultConfig,
103
116
  semanticIcons,
104
117
  SEMANTIC_ICONS,
118
+ // deprecated
105
119
  semantic_icons,
106
120
  files,
107
121
  ...config
@@ -118,7 +132,8 @@ const set = (recivedConfig, options = SET_OPTIONS) => {
118
132
  if (useIconSprite !== void 0) CONFIG.useIconSprite = useIconSprite;
119
133
  if (useDocumentTheme !== void 0) CONFIG.useDocumentTheme = useDocumentTheme;
120
134
  if (globalTheme !== void 0) CONFIG.globalTheme = globalTheme;
121
- if (recivedConfig.useThemeSuffixedVars !== void 0) CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
135
+ if (recivedConfig.useThemeSuffixedVars !== void 0)
136
+ CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
122
137
  if (useDefaultConfig !== void 0) CONFIG.useDefaultConfig = useDefaultConfig;
123
138
  const _semanticIcons = semanticIcons || SEMANTIC_ICONS || semantic_icons;
124
139
  if (_semanticIcons !== void 0) {
@@ -19,7 +19,12 @@ const getColor = (value, key, config) => {
19
19
  [name, alpha, tone] = value;
20
20
  } else {
21
21
  const parsed = parseColorToken(value);
22
- if (!parsed) return value;
22
+ if (!parsed) {
23
+ const { color: COLOR2, gradient: GRADIENT2 } = CONFIG;
24
+ const directVal = GRADIENT2[value] || COLOR2[value];
25
+ if (directVal) return CONFIG.useVariable ? `var(${directVal.var})` : directVal.value;
26
+ return value;
27
+ }
23
28
  if (parsed.passthrough) return parsed.passthrough;
24
29
  if (parsed.cssVar) return `var(${parsed.cssVar})`;
25
30
  name = parsed.name;
@@ -27,8 +27,12 @@ const setFont = (val, key) => {
27
27
  } else if (val[0]) {
28
28
  fontFace = getFontFaceEach(key, val, CONFIG.files);
29
29
  } else {
30
- const url = resolveFileUrl(val.url, CONFIG.files) || val.url;
31
- fontFace = setCustomFontMedia(key, url);
30
+ const url = Array.isArray(val.url) ? val.url.map((u) => resolveFileUrl(u, CONFIG.files) || u) : resolveFileUrl(val.url, CONFIG.files) || val.url;
31
+ fontFace = setCustomFontMedia(key, url, val.fontWeight, {
32
+ fontStyle: val.fontStyle,
33
+ fontDisplay: val.fontDisplay,
34
+ fontStretch: val.fontStretch
35
+ });
32
36
  }
33
37
  return { var: CSSvar, value: val, fontFace };
34
38
  };
@@ -247,6 +247,8 @@ const recursiveTheme = (val) => {
247
247
  continue;
248
248
  } else if (symb === ":") {
249
249
  obj[`&${param}`] = recursiveTheme(val[param]);
250
+ } else if (symb === ".") {
251
+ obj[`&${param}`] = recursiveTheme(val[param]);
250
252
  }
251
253
  } else obj[param] = val[param];
252
254
  }
@@ -24,24 +24,28 @@ const isGoogleFontsUrl = (url) => url && (url.includes("fonts.googleapis.com") |
24
24
  const setFontImport = (url) => `@import url('${url}');`;
25
25
  const setInCustomFontMedia = (str) => `@font-face { ${str} }`;
26
26
  const setCustomFont = (name, url, weight, options = {}) => {
27
- const format = getFontFormat(url);
28
- const formatStr = format ? ` format('${format}')` : "";
27
+ const urls = Array.isArray(url) ? url : [url];
28
+ const srcList = urls.map((u) => {
29
+ const format = getFontFormat(u);
30
+ const formatStr = format ? ` format('${format}')` : "";
31
+ return `url('${u}')${formatStr}`;
32
+ }).join(",\n ");
29
33
  return `
30
34
  font-family: '${name}';
31
- font-style: normal;${weight ? `
35
+ font-style: ${options.fontStyle || "normal"};${weight ? `
32
36
  font-weight: ${weight};` : ""}${options.fontStretch ? `
33
37
  font-stretch: ${options.fontStretch};` : ""}${options.fontDisplay ? `
34
38
  font-display: ${options.fontDisplay};` : ""}
35
- src: url('${url}')${formatStr};`;
39
+ src: ${srcList};`;
36
40
  };
37
41
  const setCustomFontMedia = (name, url, weight, options) => `@font-face {${setCustomFont(name, url, weight, options)}
38
42
  }`;
39
43
  const getFontFaceEach = (name, weights, files) => {
40
44
  const keys = Object.keys(weights);
41
45
  return keys.map((key) => {
42
- const { url, fontWeight } = weights[key];
43
- const resolvedUrl = resolveFileUrl(url, files) || url;
44
- return setCustomFont(name, resolvedUrl, fontWeight);
46
+ const { url, fontWeight, fontStyle, fontDisplay, fontStretch } = weights[key];
47
+ const resolvedUrl = Array.isArray(url) ? url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(url, files) || url;
48
+ return setCustomFont(name, resolvedUrl, fontWeight, { fontStyle, fontDisplay, fontStretch });
45
49
  });
46
50
  };
47
51
  const getFontFace = (LIBRARY) => {
@@ -61,8 +65,12 @@ const getFontFaceEachString = (name, weights, files) => {
61
65
  }
62
66
  const isArr = weights[0];
63
67
  if (isArr) return getFontFaceEach(name, weights, files).map(setInCustomFontMedia);
64
- const url = resolveFileUrl(weights.url, files) || weights.url;
65
- return setCustomFontMedia(name, url);
68
+ const url = Array.isArray(weights.url) ? weights.url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(weights.url, files) || weights.url;
69
+ return setCustomFontMedia(name, url, weights.fontWeight, {
70
+ fontStyle: weights.fontStyle,
71
+ fontDisplay: weights.fontDisplay,
72
+ fontStretch: weights.fontStretch
73
+ });
66
74
  };
67
75
  const getFontFaceString = (LIBRARY, files) => {
68
76
  const keys = Object.keys(LIBRARY);
@@ -467,7 +467,6 @@ var SmblsScratch = (() => {
467
467
  applyTimingSequence: () => applyTimingSequence,
468
468
  applyTypographySequence: () => applyTypographySequence,
469
469
  breakpoints: () => breakpoints,
470
- cases: () => cases,
471
470
  changeGlobalTheme: () => changeGlobalTheme,
472
471
  changeLightness: () => changeLightness,
473
472
  checkIfBoxSize: () => checkIfBoxSize,
@@ -584,7 +583,8 @@ var SmblsScratch = (() => {
584
583
  transformTransition: () => transformTransition,
585
584
  transfromGap: () => transfromGap,
586
585
  typography: () => typography,
587
- unit: () => unit
586
+ unit: () => unit,
587
+ vars: () => vars
588
588
  });
589
589
 
590
590
  // src/utils/index.js
@@ -905,24 +905,28 @@ var SmblsScratch = (() => {
905
905
  var setFontImport = (url) => `@import url('${url}');`;
906
906
  var setInCustomFontMedia = (str) => `@font-face { ${str} }`;
907
907
  var setCustomFont = (name, url, weight, options = {}) => {
908
- const format = getFontFormat(url);
909
- const formatStr = format ? ` format('${format}')` : "";
908
+ const urls = Array.isArray(url) ? url : [url];
909
+ const srcList = urls.map((u) => {
910
+ const format = getFontFormat(u);
911
+ const formatStr = format ? ` format('${format}')` : "";
912
+ return `url('${u}')${formatStr}`;
913
+ }).join(",\n ");
910
914
  return `
911
915
  font-family: '${name}';
912
- font-style: normal;${weight ? `
916
+ font-style: ${options.fontStyle || "normal"};${weight ? `
913
917
  font-weight: ${weight};` : ""}${options.fontStretch ? `
914
918
  font-stretch: ${options.fontStretch};` : ""}${options.fontDisplay ? `
915
919
  font-display: ${options.fontDisplay};` : ""}
916
- src: url('${url}')${formatStr};`;
920
+ src: ${srcList};`;
917
921
  };
918
922
  var setCustomFontMedia = (name, url, weight, options) => `@font-face {${setCustomFont(name, url, weight, options)}
919
923
  }`;
920
924
  var getFontFaceEach = (name, weights, files) => {
921
925
  const keys = Object.keys(weights);
922
926
  return keys.map((key) => {
923
- const { url, fontWeight } = weights[key];
924
- const resolvedUrl = resolveFileUrl(url, files) || url;
925
- return setCustomFont(name, resolvedUrl, fontWeight);
927
+ const { url, fontWeight, fontStyle, fontDisplay, fontStretch } = weights[key];
928
+ const resolvedUrl = Array.isArray(url) ? url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(url, files) || url;
929
+ return setCustomFont(name, resolvedUrl, fontWeight, { fontStyle, fontDisplay, fontStretch });
926
930
  });
927
931
  };
928
932
  var getFontFace = (LIBRARY) => {
@@ -942,8 +946,12 @@ var SmblsScratch = (() => {
942
946
  }
943
947
  const isArr = weights[0];
944
948
  if (isArr) return getFontFaceEach(name, weights, files).map(setInCustomFontMedia);
945
- const url = resolveFileUrl(weights.url, files) || weights.url;
946
- return setCustomFontMedia(name, url);
949
+ const url = Array.isArray(weights.url) ? weights.url.map((u) => resolveFileUrl(u, files) || u) : resolveFileUrl(weights.url, files) || weights.url;
950
+ return setCustomFontMedia(name, url, weights.fontWeight, {
951
+ fontStyle: weights.fontStyle,
952
+ fontDisplay: weights.fontDisplay,
953
+ fontStretch: weights.fontStretch
954
+ });
947
955
  };
948
956
  var getFontFaceString = (LIBRARY, files) => {
949
957
  const keys = Object.keys(LIBRARY);
@@ -977,7 +985,6 @@ var SmblsScratch = (() => {
977
985
  CLASS: () => CLASS,
978
986
  animation: () => animation,
979
987
  breakpoints: () => breakpoints,
980
- cases: () => cases,
981
988
  color: () => color,
982
989
  devices: () => devices,
983
990
  document: () => document3,
@@ -1000,7 +1007,8 @@ var SmblsScratch = (() => {
1000
1007
  theme: () => theme,
1001
1008
  timing: () => timing,
1002
1009
  typography: () => typography,
1003
- unit: () => unit
1010
+ unit: () => unit,
1011
+ vars: () => vars
1004
1012
  });
1005
1013
 
1006
1014
  // src/defaultConfig/sequence.js
@@ -1150,9 +1158,6 @@ var SmblsScratch = (() => {
1150
1158
  mobileXS: [375, 768]
1151
1159
  };
1152
1160
 
1153
- // src/defaultConfig/cases.js
1154
- var cases = {};
1155
-
1156
1161
  // src/defaultConfig/animation.js
1157
1162
  var animation = {};
1158
1163
 
@@ -1173,6 +1178,7 @@ var SmblsScratch = (() => {
1173
1178
 
1174
1179
  // src/defaultConfig/index.js
1175
1180
  var reset = {};
1181
+ var vars = {};
1176
1182
 
1177
1183
  // src/factory.js
1178
1184
  var CSS_VARS = {};
@@ -1514,20 +1520,20 @@ var SmblsScratch = (() => {
1514
1520
  CSS_VARS2[result.var] = result.value;
1515
1521
  }
1516
1522
  };
1517
- var applySequenceGlobalVars = (vars, obj, options) => {
1523
+ var applySequenceGlobalVars = (vars2, obj, options) => {
1518
1524
  const CONFIG2 = getActiveConfig();
1519
1525
  const { unit: UNIT } = CONFIG2;
1520
1526
  const unit2 = obj.unit || UNIT.default;
1521
1527
  const { base, ratio, type } = obj;
1522
1528
  const prefix = "--" + (type && type.replace(".", "-"));
1523
- vars[`${prefix}-base`] = base;
1524
- vars[`${prefix}-unit`] = unit2;
1529
+ vars2[`${prefix}-base`] = base;
1530
+ vars2[`${prefix}-unit`] = unit2;
1525
1531
  const ratioVar = `${prefix}-ratio`;
1526
- vars[ratioVar] = ratio;
1532
+ vars2[ratioVar] = ratio;
1527
1533
  const [first, middle, second] = getSubratio(base, ratio);
1528
- vars[`${prefix}-sub-ratio-1`] = `calc(var(${prefix}-ratio) * ${first / ratio})`;
1529
- vars[`${prefix}-sub-ratio-2`] = `calc(var(${prefix}-ratio) * ${middle / ratio})`;
1530
- vars[`${prefix}-sub-ratio-3`] = `calc(var(${prefix}-ratio) * ${second / ratio})`;
1534
+ vars2[`${prefix}-sub-ratio-1`] = `calc(var(${prefix}-ratio) * ${first / ratio})`;
1535
+ vars2[`${prefix}-sub-ratio-2`] = `calc(var(${prefix}-ratio) * ${middle / ratio})`;
1536
+ vars2[`${prefix}-sub-ratio-3`] = `calc(var(${prefix}-ratio) * ${second / ratio})`;
1531
1537
  };
1532
1538
  var applySequenceVars = (FACTORY2, options = {}) => {
1533
1539
  const CONFIG2 = getActiveConfig();
@@ -1692,7 +1698,12 @@ var SmblsScratch = (() => {
1692
1698
  [name, alpha, tone] = value;
1693
1699
  } else {
1694
1700
  const parsed = parseColorToken(value);
1695
- if (!parsed) return value;
1701
+ if (!parsed) {
1702
+ const { color: COLOR2, gradient: GRADIENT2 } = CONFIG2;
1703
+ const directVal = GRADIENT2[value] || COLOR2[value];
1704
+ if (directVal) return CONFIG2.useVariable ? `var(${directVal.var})` : directVal.value;
1705
+ return value;
1706
+ }
1696
1707
  if (parsed.passthrough) return parsed.passthrough;
1697
1708
  if (parsed.cssVar) return `var(${parsed.cssVar})`;
1698
1709
  name = parsed.name;
@@ -2090,6 +2101,8 @@ var SmblsScratch = (() => {
2090
2101
  continue;
2091
2102
  } else if (symb === ":") {
2092
2103
  obj[`&${param}`] = recursiveTheme(val[param]);
2104
+ } else if (symb === ".") {
2105
+ obj[`&${param}`] = recursiveTheme(val[param]);
2093
2106
  }
2094
2107
  } else obj[param] = val[param];
2095
2108
  }
@@ -2147,8 +2160,12 @@ var SmblsScratch = (() => {
2147
2160
  } else if (val[0]) {
2148
2161
  fontFace = getFontFaceEach(key, val, CONFIG2.files);
2149
2162
  } else {
2150
- const url = resolveFileUrl(val.url, CONFIG2.files) || val.url;
2151
- fontFace = setCustomFontMedia(key, url);
2163
+ const url = Array.isArray(val.url) ? val.url.map((u) => resolveFileUrl(u, CONFIG2.files) || u) : resolveFileUrl(val.url, CONFIG2.files) || val.url;
2164
+ fontFace = setCustomFontMedia(key, url, val.fontWeight, {
2165
+ fontStyle: val.fontStyle,
2166
+ fontDisplay: val.fontDisplay,
2167
+ fontStretch: val.fontStretch
2168
+ });
2152
2169
  }
2153
2170
  return { var: CSSvar, value: val, fontFace };
2154
2171
  };
@@ -2783,11 +2800,14 @@ var SmblsScratch = (() => {
2783
2800
 
2784
2801
  // src/set.js
2785
2802
  init_esm();
2786
- var setCases = (val, key) => {
2787
- if (isFunction(val)) return val();
2803
+ var setVars = (val, key) => {
2804
+ const CONFIG2 = getActiveConfig();
2805
+ const { CSS_VARS: CSS_VARS2 } = CONFIG2;
2806
+ const varName = key.startsWith("--") ? key : `--${key}`;
2807
+ CSS_VARS2[varName] = val;
2788
2808
  return val;
2789
2809
  };
2790
- var setSameValue = (val, key) => val;
2810
+ var asIs = (val) => val;
2791
2811
  var VALUE_TRANSFORMERS = {
2792
2812
  color: setColor,
2793
2813
  gradient: setGradient,
@@ -2796,21 +2816,21 @@ var SmblsScratch = (() => {
2796
2816
  fontfamily: setFontFamily,
2797
2817
  theme: setTheme,
2798
2818
  icons: setSvgIcon,
2799
- semantic_icons: setSameValue,
2800
- semanticicons: setSameValue,
2819
+ semantic_icons: asIs,
2820
+ semanticicons: asIs,
2801
2821
  svg: setSVG,
2802
- svg_data: setSameValue,
2803
- typography: setSameValue,
2804
- cases: setCases,
2822
+ svg_data: asIs,
2823
+ typography: asIs,
2805
2824
  shadow: setShadow,
2806
- spacing: setSameValue,
2807
- media: setSameValue,
2808
- grid: setSameValue,
2809
- class: setSameValue,
2810
- timing: setSameValue,
2811
- reset: setSameValue,
2812
- unit: setSameValue,
2813
- animation: setSameValue
2825
+ spacing: asIs,
2826
+ media: asIs,
2827
+ grid: asIs,
2828
+ class: asIs,
2829
+ timing: asIs,
2830
+ reset: asIs,
2831
+ unit: asIs,
2832
+ animation: asIs,
2833
+ vars: setVars
2814
2834
  };
2815
2835
  var setValue = (factoryName, value, key) => {
2816
2836
  const CONFIG2 = getActiveConfig();
@@ -2822,10 +2842,12 @@ var SmblsScratch = (() => {
2822
2842
  FACTORY2[key] = result;
2823
2843
  return FACTORY2;
2824
2844
  } catch (error) {
2825
- if (CONFIG2.verbose) console.warn("Error setting", lowerName, "value", value, key, error);
2845
+ if (CONFIG2.verbose)
2846
+ console.warn("Error setting", lowerName, "value", value, key, error);
2826
2847
  }
2827
2848
  }
2828
- if (CONFIG2.verbose) console.warn("Can not find", lowerName, "method in scratch");
2849
+ if (CONFIG2.verbose)
2850
+ console.warn("Can not find", lowerName, "method in scratch");
2829
2851
  };
2830
2852
  var setEach = (factoryName, props) => {
2831
2853
  const CONFIG2 = getActiveConfig();
@@ -2835,7 +2857,15 @@ var SmblsScratch = (() => {
2835
2857
  try {
2836
2858
  return setValue(lowerName, props[key], key);
2837
2859
  } catch (error) {
2838
- if (CONFIG2.verbose) console.warn("Error setting", lowerName, "value", props[key], key, error);
2860
+ if (CONFIG2.verbose)
2861
+ console.warn(
2862
+ "Error setting",
2863
+ lowerName,
2864
+ "value",
2865
+ props[key],
2866
+ key,
2867
+ error
2868
+ );
2839
2869
  }
2840
2870
  });
2841
2871
  return CONFIG2[lowerName] || CONFIG2[factoryName];
@@ -2870,6 +2900,7 @@ var SmblsScratch = (() => {
2870
2900
  useDefaultConfig,
2871
2901
  semanticIcons,
2872
2902
  SEMANTIC_ICONS,
2903
+ // deprecated
2873
2904
  semantic_icons: semantic_icons2,
2874
2905
  files,
2875
2906
  ...config
@@ -2886,7 +2917,8 @@ var SmblsScratch = (() => {
2886
2917
  if (useIconSprite !== void 0) CONFIG2.useIconSprite = useIconSprite;
2887
2918
  if (useDocumentTheme !== void 0) CONFIG2.useDocumentTheme = useDocumentTheme;
2888
2919
  if (globalTheme !== void 0) CONFIG2.globalTheme = globalTheme;
2889
- if (recivedConfig.useThemeSuffixedVars !== void 0) CONFIG2.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
2920
+ if (recivedConfig.useThemeSuffixedVars !== void 0)
2921
+ CONFIG2.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars;
2890
2922
  if (useDefaultConfig !== void 0) CONFIG2.useDefaultConfig = useDefaultConfig;
2891
2923
  const _semanticIcons = semanticIcons || SEMANTIC_ICONS || semantic_icons2;
2892
2924
  if (_semanticIcons !== void 0) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@symbo.ls/scratch",
3
3
  "description": "Φ / CSS framework and methodology.",
4
4
  "author": "symbo.ls",
5
- "version": "3.8.0",
5
+ "version": "3.8.1",
6
6
  "files": [
7
7
  "dist",
8
8
  "*.js",
@@ -33,8 +33,8 @@
33
33
  "prepublish": "npm run build && npm run copy:package:cjs"
34
34
  },
35
35
  "dependencies": {
36
- "@domql/utils": "^3.8.0",
37
- "@symbo.ls/smbls-utils": "^3.8.0",
36
+ "@domql/utils": "^3.8.1",
37
+ "@symbo.ls/smbls-utils": "^3.8.1",
38
38
  "color-contrast-checker": "^1.5.0"
39
39
  },
40
40
  "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681",
@@ -14,7 +14,6 @@ export * from './icons.js'
14
14
  export * from './timing.js'
15
15
  export * from './document.js'
16
16
  export * from './responsive.js'
17
- export * from './cases.js'
18
17
  export * from './animation.js'
19
18
  export * from './svg.js'
20
19
  export * from './templates.js'
@@ -22,3 +21,4 @@ export * from './grid.js'
22
21
  export * from './class.js'
23
22
 
24
23
  export const reset = {}
24
+ export const vars = {}
package/src/set.js CHANGED
@@ -17,14 +17,17 @@ import {
17
17
  setShadow
18
18
  } from './system'
19
19
 
20
- import { isFunction, deepMerge } from '@domql/utils'
20
+ import { deepMerge } from '@domql/utils'
21
21
 
22
- const setCases = (val, key) => {
23
- if (isFunction(val)) return val()
22
+ const setVars = (val, key) => {
23
+ const CONFIG = getActiveConfig()
24
+ const { CSS_VARS } = CONFIG
25
+ const varName = key.startsWith('--') ? key : `--${key}`
26
+ CSS_VARS[varName] = val
24
27
  return val
25
28
  }
26
29
 
27
- const setSameValue = (val, key) => val
30
+ const asIs = (val) => val
28
31
 
29
32
  export const VALUE_TRANSFORMERS = {
30
33
  color: setColor,
@@ -34,21 +37,21 @@ export const VALUE_TRANSFORMERS = {
34
37
  fontfamily: setFontFamily,
35
38
  theme: setTheme,
36
39
  icons: setSvgIcon,
37
- semantic_icons: setSameValue,
38
- semanticicons: setSameValue,
40
+ semantic_icons: asIs,
41
+ semanticicons: asIs,
39
42
  svg: setSVG,
40
- svg_data: setSameValue,
41
- typography: setSameValue,
42
- cases: setCases,
43
+ svg_data: asIs,
44
+ typography: asIs,
43
45
  shadow: setShadow,
44
- spacing: setSameValue,
45
- media: setSameValue,
46
- grid: setSameValue,
47
- class: setSameValue,
48
- timing: setSameValue,
49
- reset: setSameValue,
50
- unit: setSameValue,
51
- animation: setSameValue
46
+ spacing: asIs,
47
+ media: asIs,
48
+ grid: asIs,
49
+ class: asIs,
50
+ timing: asIs,
51
+ reset: asIs,
52
+ unit: asIs,
53
+ animation: asIs,
54
+ vars: setVars
52
55
  }
53
56
 
54
57
  /**
@@ -69,11 +72,13 @@ export const setValue = (factoryName, value, key) => {
69
72
  FACTORY[key] = result
70
73
  return FACTORY
71
74
  } catch (error) {
72
- if (CONFIG.verbose) console.warn('Error setting', lowerName, 'value', value, key, error)
75
+ if (CONFIG.verbose)
76
+ console.warn('Error setting', lowerName, 'value', value, key, error)
73
77
  }
74
78
  }
75
79
 
76
- if (CONFIG.verbose) console.warn('Can not find', lowerName, 'method in scratch')
80
+ if (CONFIG.verbose)
81
+ console.warn('Can not find', lowerName, 'method in scratch')
77
82
  }
78
83
 
79
84
  export const setEach = (factoryName, props) => {
@@ -85,7 +90,15 @@ export const setEach = (factoryName, props) => {
85
90
  try {
86
91
  return setValue(lowerName, props[key], key)
87
92
  } catch (error) {
88
- if (CONFIG.verbose) console.warn('Error setting', lowerName, 'value', props[key], key, error)
93
+ if (CONFIG.verbose)
94
+ console.warn(
95
+ 'Error setting',
96
+ lowerName,
97
+ 'value',
98
+ props[key],
99
+ key,
100
+ error
101
+ )
89
102
  }
90
103
  })
91
104
 
@@ -131,7 +144,7 @@ export const set = (recivedConfig, options = SET_OPTIONS) => {
131
144
  useDocumentTheme,
132
145
  useDefaultConfig,
133
146
  semanticIcons,
134
- SEMANTIC_ICONS,
147
+ SEMANTIC_ICONS, // deprecated
135
148
  semantic_icons,
136
149
  files,
137
150
  ...config
@@ -150,7 +163,8 @@ export const set = (recivedConfig, options = SET_OPTIONS) => {
150
163
  if (useIconSprite !== undefined) CONFIG.useIconSprite = useIconSprite
151
164
  if (useDocumentTheme !== undefined) CONFIG.useDocumentTheme = useDocumentTheme
152
165
  if (globalTheme !== undefined) CONFIG.globalTheme = globalTheme
153
- if (recivedConfig.useThemeSuffixedVars !== undefined) CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars
166
+ if (recivedConfig.useThemeSuffixedVars !== undefined)
167
+ CONFIG.useThemeSuffixedVars = recivedConfig.useThemeSuffixedVars
154
168
  if (useDefaultConfig !== undefined) CONFIG.useDefaultConfig = useDefaultConfig
155
169
  const _semanticIcons = semanticIcons || SEMANTIC_ICONS || semantic_icons
156
170
  if (_semanticIcons !== undefined) {
@@ -166,7 +180,7 @@ export const set = (recivedConfig, options = SET_OPTIONS) => {
166
180
  const keySet = new Set(keys)
167
181
 
168
182
  // Pre-merge: fold UPPERCASE default keys into lowercase project keys
169
- keys.forEach(key => {
183
+ keys.forEach((key) => {
170
184
  const lower = key.toLowerCase()
171
185
  if (lower !== key && keySet.has(lower)) {
172
186
  deepMerge(config[lower], config[key])
@@ -174,25 +188,31 @@ export const set = (recivedConfig, options = SET_OPTIONS) => {
174
188
  })
175
189
 
176
190
  // Process only lowercase keys (skip UPPERCASE when lowercase equivalent exists)
177
- keys.map(key => {
191
+ keys.map((key) => {
178
192
  const lower = key.toLowerCase()
179
193
  if (lower !== key && keySet.has(lower)) return
180
194
  return setEach(key, config[key])
181
195
  })
182
196
 
183
197
  // apply generic configs
184
- if (config.typography || config.TYPOGRAPHY) {
185
- try { applyTypographySequence() } catch (e) {
198
+ if (config.typography || config.TYPOGRAPHY) { // UPPERCASE deprecated
199
+ try {
200
+ applyTypographySequence()
201
+ } catch (e) {
186
202
  if (CONFIG.verbose) console.warn('Error applying typography sequence', e)
187
203
  }
188
204
  }
189
- if (config.spacing || config.SPACING) {
190
- try { applySpacingSequence() } catch (e) {
205
+ if (config.spacing || config.SPACING) { // UPPERCASE deprecated
206
+ try {
207
+ applySpacingSequence()
208
+ } catch (e) {
191
209
  if (CONFIG.verbose) console.warn('Error applying spacing sequence', e)
192
210
  }
193
211
  }
194
- if (config.timing || config.TIMING) {
195
- try { applyTimingSequence() } catch (e) {
212
+ if (config.timing || config.TIMING) { // UPPERCASE deprecated
213
+ try {
214
+ applyTimingSequence()
215
+ } catch (e) {
196
216
  if (CONFIG.verbose) console.warn('Error applying timing sequence', e)
197
217
  }
198
218
  }
@@ -26,7 +26,13 @@ export const getColor = (value, key, config) => {
26
26
  [name, alpha, tone] = value
27
27
  } else {
28
28
  const parsed = parseColorToken(value)
29
- if (!parsed) return value
29
+ if (!parsed) {
30
+ // Direct lookup for hyphenated names (e.g. 'gradient-light', 'gradient-dark-active')
31
+ const { color: COLOR, gradient: GRADIENT } = CONFIG
32
+ const directVal = GRADIENT[value] || COLOR[value]
33
+ if (directVal) return CONFIG.useVariable ? `var(${directVal.var})` : directVal.value
34
+ return value
35
+ }
30
36
  if (parsed.passthrough) return parsed.passthrough
31
37
  if (parsed.cssVar) return `var(${parsed.cssVar})`
32
38
  name = parsed.name
@@ -33,8 +33,14 @@ export const setFont = (val, key) => {
33
33
  } else if (val[0]) {
34
34
  fontFace = getFontFaceEach(key, val, CONFIG.files)
35
35
  } else {
36
- const url = resolveFileUrl(val.url, CONFIG.files) || val.url
37
- fontFace = setCustomFontMedia(key, url)
36
+ const url = Array.isArray(val.url)
37
+ ? val.url.map((u) => resolveFileUrl(u, CONFIG.files) || u)
38
+ : resolveFileUrl(val.url, CONFIG.files) || val.url
39
+ fontFace = setCustomFontMedia(key, url, val.fontWeight, {
40
+ fontStyle: val.fontStyle,
41
+ fontDisplay: val.fontDisplay,
42
+ fontStretch: val.fontStretch
43
+ })
38
44
  }
39
45
 
40
46
  return { var: CSSvar, value: val, fontFace }
@@ -310,6 +310,8 @@ const recursiveTheme = val => {
310
310
  continue
311
311
  } else if (symb === ':') {
312
312
  obj[`&${param}`] = recursiveTheme(val[param])
313
+ } else if (symb === '.') {
314
+ obj[`&${param}`] = recursiveTheme(val[param])
313
315
  }
314
316
  } else obj[param] = val[param]
315
317
  }
package/src/utils/font.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  export const resolveFileUrl = (url, files) => {
4
4
  if (!url || !files) return null
5
- try { new URL(url); return null } catch (e) { }
5
+ try { new URL(url); return null } catch (e) { } // expected: src is not an absolute URL, treating as relative path
6
6
  const file = files[url]
7
7
  if (file) return file.content && file.content.src
8
8
  return null
@@ -30,11 +30,15 @@ export const setFontImport = (url) => `@import url('${url}');`
30
30
  export const setInCustomFontMedia = (str) => `@font-face { ${str} }`
31
31
 
32
32
  export const setCustomFont = (name, url, weight, options = {}) => {
33
- const format = getFontFormat(url)
34
- const formatStr = format ? ` format('${format}')` : ''
33
+ const urls = Array.isArray(url) ? url : [url]
34
+ const srcList = urls.map((u) => {
35
+ const format = getFontFormat(u)
36
+ const formatStr = format ? ` format('${format}')` : ''
37
+ return `url('${u}')${formatStr}`
38
+ }).join(',\n ')
35
39
  return `
36
40
  font-family: '${name}';
37
- font-style: normal;${
41
+ font-style: ${options.fontStyle || 'normal'};${
38
42
  weight
39
43
  ? `
40
44
  font-weight: ${weight};`
@@ -50,7 +54,7 @@ export const setCustomFont = (name, url, weight, options = {}) => {
50
54
  font-display: ${options.fontDisplay};`
51
55
  : ''
52
56
  }
53
- src: url('${url}')${formatStr};`
57
+ src: ${srcList};`
54
58
  }
55
59
 
56
60
  export const setCustomFontMedia = (
@@ -64,9 +68,11 @@ export const setCustomFontMedia = (
64
68
  export const getFontFaceEach = (name, weights, files) => {
65
69
  const keys = Object.keys(weights)
66
70
  return keys.map((key) => {
67
- const { url, fontWeight } = weights[key]
68
- const resolvedUrl = resolveFileUrl(url, files) || url
69
- return setCustomFont(name, resolvedUrl, fontWeight)
71
+ const { url, fontWeight, fontStyle, fontDisplay, fontStretch } = weights[key]
72
+ const resolvedUrl = Array.isArray(url)
73
+ ? url.map((u) => resolveFileUrl(u, files) || u)
74
+ : resolveFileUrl(url, files) || url
75
+ return setCustomFont(name, resolvedUrl, fontWeight, { fontStyle, fontDisplay, fontStretch })
70
76
  })
71
77
  }
72
78
 
@@ -88,8 +94,14 @@ export const getFontFaceEachString = (name, weights, files) => {
88
94
  }
89
95
  const isArr = weights[0]
90
96
  if (isArr) return getFontFaceEach(name, weights, files).map(setInCustomFontMedia)
91
- const url = resolveFileUrl(weights.url, files) || weights.url
92
- return setCustomFontMedia(name, url)
97
+ const url = Array.isArray(weights.url)
98
+ ? weights.url.map((u) => resolveFileUrl(u, files) || u)
99
+ : resolveFileUrl(weights.url, files) || weights.url
100
+ return setCustomFontMedia(name, url, weights.fontWeight, {
101
+ fontStyle: weights.fontStyle,
102
+ fontDisplay: weights.fontDisplay,
103
+ fontStretch: weights.fontStretch
104
+ })
93
105
  }
94
106
 
95
107
  export const getFontFaceString = (LIBRARY, files) => {