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
@@ -3,14 +3,16 @@
3
3
  * @module
4
4
  */
5
5
  import type * as Binding from '../../internal/Binding.js'
6
- import * as Config from '../../Config.js'
6
+ import * as Config from '../../internal/Configuration.js'
7
7
  import * as Configurations from './Configurations.js'
8
8
  import * as FunctionSyntax from '../../internal/FunctionSyntax.js'
9
9
  import * as Identifiers from './Identifiers.js'
10
10
  import * as PackedStyles from './PackedStyles.js'
11
11
  import * as Shorthands from '../../internal/Shorthands.js'
12
12
  import * as Stylesheets from './Stylesheets.js'
13
- import * as Theme from '../../Theme.js'
13
+ import * as Theme from '../../internal/Theme.js'
14
+ import * as VariableSets from '../../internal/VariableSets.js'
15
+ import * as Vars from '../../Vars.js'
14
16
  import type * as Themes from './Themes.js'
15
17
  import * as Token from '../../internal/Token.js'
16
18
 
@@ -24,7 +26,7 @@ export function read(
24
26
  if (
25
27
  ![
26
28
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
27
- 22, 23,
29
+ 22, 23, 24, 25, 26, 27,
28
30
  ].includes(data.version as number)
29
31
  )
30
32
  throw new Error('Unsupported Zyzz contract version.')
@@ -56,12 +58,53 @@ export function read(
56
58
  for (const entry of Object.values(record(data.exports))) collect(entry)
57
59
  }
58
60
 
61
+ function decode(value: unknown): unknown {
62
+ if (!value || typeof value !== 'object') return value
63
+ if (Array.isArray(value)) return value.map(decode)
64
+ const fields = record(value)
65
+ if (Object.hasOwn(fields, '$object'))
66
+ return Object.fromEntries(
67
+ Object.entries(record(fields.$object)).map(([key, value]) => [
68
+ key,
69
+ decode(value),
70
+ ]),
71
+ )
72
+ if (Object.hasOwn(fields, '$variable')) {
73
+ const reference = record(fields.$variable)
74
+ const identity = string(reference.identity)
75
+ let contract = identities.get(identity)
76
+ if (contract && !contract.variableSet)
77
+ throw new Error(
78
+ 'Conflicting packed variable-set modes for one identity.',
79
+ )
80
+ if (!contract) {
81
+ contract = Object.freeze({
82
+ variableSet: true,
83
+ [Token.identity]: identity,
84
+ })
85
+ identities.set(identity, contract)
86
+ }
87
+ const resolved = decode(reference.value) as Token.Value
88
+ return Token.create({
89
+ contract,
90
+ group: VariableSets.domain(resolved),
91
+ path: string(reference.path),
92
+ value: resolved,
93
+ })
94
+ }
95
+ return Object.fromEntries(
96
+ Object.entries(fields).map(([key, value]) => [key, decode(value)]),
97
+ )
98
+ }
59
99
  const themes: Record<string, Theme.Definition> = Object.create(null)
60
100
  const types: Record<string, string> = Object.create(null)
61
101
 
62
102
  for (const [name, value] of Object.entries(record(data.themes))) {
63
103
  const entry = record(value)
64
104
  const identity = string(entry.identity)
105
+ if (entry.variableSet === true && (data.version as number) < 26)
106
+ throw new Error('Vars contracts require contract version 26 or later.')
107
+ const mappings = VariableSets.mappings(entry.mappings)
65
108
  if (
66
109
  entry.cssOutput !== undefined &&
67
110
  entry.cssOutput !== 'atomic' &&
@@ -73,11 +116,28 @@ export function read(
73
116
  | 'grouped'
74
117
  | undefined
75
118
 
119
+ if (entry.defaultLayer !== undefined) {
120
+ if ((data.version as number) < 27)
121
+ throw new Error('Default layers require contract version 27 or later.')
122
+ Config.create({ defaultLayer: entry.defaultLayer as string })
123
+ }
124
+ const defaultLayer = entry.defaultLayer as string | undefined
125
+
76
126
  const shorthands =
77
127
  entry.shorthands !== undefined
78
128
  ? Shorthands.read(entry.shorthands)
79
129
  : undefined
80
130
  let contract = identities.get(identity)
131
+ if (
132
+ contract &&
133
+ Boolean(contract.variableSet) !== (entry.variableSet === true)
134
+ )
135
+ throw new Error('Conflicting packed variable-set modes for one identity.')
136
+ if (
137
+ contract &&
138
+ JSON.stringify(contract.mappings ?? {}) !== JSON.stringify(mappings ?? {})
139
+ )
140
+ throw new Error('Conflicting packed variable mappings for one identity.')
81
141
  if (
82
142
  contract &&
83
143
  Shorthands.signature(contract.shorthands) !==
@@ -95,19 +155,53 @@ export function read(
95
155
  'Conflicting packed CSS output modes for one theme identity.',
96
156
  )
97
157
 
158
+ if (contract && contract.defaultLayer !== defaultLayer)
159
+ throw new Error(
160
+ 'Conflicting packed default layers for one theme identity.',
161
+ )
162
+
98
163
  if (!contract) {
99
164
  contract = Object.freeze({
165
+ ...(entry.variableSet === true
166
+ ? {
167
+ variableSet: true,
168
+ mappings,
169
+ }
170
+ : {}),
100
171
  ...(entry.shorthands !== undefined
101
172
  ? { shorthands: Shorthands.read(entry.shorthands) }
102
173
  : {}),
103
174
  ...(cssOutput ? { cssOutput } : {}),
175
+ ...(defaultLayer !== undefined ? { defaultLayer } : {}),
104
176
  [Token.complete]: true,
105
177
  [Token.identity]: identity,
106
178
  })
107
179
  identities.set(identity, contract)
108
180
  }
109
181
 
110
- const definition = Theme.define(record(entry.tokens) as Theme.Tokens)
182
+ const definition =
183
+ entry.variableSet === true
184
+ ? VariableSets.theme(
185
+ Vars.define(decode(entry.tokens) as Vars.Values),
186
+ mappings,
187
+ )
188
+ : Theme.define(record(entry.tokens) as Theme.Tokens)
189
+ if (
190
+ (data.version as number) < 24 &&
191
+ Object.hasOwn(definition.tokens, 'typography')
192
+ )
193
+ throw new Error(
194
+ 'Packed typography sets require contract version 24 or later.',
195
+ )
196
+
197
+ if (
198
+ (data.version as number) < 25 &&
199
+ (definition[Token.definition].paths ||
200
+ Object.hasOwn(definition.tokens, 'borderWidth'))
201
+ )
202
+ throw new Error(
203
+ 'Packed responsive typography and border widths require contract version 25 or later.',
204
+ )
111
205
 
112
206
  themes[name] = Token.bind(definition, contract)
113
207
  types[name] = type(input(definition))
@@ -198,9 +292,10 @@ export function read(
198
292
  const name = string(entry.name)
199
293
  const reference = string(entry.reference)
200
294
  if (
201
- ![9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].includes(
202
- data.version as number,
203
- ) ||
295
+ ![
296
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
297
+ 27,
298
+ ].includes(data.version as number) ||
204
299
  ![
205
300
  'cssFunction',
206
301
  'customMedia',
@@ -247,10 +342,7 @@ export function read(
247
342
  }
248
343
 
249
344
  if (entry.kind === 'style-reference') {
250
- if (
251
- entry.style !== undefined &&
252
- ![16, 17, 18, 19, 20, 21, 22, 23].includes(data.version as number)
253
- )
345
+ if (entry.style !== undefined && (data.version as number) < 16)
254
346
  throw new Error(
255
347
  'Packed callable styles require contract version 16 or later.',
256
348
  )
@@ -324,10 +416,17 @@ export function read(
324
416
  : undefined
325
417
 
326
418
  const options =
327
- entry.options === undefined ? undefined : record(entry.options)
419
+ entry.options === undefined ? undefined : record(decode(entry.options))
328
420
 
329
421
  if (options) {
330
- Config.create(options as Config.create.Options)
422
+ if (entry.variableConfig === true)
423
+ Config.create(
424
+ variableOptions(
425
+ options,
426
+ entry.variableMappings as Vars.Mappings | false | undefined,
427
+ ),
428
+ )
429
+ else Config.create(options as Config.create.Options)
331
430
  if (
332
431
  (data.version as number) >= 17 &&
333
432
  (options.cssOutput ?? 'atomic') !==
@@ -337,6 +436,14 @@ export function read(
337
436
  'Configuration CSS output disagrees with linked theme metadata.',
338
437
  )
339
438
 
439
+ if (
440
+ options.defaultLayer !==
441
+ definition[Token.definition].contract.defaultLayer
442
+ )
443
+ throw new Error(
444
+ 'Configuration default layer disagrees with linked theme metadata.',
445
+ )
446
+
340
447
  if (
341
448
  Shorthands.signature(options.shorthands) !==
342
449
  Shorthands.signature(definition[Token.definition].contract.shorthands)
@@ -350,7 +457,9 @@ export function read(
350
457
  !!options?.themes &&
351
458
  ((data.version as number) < 4 || entry.catalogOnly === true)
352
459
  const fullConfigType = options
353
- ? `import('zyzz').Config.create.ReturnType<${Configurations.type(options)}>`
460
+ ? entry.variableConfig === true
461
+ ? `import('zyzz').Config.VariableConfig<${Configurations.type(variableOptions(options, entry.variableMappings as Vars.Mappings | false | undefined))}>`
462
+ : `import('zyzz').Config.create.ReturnType<${Configurations.type(options)}>`
354
463
  : ''
355
464
  // Helpers a legacy library did not compile are hidden from its consumers' types.
356
465
  const hidden = [
@@ -369,6 +478,27 @@ export function read(
369
478
  return {
370
479
  binding: string(entry.binding),
371
480
  call: {
481
+ ...(entry.variableSet === true
482
+ ? {
483
+ variableSet: true,
484
+ type: `import('zyzz').Vars.Definition<${types[theme]!}>`,
485
+ }
486
+ : {}),
487
+ ...(entry.directVariables === true
488
+ ? {
489
+ directVariables: true,
490
+ type: `import('zyzz').Vars.${entry.variableSet === true ? 'Definition' : 'References'}<${types[theme]!}>`,
491
+ }
492
+ : {}),
493
+ ...(entry.variableConfig === true
494
+ ? {
495
+ variableConfig: true,
496
+ variableMappings: entry.variableMappings as
497
+ | Vars.Mappings
498
+ | false
499
+ | undefined,
500
+ }
501
+ : {}),
372
502
  ...(entry.recipe === true ? { recipe: true } : {}),
373
503
  ...(entry.output === 'html' ? { output: 'html' as const } : {}),
374
504
  ...(catalogOnly ? { catalogOnly: true } : {}),
@@ -392,7 +522,7 @@ export function read(
392
522
  ...(options
393
523
  ? {
394
524
  options,
395
- type: `${outputType}${entry.initialization === true ? "['script']" : entry.root === true ? "['appearance']" : entry.selection === true ? "['themes']" : ''}`,
525
+ type: `${outputType}${entry.initialization === true ? "['script']" : entry.root === true ? "['appearance']" : entry.selection === true ? (entry.variableConfig === true ? "['vars']" : "['themes']") : ''}`,
396
526
  }
397
527
  : {}),
398
528
  ...(members
@@ -452,6 +582,7 @@ function tokens(tree: Theme.References<Theme.Tokens>): Record<string, unknown> {
452
582
  }
453
583
 
454
584
  function type(value: unknown): string {
585
+ if (Token.is(value)) return Configurations.type(value)
455
586
  if (Array.isArray(value)) return `readonly [${value.map(type).join(',')}]`
456
587
  if (!value || typeof value !== 'object') return JSON.stringify(value)
457
588
 
@@ -518,6 +649,11 @@ export function write(
518
649
  }
519
650
 
520
651
  return {
652
+ ...(link.call.variableSet ? { variableSet: true } : {}),
653
+ ...(link.call.directVariables ? { directVariables: true } : {}),
654
+ ...(link.call.variableConfig
655
+ ? { variableConfig: true, variableMappings: link.call.variableMappings }
656
+ : {}),
521
657
  ...(link.call.recipe ? { recipe: true } : {}),
522
658
  ...(link.call.output ? { output: link.call.output } : {}),
523
659
  ...(link.call.script &&
@@ -534,7 +670,7 @@ export function write(
534
670
  ...(link.call.selection ? { selection: true } : {}),
535
671
  ...(link.call.initialization ? { initialization: true } : {}),
536
672
  ...(link.call.root ? { root: true } : {}),
537
- ...(link.call.options ? { options: link.call.options } : {}),
673
+ ...(link.call.options ? { options: encode(link.call.options) } : {}),
538
674
  ...(link.members
539
675
  ? {
540
676
  members: Object.fromEntries(
@@ -565,15 +701,53 @@ export function write(
565
701
  ...(theme[Token.definition].contract.shorthands
566
702
  ? { shorthands: theme[Token.definition].contract.shorthands }
567
703
  : {}),
704
+ ...(theme[Token.definition].contract.defaultLayer !== undefined
705
+ ? { defaultLayer: theme[Token.definition].contract.defaultLayer }
706
+ : {}),
568
707
  ...(theme[Token.definition].contract.cssOutput
569
708
  ? { cssOutput: theme[Token.definition].contract.cssOutput }
570
709
  : {}),
710
+ ...(theme[Token.definition].contract.variableSet
711
+ ? {
712
+ variableSet: true,
713
+ mappings: theme[Token.definition].contract.mappings,
714
+ }
715
+ : {}),
571
716
  identity: theme[Token.definition].contract[Token.identity],
572
- tokens: input(theme),
717
+ tokens: encode(input(theme)),
573
718
  },
574
719
  ]),
575
720
  ),
576
721
  version: (() => {
722
+ if (
723
+ Object.values(themes).some(
724
+ (theme) =>
725
+ theme[Token.definition].contract.defaultLayer !== undefined,
726
+ )
727
+ )
728
+ return 27
729
+ if (
730
+ Object.values(themes).some(
731
+ (theme) => theme[Token.definition].contract.variableSet,
732
+ )
733
+ )
734
+ return 26
735
+ if (
736
+ Object.values(themes).some(
737
+ (theme) =>
738
+ theme[Token.definition].paths ||
739
+ Object.hasOwn(theme.tokens, 'borderWidth'),
740
+ )
741
+ )
742
+ return 25
743
+
744
+ if (
745
+ Object.values(themes).some((theme) =>
746
+ Object.hasOwn(theme.tokens, 'typography'),
747
+ )
748
+ )
749
+ return 24
750
+
577
751
  function callable(link: Themes.Link): boolean {
578
752
  return !!link.style || Object.values(link.members ?? {}).some(callable)
579
753
  }
@@ -844,3 +1018,35 @@ function extended(signature: NonNullable<Themes.Call['function']>): boolean {
844
1018
  )
845
1019
  )
846
1020
  }
1021
+
1022
+ function encode(value: unknown): unknown {
1023
+ if (Token.is(value))
1024
+ return {
1025
+ $variable: {
1026
+ identity: value.contract[Token.identity],
1027
+ path: value.path,
1028
+ value: encode(value.value),
1029
+ },
1030
+ }
1031
+ if (Array.isArray(value)) return value.map(encode)
1032
+ if (!value || typeof value !== 'object') return value
1033
+ const fields = Object.fromEntries(
1034
+ Object.entries(value).map(([key, value]) => [key, encode(value)]),
1035
+ )
1036
+ return Object.hasOwn(fields, '$variable') || Object.hasOwn(fields, '$object')
1037
+ ? { $object: fields }
1038
+ : fields
1039
+ }
1040
+
1041
+ function variableOptions(
1042
+ options: Record<string, unknown>,
1043
+ mappings?: Vars.Mappings | false,
1044
+ ): Config.VariableOptions {
1045
+ const { theme, themes, defaultTheme, ...rest } = options
1046
+ return {
1047
+ ...rest,
1048
+ vars: (themes ?? theme) as Vars.Values,
1049
+ ...(themes ? { defaultVars: String(defaultTheme) } : {}),
1050
+ ...(mappings !== undefined ? { mappings } : {}),
1051
+ }
1052
+ }
@@ -18,7 +18,7 @@ import * as Properties from './Properties.js'
18
18
  import * as RuleReference from '../../internal/RuleReference.js'
19
19
  import type * as Scope from './Scope.js'
20
20
  import * as Style from '../../Style.js'
21
- import * as Theme from '../../Theme.js'
21
+ import * as Theme from '../../internal/Theme.js'
22
22
  import * as Themes from './Themes.js'
23
23
  import type * as Token from '../../internal/Token.js'
24
24
  import * as Walker from 'oxc-walker'
@@ -64,7 +64,7 @@ export function read(
64
64
  'key',
65
65
  'ref',
66
66
  'style',
67
- 'variables',
67
+ 'vars',
68
68
  '__proto__',
69
69
  ].includes(key) ||
70
70
  Object.hasOwn(slots, key)
@@ -4,7 +4,33 @@
4
4
  */
5
5
  import type * as Ast from '@oxc-project/types'
6
6
  import * as Binding from '../../internal/Binding.js'
7
+ import * as Literal from '../../internal/Literal.js'
7
8
  import * as Token from '../../internal/Token.js'
9
+ import * as Tree from 'css-tree'
10
+
11
+ /** Checks color substitutions inside compound CSS values without widening direct reference domains. */
12
+ export function acceptsColor(
13
+ expression: Token.Expression,
14
+ property: keyof Literal.Properties,
15
+ ): boolean {
16
+ const value = expression.parts
17
+ .map((part) => {
18
+ if (typeof part === 'string') return part
19
+ if (Binding.is(part) ? part.type === 'color' : part.group === 'color')
20
+ return 'rgb(1 2 3)'
21
+ return 'var(--zyzz-reference)'
22
+ })
23
+ .join('')
24
+ .replace(/ !important$/, '')
25
+
26
+ try {
27
+ return (
28
+ Tree.lexer.matchProperty(Literal.name(property), value).error === null
29
+ )
30
+ } catch {
31
+ return false
32
+ }
33
+ }
8
34
 
9
35
  /** Folds cooked template text and literal primitive substitutions; unresolved syntax returns undefined. */
10
36
  export function template(
@@ -99,8 +99,9 @@ export function read(value: string): string | undefined {
99
99
  /** Reads an explicit authoring identity shared with uncompiled execution. */
100
100
  export function explicit(
101
101
  call: import('@oxc-project/types').CallExpression,
102
+ index = 1,
102
103
  ): string | undefined {
103
- const argument = call.arguments[1]
104
+ const argument = call.arguments[index]
104
105
  if (!argument) return undefined
105
106
  if (argument.type !== 'ObjectExpression' || argument.properties.length !== 1)
106
107
  throw new Error('Definition options require one literal id.')
@@ -19,13 +19,13 @@ export function compile(
19
19
  return {
20
20
  ...prepared,
21
21
  styles: StyleSheet.select(prepared.styles, {
22
- theme: options.theme ?? 'default',
22
+ set: options.set ?? 'default',
23
23
  colorScheme: options.colorScheme,
24
24
  }),
25
25
  }
26
26
  }
27
27
 
28
- /** Prepares immutable programs and all theme/scheme tables before selection. */
28
+ /** Prepares immutable programs and all set/scheme tables before selection. */
29
29
  export function prepare(
30
30
  recipe: Recipe.Definition,
31
31
  call: Pick<Source.Call, 'slots' | 'recipe'>,
@@ -131,7 +131,7 @@ export function prepare(
131
131
  styles: { styles: fragments },
132
132
  fonts: options.fonts,
133
133
  platform: options.platform,
134
- themes: options.themes,
134
+ vars: options.vars,
135
135
  units: options.units,
136
136
  })
137
137
  return {
@@ -8,7 +8,7 @@ import * as ConditionalRecipe from '../../runtime/ConditionalRecipe.js'
8
8
  import * as Literal from '../../internal/Literal.js'
9
9
  import type * as Source from '../Source.js'
10
10
  import type * as Style from '../../Style.js'
11
- import type * as Theme from '../../Theme.js'
11
+ import type * as Theme from '../../internal/Theme.js'
12
12
  import * as Token from '../../internal/Token.js'
13
13
 
14
14
  /** Portable composition inputs; selection behavior remains in the compiled callable. */
@@ -94,11 +94,10 @@ export function read(
94
94
  )
95
95
  // Catalog themes share identities and paths but retain distinct fallback values.
96
96
  tokens.set(
97
- JSON.stringify([
98
- value.contract[Token.identity],
99
- value.path,
100
- value.value,
101
- ]),
97
+ JSON.stringify(
98
+ [value.contract[Token.identity], value.path, value.value],
99
+ encode,
100
+ ),
102
101
  value,
103
102
  )
104
103
  return
@@ -320,14 +319,9 @@ export function read(
320
319
  const name = string(value)
321
320
  if (
322
321
  !field ||
323
- [
324
- '__proto__',
325
- 'style',
326
- 'className',
327
- 'variables',
328
- 'key',
329
- 'ref',
330
- ].includes(field) ||
322
+ ['__proto__', 'style', 'className', 'vars', 'key', 'ref'].includes(
323
+ field,
324
+ ) ||
331
325
  !slots.includes(name)
332
326
  )
333
327
  throw new Error('Invalid packed dynamic slot.')
@@ -430,22 +424,24 @@ export function write(definition: Definition): unknown {
430
424
  cssOutput: definition.style.cssOutput ?? 'atomic',
431
425
  },
432
426
  },
433
- (_, value: unknown) => {
434
- if (Token.is(value))
435
- return {
436
- identity: value.contract[Token.identity],
437
- kind: 'token',
438
- path: value.path,
439
- value: value.value,
440
- }
441
- if (Token.isExpression(value))
442
- return { kind: 'expression', parts: value.parts }
443
- return value
444
- },
427
+ encode,
445
428
  ),
446
429
  )
447
430
  }
448
431
 
432
+ function encode(_: string, value: unknown): unknown {
433
+ if (Token.is(value))
434
+ return {
435
+ identity: value.contract[Token.identity],
436
+ kind: 'token',
437
+ path: value.path,
438
+ value: value.value,
439
+ }
440
+ if (Token.isExpression(value))
441
+ return { kind: 'expression', parts: value.parts }
442
+ return value
443
+ }
444
+
449
445
  function array(value: unknown): unknown[] {
450
446
  if (!Array.isArray(value)) throw new Error('Expected a packed style array.')
451
447
  return value
@@ -194,7 +194,7 @@ export function expand(
194
194
  'key',
195
195
  'ref',
196
196
  'style',
197
- 'variables',
197
+ 'vars',
198
198
  ].includes(axis)
199
199
  )
200
200
  throw new Themes.InvalidError(
@@ -2,7 +2,7 @@
2
2
  import type * as Ast from '@oxc-project/types'
3
3
  import * as Walker from 'oxc-walker'
4
4
  import * as Condition from '../../internal/Condition.js'
5
- import * as Theme from '../../Theme.js'
5
+ import * as Theme from '../../internal/Theme.js'
6
6
  import * as AtRules from './AtRules.js'
7
7
  import * as Identity from '../../internal/Identity.js'
8
8
  import * as Identifiers from './Identifiers.js'