zyzz 0.0.2 → 0.0.5

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 (252) hide show
  1. package/README.md +34 -19
  2. package/dist/Config.d.ts +16 -167
  3. package/dist/Config.d.ts.map +1 -1
  4. package/dist/Config.js +7 -246
  5. package/dist/Config.js.map +1 -1
  6. package/dist/Style.d.ts +19 -13
  7. package/dist/Style.d.ts.map +1 -1
  8. package/dist/Style.js +73 -7
  9. package/dist/Style.js.map +1 -1
  10. package/dist/Vars.d.ts +114 -0
  11. package/dist/Vars.d.ts.map +1 -0
  12. package/dist/Vars.js +42 -0
  13. package/dist/Vars.js.map +1 -0
  14. package/dist/compiler/Graph.js +11 -8
  15. package/dist/compiler/Graph.js.map +1 -1
  16. package/dist/compiler/Native.d.ts +5 -5
  17. package/dist/compiler/Native.d.ts.map +1 -1
  18. package/dist/compiler/Native.js +21 -21
  19. package/dist/compiler/Native.js.map +1 -1
  20. package/dist/compiler/Source.d.ts +10 -6
  21. package/dist/compiler/Source.d.ts.map +1 -1
  22. package/dist/compiler/Source.js +66 -11
  23. package/dist/compiler/Source.js.map +1 -1
  24. package/dist/compiler/Transform.d.ts +1 -1
  25. package/dist/compiler/Transform.d.ts.map +1 -1
  26. package/dist/compiler/Transform.js +59 -21
  27. package/dist/compiler/Transform.js.map +1 -1
  28. package/dist/compiler/internal/Compositions.d.ts +5 -0
  29. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  30. package/dist/compiler/internal/Compositions.js +22 -3
  31. package/dist/compiler/internal/Compositions.js.map +1 -1
  32. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  33. package/dist/compiler/internal/Configurations.js +73 -12
  34. package/dist/compiler/internal/Configurations.js.map +1 -1
  35. package/dist/compiler/internal/Contract.d.ts +1 -1
  36. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  37. package/dist/compiler/internal/Contract.js +162 -13
  38. package/dist/compiler/internal/Contract.js.map +1 -1
  39. package/dist/compiler/internal/Contributions.js +1 -1
  40. package/dist/compiler/internal/Contributions.js.map +1 -1
  41. package/dist/compiler/internal/Dynamic.js +1 -1
  42. package/dist/compiler/internal/Dynamic.js.map +1 -1
  43. package/dist/compiler/internal/Expression.d.ts +3 -0
  44. package/dist/compiler/internal/Expression.d.ts.map +1 -1
  45. package/dist/compiler/internal/Expression.js +21 -0
  46. package/dist/compiler/internal/Expression.js.map +1 -1
  47. package/dist/compiler/internal/Identifiers.d.ts +1 -1
  48. package/dist/compiler/internal/Identifiers.d.ts.map +1 -1
  49. package/dist/compiler/internal/Identifiers.js +2 -2
  50. package/dist/compiler/internal/Identifiers.js.map +1 -1
  51. package/dist/compiler/internal/NativeBindings.d.ts +1 -1
  52. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  53. package/dist/compiler/internal/NativeBindings.js +3 -3
  54. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  55. package/dist/compiler/internal/PackedStyles.d.ts +1 -1
  56. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  57. package/dist/compiler/internal/PackedStyles.js +15 -25
  58. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  59. package/dist/compiler/internal/Recipes.js +1 -1
  60. package/dist/compiler/internal/Recipes.js.map +1 -1
  61. package/dist/compiler/internal/Selectors.js +1 -1
  62. package/dist/compiler/internal/Selectors.js.map +1 -1
  63. package/dist/compiler/internal/Themes.d.ts +12 -3
  64. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  65. package/dist/compiler/internal/Themes.js +192 -52
  66. package/dist/compiler/internal/Themes.js.map +1 -1
  67. package/dist/compiler/internal/{Variables.d.ts → Vars.d.ts} +1 -1
  68. package/dist/compiler/internal/Vars.d.ts.map +1 -0
  69. package/dist/compiler/internal/{Variables.js → Vars.js} +3 -3
  70. package/dist/compiler/internal/Vars.js.map +1 -0
  71. package/dist/default.d.ts +451 -1649
  72. package/dist/default.d.ts.map +1 -1
  73. package/dist/default.js +389 -80
  74. package/dist/default.js.map +2 -2
  75. package/dist/default.js.zyzz.json +1 -1
  76. package/dist/esbuild/index.d.ts +3 -0
  77. package/dist/esbuild/index.d.ts.map +1 -0
  78. package/dist/esbuild/index.js +5 -0
  79. package/dist/esbuild/index.js.map +1 -0
  80. package/dist/index.d.ts +4 -4
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +4 -4
  83. package/dist/index.js.map +1 -1
  84. package/dist/internal/Authoring.d.ts +1 -1
  85. package/dist/internal/Authoring.d.ts.map +1 -1
  86. package/dist/internal/Authoring.js +4 -4
  87. package/dist/internal/Authoring.js.map +1 -1
  88. package/dist/internal/Binding.d.ts +1 -1
  89. package/dist/internal/Binding.d.ts.map +1 -1
  90. package/dist/internal/Completion.d.ts +19 -0
  91. package/dist/internal/Completion.d.ts.map +1 -0
  92. package/dist/internal/Completion.js +2 -0
  93. package/dist/internal/Completion.js.map +1 -0
  94. package/dist/internal/Condition.d.ts +3 -1
  95. package/dist/internal/Condition.d.ts.map +1 -1
  96. package/dist/internal/Condition.js.map +1 -1
  97. package/dist/internal/Configuration.d.ts +248 -0
  98. package/dist/internal/Configuration.d.ts.map +1 -0
  99. package/dist/internal/Configuration.js +343 -0
  100. package/dist/internal/Configuration.js.map +1 -0
  101. package/dist/internal/Shorthands.d.ts +1 -1
  102. package/dist/internal/Shorthands.d.ts.map +1 -1
  103. package/dist/internal/Shorthands.js +1 -0
  104. package/dist/internal/Shorthands.js.map +1 -1
  105. package/dist/{Theme.d.ts → internal/Theme.d.ts} +24 -19
  106. package/dist/internal/Theme.d.ts.map +1 -0
  107. package/dist/{Theme.js → internal/Theme.js} +57 -14
  108. package/dist/internal/Theme.js.map +1 -0
  109. package/dist/internal/Token.d.ts +46 -16
  110. package/dist/internal/Token.d.ts.map +1 -1
  111. package/dist/internal/Token.js +89 -5
  112. package/dist/internal/Token.js.map +1 -1
  113. package/dist/internal/Typography.d.ts +31 -0
  114. package/dist/internal/Typography.d.ts.map +1 -0
  115. package/dist/internal/Typography.js +54 -0
  116. package/dist/internal/Typography.js.map +1 -0
  117. package/dist/internal/Value.d.ts +6 -1
  118. package/dist/internal/Value.d.ts.map +1 -1
  119. package/dist/internal/Value.js.map +1 -1
  120. package/dist/internal/VariableSets.d.ts +20 -0
  121. package/dist/internal/VariableSets.d.ts.map +1 -0
  122. package/dist/internal/VariableSets.js +317 -0
  123. package/dist/internal/VariableSets.js.map +1 -0
  124. package/dist/next/loader.js +15 -5
  125. package/dist/next/loader.js.map +1 -1
  126. package/dist/node/Host.d.ts.map +1 -1
  127. package/dist/node/Host.js +1 -1
  128. package/dist/node/Host.js.map +1 -1
  129. package/dist/react-native/Host.d.ts +2 -2
  130. package/dist/react-native/Host.d.ts.map +1 -1
  131. package/dist/react-native/Host.js +4 -4
  132. package/dist/react-native/Host.js.map +1 -1
  133. package/dist/react-native/StyleSheet.d.ts +9 -8
  134. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  135. package/dist/react-native/StyleSheet.js +29 -23
  136. package/dist/react-native/StyleSheet.js.map +1 -1
  137. package/dist/react-native/Variants.d.ts +3 -3
  138. package/dist/react-native/Variants.d.ts.map +1 -1
  139. package/dist/react-native/Variants.js +2 -2
  140. package/dist/react-native/react.d.ts +1 -1
  141. package/dist/react-native/react.d.ts.map +1 -1
  142. package/dist/react-native/react.js +5 -5
  143. package/dist/react-native/react.js.map +1 -1
  144. package/dist/rollup/index.d.ts +3 -0
  145. package/dist/rollup/index.d.ts.map +1 -0
  146. package/dist/rollup/index.js +5 -0
  147. package/dist/rollup/index.js.map +1 -0
  148. package/dist/runtime/Appearance.d.ts +7 -7
  149. package/dist/runtime/Appearance.d.ts.map +1 -1
  150. package/dist/runtime/Appearance.js +15 -15
  151. package/dist/runtime/Appearance.js.map +1 -1
  152. package/dist/runtime/Dynamic.d.ts.map +1 -1
  153. package/dist/runtime/Dynamic.js +4 -1
  154. package/dist/runtime/Dynamic.js.map +1 -1
  155. package/dist/runtime/NativeContext.d.ts +4 -4
  156. package/dist/runtime/NativeContext.d.ts.map +1 -1
  157. package/dist/runtime/NativeContext.js +5 -5
  158. package/dist/runtime/NativeContext.js.map +1 -1
  159. package/dist/runtime/NativeDynamic.d.ts +1 -1
  160. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  161. package/dist/runtime/NativeDynamic.js.map +1 -1
  162. package/dist/runtime/Props.d.ts +1 -1
  163. package/dist/runtime/Props.js +3 -3
  164. package/dist/runtime/Props.js.map +1 -1
  165. package/dist/runtime/Selection.d.ts +14 -10
  166. package/dist/runtime/Selection.d.ts.map +1 -1
  167. package/dist/runtime/Selection.js +19 -18
  168. package/dist/runtime/Selection.js.map +1 -1
  169. package/dist/styleFunction.d.ts +14 -14
  170. package/dist/styleFunction.d.ts.map +1 -1
  171. package/dist/styleFunction.js.map +1 -1
  172. package/dist/unplugin/index.d.ts +20 -0
  173. package/dist/unplugin/index.d.ts.map +1 -0
  174. package/dist/unplugin/index.js +498 -0
  175. package/dist/unplugin/index.js.map +1 -0
  176. package/dist/variants.d.ts +3 -3
  177. package/dist/variants.d.ts.map +1 -1
  178. package/dist/variants.js.map +1 -1
  179. package/dist/vite/index.d.ts.map +1 -1
  180. package/dist/vite/index.js +6 -3
  181. package/dist/vite/index.js.map +1 -1
  182. package/dist/web/Css.d.ts +4 -3
  183. package/dist/web/Css.d.ts.map +1 -1
  184. package/dist/web/Css.js +4 -4
  185. package/dist/web/Css.js.map +1 -1
  186. package/dist/web/internal/Themes.d.ts +3 -2
  187. package/dist/web/internal/Themes.d.ts.map +1 -1
  188. package/dist/web/internal/Themes.js +42 -6
  189. package/dist/web/internal/Themes.js.map +1 -1
  190. package/dist/webpack/index.d.ts +3 -0
  191. package/dist/webpack/index.d.ts.map +1 -0
  192. package/dist/webpack/index.js +5 -0
  193. package/dist/webpack/index.js.map +1 -0
  194. package/package.json +23 -2
  195. package/src/Config.ts +43 -684
  196. package/src/Style.ts +167 -40
  197. package/src/Vars.ts +299 -0
  198. package/src/compiler/Graph.ts +14 -9
  199. package/src/compiler/Native.ts +29 -32
  200. package/src/compiler/Source.ts +85 -18
  201. package/src/compiler/Transform.ts +78 -22
  202. package/src/compiler/internal/Compositions.ts +36 -3
  203. package/src/compiler/internal/Configurations.ts +83 -11
  204. package/src/compiler/internal/Contract.ts +223 -17
  205. package/src/compiler/internal/Contributions.ts +1 -1
  206. package/src/compiler/internal/Dynamic.ts +1 -1
  207. package/src/compiler/internal/Expression.ts +26 -0
  208. package/src/compiler/internal/Identifiers.ts +2 -1
  209. package/src/compiler/internal/NativeBindings.ts +3 -3
  210. package/src/compiler/internal/PackedStyles.ts +22 -26
  211. package/src/compiler/internal/Recipes.ts +1 -1
  212. package/src/compiler/internal/Selectors.ts +1 -1
  213. package/src/compiler/internal/Themes.ts +266 -57
  214. package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
  215. package/src/default.ts +868 -156
  216. package/src/esbuild/index.ts +5 -0
  217. package/src/index.ts +4 -4
  218. package/src/internal/Authoring.ts +5 -7
  219. package/src/internal/Binding.ts +1 -1
  220. package/src/internal/Completion.ts +42 -0
  221. package/src/internal/Condition.ts +31 -1
  222. package/src/internal/Configuration.ts +970 -0
  223. package/src/internal/Shorthands.ts +2 -0
  224. package/src/{Theme.ts → internal/Theme.ts} +174 -48
  225. package/src/internal/Token.ts +258 -85
  226. package/src/internal/Typography.ts +106 -0
  227. package/src/internal/Value.ts +45 -26
  228. package/src/internal/VariableSets.ts +458 -0
  229. package/src/next/loader.ts +19 -5
  230. package/src/node/Host.ts +1 -2
  231. package/src/react-native/Host.ts +6 -6
  232. package/src/react-native/StyleSheet.ts +49 -42
  233. package/src/react-native/Variants.ts +3 -3
  234. package/src/react-native/react.ts +6 -6
  235. package/src/rollup/index.ts +5 -0
  236. package/src/runtime/Appearance.ts +20 -20
  237. package/src/runtime/Dynamic.ts +4 -1
  238. package/src/runtime/NativeContext.ts +8 -8
  239. package/src/runtime/NativeDynamic.ts +2 -4
  240. package/src/runtime/Props.ts +3 -3
  241. package/src/runtime/Selection.ts +44 -33
  242. package/src/styleFunction.ts +22 -19
  243. package/src/unplugin/index.ts +600 -0
  244. package/src/variants.ts +7 -5
  245. package/src/vite/index.ts +5 -4
  246. package/src/web/Css.ts +10 -7
  247. package/src/web/internal/Themes.ts +52 -9
  248. package/src/webpack/index.ts +5 -0
  249. package/dist/Theme.d.ts.map +0 -1
  250. package/dist/Theme.js.map +0 -1
  251. package/dist/compiler/internal/Variables.d.ts.map +0 -1
  252. package/dist/compiler/internal/Variables.js.map +0 -1
package/src/Style.ts CHANGED
@@ -2,13 +2,16 @@
2
2
  * Copies typed style declarations into immutable, ordered, target-independent data.
3
3
  * @module
4
4
  */
5
+ import * as VariableSets from './internal/VariableSets.js'
6
+ import type * as Vars from './Vars.js'
5
7
  import * as Condition from './internal/Condition.js'
6
8
  import * as Query from './internal/Query.js'
7
9
  import * as Binding from './internal/Binding.js'
8
10
  import type * as Literal from './internal/Literal.js'
9
11
  import * as Token from './internal/Token.js'
12
+ import * as Typography from './internal/Typography.js'
10
13
  import * as Value from './internal/Value.js'
11
- import type * as Theme from './Theme.js'
14
+ import type * as Theme from './internal/Theme.js'
12
15
  import * as Targets from './internal/Targets.js'
13
16
 
14
17
  /** Validates only authored keys, recursively retaining nested token inference. */
@@ -24,7 +27,8 @@ export type Accepted<
24
27
  | Condition.Keys<tokens, Keys<style>>
25
28
  | 'selectors'
26
29
  | 'targets'
27
- | 'variables'
30
+ | 'typography'
31
+ | 'vars'
28
32
  >,
29
33
  never
30
34
  > &
@@ -45,38 +49,46 @@ export type Accepted<
45
49
  : never
46
50
  }
47
51
  : never
48
- : key extends 'variables'
52
+ : key extends 'vars'
49
53
  ? style[key] extends Record<string, unknown>
50
54
  ? {
51
55
  [name in keyof style[key]]: style[key][name] extends
52
56
  | number
53
57
  | string
54
58
  ? Literal.Checked<style[key][name]>
55
- : never
59
+ : literal extends true
60
+ ? never
61
+ : style[key][name] extends Token.Reference
62
+ ? style[key][name]
63
+ : never
56
64
  }
57
65
  : never
58
- : key extends keyof Literal.Properties
59
- ? Value.Accepted<
60
- Pick<style, key>,
61
- literal extends true
62
- ? LiteralDeclarations
63
- : DeclarationProperties<tokens>
64
- >[key] &
65
- Value.Checked<Pick<style, key>, tokens>[key]
66
- : key extends Condition.Keys<tokens, key>
67
- ? [style[key]] extends [undefined]
68
- ? never
69
- : NonNullable<style[key]> extends Record<string, unknown>
70
- ?
71
- | Accepted<
72
- NonNullable<style[key]>,
73
- tokens,
74
- literal,
75
- targets
76
- >
77
- | Extract<style[key], undefined>
78
- : never
79
- : never
66
+ : key extends 'typography'
67
+ ? literal extends true
68
+ ? never
69
+ : Value.Atom<Typography.Names<tokens>>
70
+ : key extends keyof Literal.Properties
71
+ ? Value.Accepted<
72
+ Pick<style, key>,
73
+ literal extends true
74
+ ? LiteralDeclarations
75
+ : DeclarationProperties<tokens>
76
+ >[key] &
77
+ Value.Checked<Pick<style, key>, tokens>[key]
78
+ : key extends Condition.Keys<tokens, key>
79
+ ? [style[key]] extends [undefined]
80
+ ? never
81
+ : NonNullable<style[key]> extends Record<string, unknown>
82
+ ?
83
+ | Accepted<
84
+ NonNullable<style[key]>,
85
+ tokens,
86
+ literal,
87
+ targets
88
+ >
89
+ | Extract<style[key], undefined>
90
+ : never
91
+ : never
80
92
  }
81
93
  : never)
82
94
 
@@ -162,6 +174,22 @@ export type Declaration = {
162
174
  * @returns Immutable definitions retaining the inferred style-name union.
163
175
  * @throws {InvalidError} If the input structure cannot represent ordered declarations.
164
176
  */
177
+ export function define<
178
+ const values extends Vars.Values,
179
+ const styles extends Record<string, unknown>,
180
+ >(
181
+ styles: styles &
182
+ NoInfer<Exact<styles, Vars.Mapped<values, {}>>> & {
183
+ [key in keyof styles]: WithoutRelationships<styles[key]>
184
+ },
185
+ options: {
186
+ readonly vars: Vars.Definition<values>
187
+ readonly locations?: readonly SourceLocation[]
188
+ },
189
+ ): Definition<
190
+ `${Extract<keyof styles, string | number>}`,
191
+ Targets.Domains<styles>
192
+ >
165
193
  export function define<
166
194
  const styles extends Record<string, unknown>,
167
195
  const tokens extends Theme.Tokens,
@@ -189,6 +217,11 @@ export function define(
189
217
  styles: Record<string, unknown>,
190
218
  options: define.Options = {},
191
219
  ): Definition {
220
+ const theme =
221
+ options.vars &&
222
+ (typeof Reflect.get(options.vars, 'style') === 'function'
223
+ ? (options.vars as Theme.Definition)
224
+ : VariableSets.theme(options.vars as Vars.Definition))
192
225
  if ((options[nesting] ?? 0) > 128)
193
226
  throw new InvalidError([
194
227
  {
@@ -293,7 +326,7 @@ export function define(
293
326
  if (name.length === 0)
294
327
  report('invalid_structure', [name], 'Style names must not be empty.')
295
328
 
296
- const mappings = options.theme?.[Token.definition].contract.shorthands
329
+ const mappings = theme?.[Token.definition].contract.shorthands
297
330
  const authored = entries(style, [name]).filter(
298
331
  ([key, value]) => key !== 'targets' || value !== undefined,
299
332
  )
@@ -364,21 +397,61 @@ export function define(
364
397
  continue
365
398
  }
366
399
 
367
- const properties = authored.flatMap(([property, input]) =>
368
- (mappings?.[property] ?? [property]).map(
369
- (target) => [target, input, property] as const,
370
- ),
400
+ const properties = authored.flatMap(
401
+ ([property, input]): readonly (readonly [string, unknown, string])[] => {
402
+ if (property !== 'typography')
403
+ return (mappings?.[property] ?? [property]).map(
404
+ (target) => [target, input, property] as const,
405
+ )
406
+
407
+ const parsed = Value.parse(input, 'fontFamily')
408
+ if (parsed && 'invalid' in parsed) {
409
+ report(
410
+ 'invalid_value',
411
+ [name, property],
412
+ 'Importance requires the suffix " !important".',
413
+ )
414
+ return []
415
+ }
416
+
417
+ const path = parsed?.value ?? input
418
+ const entries = Typography.entries(theme, path)
419
+ if (!entries.length) {
420
+ report(
421
+ 'invalid_value',
422
+ [name, property],
423
+ 'Expected a named typography set from the bound theme.',
424
+ )
425
+ return []
426
+ }
427
+
428
+ // Explicit declarations in this block override the corresponding preset fields.
429
+ const explicit = new Set(
430
+ authored.flatMap(([property]) => mappings?.[property] ?? [property]),
431
+ )
432
+ return Typography.entries(theme, path, explicit, parsed?.important).map(
433
+ ([field, value]) => [field, value, property] as const,
434
+ )
435
+ },
371
436
  )
372
437
 
373
438
  if (properties.some(([key]) => Condition.is(key))) {
374
439
  const rules: Rule[] = []
375
440
 
376
- for (const [key, input] of authored) {
441
+ const blocks = authored.flatMap(([key, input]) =>
442
+ key === 'typography'
443
+ ? properties
444
+ .filter(([, , original]) => original === key)
445
+ .map(([property, value]) => [property, value] as const)
446
+ : [[key, input] as const],
447
+ )
448
+
449
+ for (const [key, input] of blocks) {
377
450
  try {
378
451
  const condition = Condition.is(key)
379
452
  ? Query.resolve(
380
453
  key,
381
- options.theme?.[Token.definition].queries ?? {
454
+ theme?.[Token.definition].queries ?? {
382
455
  breakpoints: {},
383
456
  containers: {},
384
457
  containerNames: [],
@@ -535,7 +608,7 @@ export function define(
535
608
  const scalar = parsed ? parsed.value : entry
536
609
 
537
610
  const resolved = (() => {
538
- if (!options.theme) return scalar
611
+ if (!theme) return scalar
539
612
 
540
613
  if (typeof scalar !== 'string' && typeof scalar !== 'number')
541
614
  return scalar
@@ -545,7 +618,7 @@ export function define(
545
618
 
546
619
  const resolved = Token.resolve(scalar, {
547
620
  property: key,
548
- theme: options.theme,
621
+ theme,
549
622
  })
550
623
 
551
624
  if (Token.is(resolved)) {
@@ -559,6 +632,19 @@ export function define(
559
632
  return resolved
560
633
  })()
561
634
 
635
+ if (
636
+ Token.is(resolved) &&
637
+ resolved.contract.variableSet &&
638
+ !Token.acceptsReference(resolved, key)
639
+ ) {
640
+ report(
641
+ 'invalid_value',
642
+ [name, authoredProperty],
643
+ 'Variable value is incompatible with this property.',
644
+ )
645
+ continue
646
+ }
647
+
562
648
  const value = parsed && resolved === '0' ? 0 : resolved
563
649
 
564
650
  declarations.push(
@@ -583,9 +669,48 @@ export function define(
583
669
 
584
670
  if (diagnostics.length) throw new InvalidError(diagnostics)
585
671
 
672
+ const defaultLayer = theme?.[Token.definition].contract.defaultLayer
673
+ // Apply defaults after validation to retain authored diagnostic paths and explicit layer nesting.
674
+ function layered(style: NamedStyle): NamedStyle {
675
+ const { targets, ...body } = style
676
+ const rules = (() => {
677
+ if (style.rules)
678
+ return style.rules.map((rule) =>
679
+ rule.condition === '@layer' || rule.condition?.startsWith('@layer ')
680
+ ? rule
681
+ : Object.freeze({ ...rule, style: layered(rule.style) }),
682
+ )
683
+
684
+ if (!style.declarations.length) return []
685
+
686
+ return [
687
+ Object.freeze({
688
+ condition: `@layer ${defaultLayer}`,
689
+ style: Object.freeze(body),
690
+ }),
691
+ ]
692
+ })()
693
+
694
+ return Object.freeze({
695
+ ...body,
696
+ declarations: style.rules ? style.declarations : Object.freeze([]),
697
+ rules: Object.freeze(rules),
698
+ ...(targets
699
+ ? {
700
+ targets: Object.freeze({
701
+ ...targets,
702
+ ...(targets.web ? { web: layered(targets.web) } : {}),
703
+ }),
704
+ }
705
+ : {}),
706
+ })
707
+ }
708
+
586
709
  // Validated names are precisely the input's enumerable string keys.
587
710
  return Object.freeze({
588
- styles: Object.freeze(output),
711
+ styles: Object.freeze(
712
+ defaultLayer && !options[nesting] ? output.map(layered) : output,
713
+ ),
589
714
  })
590
715
  }
591
716
 
@@ -601,11 +726,11 @@ export declare namespace define {
601
726
  } & ([tokens] extends [never]
602
727
  ? {
603
728
  /** Optional themes do not enable shorthand inference. */
604
- readonly theme?: Theme.Definition | undefined
729
+ readonly vars?: Theme.Definition | Vars.Definition | undefined
605
730
  }
606
731
  : {
607
732
  /** Shorthand inference requires a defined token contract. */
608
- readonly theme: Theme.Definition<tokens>
733
+ readonly vars: Theme.Definition<tokens>
609
734
  })
610
735
  }
611
736
 
@@ -691,7 +816,7 @@ export type DeclarationProperties<tokens extends Theme.Tokens = {}> = {
691
816
  | Value.Atom<Token.Names<tokens, property>>
692
817
  | {
693
818
  [group in Token.Group]: property extends Token.Properties<group>
694
- ? Token.Reference<group>
819
+ ? Value.Atom<Token.Reference<group> | Token.Variable<group>>
695
820
  : never
696
821
  }[Token.Group]
697
822
  >
@@ -707,6 +832,8 @@ export type Properties<
707
832
  readonly targets?:
708
833
  | (targets extends true ? TargetBranches<tokens> : never)
709
834
  | undefined
835
+ /** Applies a named typography set. Explicit fields in the same block take precedence. */
836
+ readonly typography?: Value.Atom<Typography.Names<tokens>>
710
837
  }
711
838
 
712
839
  /** Nested literal declarations retain exact keys at every depth. */
@@ -739,7 +866,7 @@ type WithoutRelationships<value> = value extends readonly unknown[]
739
866
  ? unknown
740
867
  : value extends object
741
868
  ? {
742
- [key in keyof value]: key extends symbol | 'selectors' | 'variables'
869
+ [key in keyof value]: key extends symbol | 'selectors' | 'vars'
743
870
  ? never
744
871
  : key extends keyof Literal.Properties
745
872
  ? unknown
package/src/Vars.ts ADDED
@@ -0,0 +1,299 @@
1
+ /** Defines immutable variable sets and compatible scoped overrides. @module */
2
+ import type * as Typography from './internal/Typography.js'
3
+ import type * as Theme from './internal/Theme.js'
4
+ import * as Identity from './internal/Identity.js'
5
+ import type * as Literal from './internal/Literal.js'
6
+ import * as Token from './internal/Token.js'
7
+ import * as VariableSets from './internal/VariableSets.js'
8
+ import type { style } from './styleFunction.js'
9
+
10
+ /** Portable scalar reference with its accepted value domain. */
11
+ export type Reference<group extends Token.Group = Token.Group> =
12
+ Token.Reference<group>
13
+
14
+ const shape = Symbol('zyzz.variables.shape')
15
+
16
+ /** A scalar, a color-scheme pair, or ordered media overrides with a required default. */
17
+ export type Value =
18
+ | string
19
+ | number
20
+ | Token.Reference
21
+ | {
22
+ readonly light: string | Token.Reference
23
+ readonly dark: string | Token.Reference
24
+ }
25
+ | ({ readonly default: Value } & {
26
+ readonly [query: `@media ${string}`]: Value
27
+ })
28
+
29
+ /** Nested categories and variable paths. */
30
+ export type Values = {
31
+ readonly [key: string]: Value | Values | readonly string[]
32
+ }
33
+
34
+ /** Immutable references retaining their shared set contract. */
35
+ export type Definition<values extends Values = Values> = (Values extends values
36
+ ? {}
37
+ : References<values>) & {
38
+ /** Authored value shape retained for inference. */
39
+ readonly [shape]: values
40
+ /** Compiler-owned identity and values. */
41
+ readonly [Token.definition]: Token.Metadata
42
+ }
43
+
44
+ /** Reference tree preserving the domain of each scalar leaf. */
45
+ export type References<values, root extends boolean = true> = {
46
+ readonly [key in Exclude<
47
+ keyof values,
48
+ root extends true ? 'breakpoints' | 'containers' | 'containerNames' : never
49
+ >]: values[key] extends Value
50
+ ? Token.Reference<Domain<Scalar<values[key]>>> & {
51
+ readonly [Token.scalar]: Scalar<values[key]>
52
+ }
53
+ : References<values[key], false>
54
+ }
55
+
56
+ /** Resolves the scalar types represented by all conditional branches. */
57
+ export type Scalar<value> = Value extends value
58
+ ? string | number
59
+ : value extends { readonly [Token.scalar]: infer scalar }
60
+ ? scalar
61
+ : value extends readonly string[]
62
+ ? value
63
+ : value extends Token.Reference<infer group>
64
+ ? group extends 'color'
65
+ ? Literal.Color
66
+ : group extends 'spacing'
67
+ ? Literal.Length
68
+ : group extends 'number'
69
+ ? number
70
+ : string
71
+ : value extends { default: unknown }
72
+ ? Scalar<value[keyof value]>
73
+ : value extends { light: infer light; dark: infer dark }
74
+ ? Scalar<light | dark>
75
+ : value
76
+
77
+ /** Scalar domain shared by compatible set alternatives. */
78
+ export type Domain<value> = [value] extends [Literal.Color]
79
+ ? 'color'
80
+ : [value] extends [Literal.Length]
81
+ ? 'spacing'
82
+ : [value] extends [number]
83
+ ? 'number'
84
+ : 'string'
85
+
86
+ /** Creates typed references without emitting CSS or reading the environment. */
87
+ export function define<const values extends Values>(
88
+ values: values & NoInfer<Validated<values, false, true>>,
89
+ options?: style.DefinitionOptions,
90
+ ): Definition<values>
91
+ /** Deeply merges derived leaves, rejecting duplicate paths and leaf/category conflicts. */
92
+ export function define<
93
+ const values extends Values,
94
+ const derived extends Values,
95
+ >(
96
+ values: values & NoInfer<Validated<values, false, true>>,
97
+ derive: ((vars: References<values>) => derived) &
98
+ NoInfer<(vars: References<values>) => Validated<derived, false, true>>,
99
+ options?: style.DefinitionOptions,
100
+ ): Definition<Merge<values, derived>>
101
+ export function define(
102
+ values: Values,
103
+ derive: style.DefinitionOptions | ((vars: References<Values>) => Values) = {},
104
+ options: style.DefinitionOptions = {},
105
+ ): Definition {
106
+ if (typeof derive !== 'function') options = derive
107
+
108
+ const contract = Object.freeze({
109
+ variableSet: true,
110
+ ...(options.id === undefined
111
+ ? {}
112
+ : {
113
+ [Token.identity]: Identity.requireId(options.id, 'Vars.define'),
114
+ [Token.complete]: true,
115
+ }),
116
+ })
117
+ const base = VariableSets.build(values, contract)
118
+ if (typeof derive !== 'function') return base
119
+
120
+ const merged = VariableSets.merge(values, derive(base as References<Values>))
121
+ return VariableSets.build(merged, contract)
122
+ }
123
+
124
+ type Merge<base, derived> = {
125
+ readonly [key in keyof base | keyof derived]: key extends keyof derived
126
+ ? key extends keyof base
127
+ ? Merge<base[key], derived[key]>
128
+ : derived[key]
129
+ : key extends keyof base
130
+ ? base[key]
131
+ : never
132
+ }
133
+
134
+ /** Replaces existing leaves while preserving paths, domains, and reference identity. */
135
+ export function extend<const values extends Values>(
136
+ variables: Definition<values>,
137
+ overrides: Overrides<values>,
138
+ ): Definition<values> {
139
+ const metadata = Object.getOwnPropertyDescriptor(variables, Token.definition)
140
+ ?.value as Token.Metadata | undefined
141
+ if (!metadata?.contract.variableSet)
142
+ throw new InvalidError([], 'Expected a variable set.')
143
+ return VariableSets.build(
144
+ overrides,
145
+ metadata.contract,
146
+ metadata.values,
147
+ metadata.queries,
148
+ metadata.paths,
149
+ ) as Definition<values>
150
+ }
151
+
152
+ /** Partial compatible overrides. Conditional leaves are replaced in full. */
153
+ export type Overrides<values> = {
154
+ readonly [key in keyof values]?: values[key] extends Value
155
+ ? Conditional<Compatible<Scalar<values[key]>>>
156
+ : Overrides<values[key]>
157
+ }
158
+
159
+ type Conditional<scalar> =
160
+ | scalar
161
+ | {
162
+ readonly default: Conditional<scalar>
163
+ readonly [query: `@media ${string}`]: Conditional<scalar>
164
+ }
165
+ type Compatible<scalar> = [scalar] extends [Literal.Color]
166
+ ?
167
+ | Literal.Color
168
+ | Token.Reference<'color'>
169
+ | {
170
+ readonly light: Literal.Color | Token.Reference<'color'>
171
+ readonly dark: Literal.Color | Token.Reference<'color'>
172
+ }
173
+ : [scalar] extends [Literal.Length]
174
+ ? Literal.Length | Token.Reference<'spacing'>
175
+ : [scalar] extends [number]
176
+ ? number | Token.Reference<'number'>
177
+ : string | Token.Reference<'string'>
178
+
179
+ /** Category names mapped to the CSS properties that accept their shorthand tokens. */
180
+ export type Mappings = Readonly<
181
+ Record<string, readonly (keyof Literal.Properties)[]>
182
+ >
183
+
184
+ /** Type carrier for configured shorthand lookup. */
185
+ export type Mapped<values, mappings> = (Pick<
186
+ values,
187
+ keyof values &
188
+ ('breakpoints' | 'containers' | 'containerNames' | 'typography')
189
+ > extends infer metadata extends Theme.Tokens
190
+ ? metadata
191
+ : {}) & {
192
+ readonly color?: undefined
193
+ readonly '~vars': {
194
+ readonly values: values
195
+ readonly mappings: mappings
196
+ }
197
+ }
198
+
199
+ /** Reads the values declared by a reusable definition or inline set. */
200
+ export type Extract<input> = input extends { readonly [shape]: infer values }
201
+ ? values
202
+ : input
203
+
204
+ /** Invalid variable data with the offending path. */
205
+ export class InvalidError extends Error {
206
+ /** Creates a diagnostic for invalid data at the supplied path. */
207
+ constructor(
208
+ readonly path: readonly string[],
209
+ message: string,
210
+ ) {
211
+ super(`${JSON.stringify(path)}: ${message}`)
212
+ }
213
+ /** Stable diagnostic name. */
214
+ override name = 'Vars.InvalidError'
215
+ }
216
+
217
+ type Validated<
218
+ value,
219
+ typography extends boolean = false,
220
+ root extends boolean = false,
221
+ > = Values extends value
222
+ ? value
223
+ : value extends readonly string[]
224
+ ? never
225
+ : value extends Token.Reference
226
+ ? value
227
+ : value extends string | number
228
+ ? Literal.Checked<value>
229
+ : root extends true
230
+ ? {
231
+ readonly [key in keyof value]: key extends 'containerNames'
232
+ ? value[key] extends readonly string[]
233
+ ? value[key]
234
+ : never
235
+ : key extends
236
+ | `${string}.${string}`
237
+ | `${string}!${string}`
238
+ | `@${string}`
239
+ | ''
240
+ ? never
241
+ : Validated<
242
+ value[key],
243
+ key extends 'typography' ? true : false
244
+ >
245
+ }
246
+ : value extends { default: infer base }
247
+ ? Conditional<Compatible<Scalar<base>>> &
248
+ Record<
249
+ Exclude<keyof value, 'default' | `@media ${string}`>,
250
+ never
251
+ >
252
+ : value extends { light: unknown; dark: unknown }
253
+ ? Pair<value>
254
+ : keyof value extends 'light' | 'dark'
255
+ ? Pair<value>
256
+ : {
257
+ readonly [key in keyof value]: key extends
258
+ | `${string}.${string}`
259
+ | `${string}!${string}`
260
+ | `@${string}`
261
+ | ''
262
+ ? typography extends true
263
+ ? key extends Typography.Condition
264
+ ? Validated<value[key], true>
265
+ : never
266
+ : never
267
+ : Validated<
268
+ value[key],
269
+ key extends 'typography' ? true : typography
270
+ >
271
+ }
272
+
273
+ /** Applies a compatible variable set and optional color scheme to a scope. */
274
+ export type Selector<
275
+ name extends string,
276
+ output extends style.Output = 'react',
277
+ > = {
278
+ <
279
+ const selection extends {
280
+ readonly set?: name | undefined
281
+ readonly colorScheme?: 'light' | 'dark' | 'light dark' | undefined
282
+ } = {},
283
+ >(
284
+ options?: selection &
285
+ Record<Exclude<keyof selection, 'set' | 'colorScheme'>, never>,
286
+ ): style.Props<output>
287
+ }
288
+
289
+ type Pair<value> = {
290
+ readonly light: Literal.Color | Token.Reference<'color'>
291
+ readonly dark: Literal.Color | Token.Reference<'color'>
292
+ } & Record<Exclude<keyof value, 'light' | 'dark'>, never>
293
+
294
+ /** Configured references and a selector for compatible scopes. */
295
+ export type Bound<
296
+ values extends Values,
297
+ name extends string = never,
298
+ output extends style.Output = 'react',
299
+ > = Definition<values> & Selector<name, output>