zyzz 0.0.3 → 0.0.6

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 (273) 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 +15 -12
  7. package/dist/Style.d.ts.map +1 -1
  8. package/dist/Style.js +51 -26
  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/babel/index.d.ts +2 -0
  15. package/dist/babel/index.d.ts.map +1 -1
  16. package/dist/babel/index.js +10 -1
  17. package/dist/babel/index.js.map +1 -1
  18. package/dist/compiler/Graph.d.ts +2 -0
  19. package/dist/compiler/Graph.d.ts.map +1 -1
  20. package/dist/compiler/Graph.js +30 -9
  21. package/dist/compiler/Graph.js.map +1 -1
  22. package/dist/compiler/Native.d.ts +5 -5
  23. package/dist/compiler/Native.d.ts.map +1 -1
  24. package/dist/compiler/Native.js +21 -21
  25. package/dist/compiler/Native.js.map +1 -1
  26. package/dist/compiler/Source.d.ts +8 -6
  27. package/dist/compiler/Source.d.ts.map +1 -1
  28. package/dist/compiler/Source.js +52 -16
  29. package/dist/compiler/Source.js.map +1 -1
  30. package/dist/compiler/Transform.d.ts +1 -1
  31. package/dist/compiler/Transform.d.ts.map +1 -1
  32. package/dist/compiler/Transform.js +58 -22
  33. package/dist/compiler/Transform.js.map +1 -1
  34. package/dist/compiler/internal/Compositions.d.ts +5 -0
  35. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  36. package/dist/compiler/internal/Compositions.js +22 -3
  37. package/dist/compiler/internal/Compositions.js.map +1 -1
  38. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  39. package/dist/compiler/internal/Configurations.js +73 -12
  40. package/dist/compiler/internal/Configurations.js.map +1 -1
  41. package/dist/compiler/internal/Contract.d.ts +1 -1
  42. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  43. package/dist/compiler/internal/Contract.js +155 -13
  44. package/dist/compiler/internal/Contract.js.map +1 -1
  45. package/dist/compiler/internal/Contributions.d.ts +1 -1
  46. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  47. package/dist/compiler/internal/Contributions.js +6 -4
  48. package/dist/compiler/internal/Contributions.js.map +1 -1
  49. package/dist/compiler/internal/Dynamic.js +1 -1
  50. package/dist/compiler/internal/Dynamic.js.map +1 -1
  51. package/dist/compiler/internal/Expression.d.ts +3 -0
  52. package/dist/compiler/internal/Expression.d.ts.map +1 -1
  53. package/dist/compiler/internal/Expression.js +21 -0
  54. package/dist/compiler/internal/Expression.js.map +1 -1
  55. package/dist/compiler/internal/Identifiers.d.ts +1 -1
  56. package/dist/compiler/internal/Identifiers.d.ts.map +1 -1
  57. package/dist/compiler/internal/Identifiers.js +2 -2
  58. package/dist/compiler/internal/Identifiers.js.map +1 -1
  59. package/dist/compiler/internal/NativeBindings.d.ts +1 -1
  60. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  61. package/dist/compiler/internal/NativeBindings.js +3 -3
  62. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  63. package/dist/compiler/internal/PackedStyles.d.ts +1 -1
  64. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  65. package/dist/compiler/internal/PackedStyles.js +15 -25
  66. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  67. package/dist/compiler/internal/Recipes.js +1 -1
  68. package/dist/compiler/internal/Recipes.js.map +1 -1
  69. package/dist/compiler/internal/Selectors.js +1 -1
  70. package/dist/compiler/internal/Selectors.js.map +1 -1
  71. package/dist/compiler/internal/Static.d.ts.map +1 -1
  72. package/dist/compiler/internal/Static.js +2 -0
  73. package/dist/compiler/internal/Static.js.map +1 -1
  74. package/dist/compiler/internal/Themes.d.ts +12 -3
  75. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  76. package/dist/compiler/internal/Themes.js +192 -52
  77. package/dist/compiler/internal/Themes.js.map +1 -1
  78. package/dist/compiler/internal/{Variables.d.ts → Vars.d.ts} +1 -1
  79. package/dist/compiler/internal/Vars.d.ts.map +1 -0
  80. package/dist/compiler/internal/{Variables.js → Vars.js} +3 -3
  81. package/dist/compiler/internal/Vars.js.map +1 -0
  82. package/dist/default.d.ts +147 -2562
  83. package/dist/default.d.ts.map +1 -1
  84. package/dist/default.js +85 -80
  85. package/dist/default.js.map +2 -2
  86. package/dist/default.js.zyzz.json +1 -1
  87. package/dist/esbuild/index.d.ts +3 -0
  88. package/dist/esbuild/index.d.ts.map +1 -0
  89. package/dist/esbuild/index.js +5 -0
  90. package/dist/esbuild/index.js.map +1 -0
  91. package/dist/index.d.ts +4 -4
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +4 -4
  94. package/dist/index.js.map +1 -1
  95. package/dist/internal/Authoring.d.ts +1 -1
  96. package/dist/internal/Authoring.d.ts.map +1 -1
  97. package/dist/internal/Authoring.js +4 -4
  98. package/dist/internal/Authoring.js.map +1 -1
  99. package/dist/internal/Binding.d.ts +1 -1
  100. package/dist/internal/Binding.d.ts.map +1 -1
  101. package/dist/internal/Completion.d.ts +19 -0
  102. package/dist/internal/Completion.d.ts.map +1 -0
  103. package/dist/internal/Completion.js +2 -0
  104. package/dist/internal/Completion.js.map +1 -0
  105. package/dist/internal/Condition.d.ts +3 -1
  106. package/dist/internal/Condition.d.ts.map +1 -1
  107. package/dist/internal/Condition.js.map +1 -1
  108. package/dist/internal/Configuration.d.ts +248 -0
  109. package/dist/internal/Configuration.d.ts.map +1 -0
  110. package/dist/internal/Configuration.js +343 -0
  111. package/dist/internal/Configuration.js.map +1 -0
  112. package/dist/{Theme.d.ts → internal/Theme.d.ts} +15 -13
  113. package/dist/internal/Theme.d.ts.map +1 -0
  114. package/dist/{Theme.js → internal/Theme.js} +39 -12
  115. package/dist/internal/Theme.js.map +1 -0
  116. package/dist/internal/Token.d.ts +46 -16
  117. package/dist/internal/Token.d.ts.map +1 -1
  118. package/dist/internal/Token.js +89 -5
  119. package/dist/internal/Token.js.map +1 -1
  120. package/dist/internal/Typography.d.ts +13 -5
  121. package/dist/internal/Typography.d.ts.map +1 -1
  122. package/dist/internal/Typography.js +42 -6
  123. package/dist/internal/Typography.js.map +1 -1
  124. package/dist/internal/Value.d.ts +6 -1
  125. package/dist/internal/Value.d.ts.map +1 -1
  126. package/dist/internal/Value.js.map +1 -1
  127. package/dist/internal/VariableSets.d.ts +20 -0
  128. package/dist/internal/VariableSets.d.ts.map +1 -0
  129. package/dist/internal/VariableSets.js +317 -0
  130. package/dist/internal/VariableSets.js.map +1 -0
  131. package/dist/next/index.d.ts +8 -3
  132. package/dist/next/index.d.ts.map +1 -1
  133. package/dist/next/index.js +21 -10
  134. package/dist/next/index.js.map +1 -1
  135. package/dist/next/loader.d.ts +1 -0
  136. package/dist/next/loader.d.ts.map +1 -1
  137. package/dist/next/loader.js +25 -6
  138. package/dist/next/loader.js.map +1 -1
  139. package/dist/node/Host.d.ts.map +1 -1
  140. package/dist/node/Host.js +1 -1
  141. package/dist/node/Host.js.map +1 -1
  142. package/dist/node/Reset.d.ts +3 -0
  143. package/dist/node/Reset.d.ts.map +1 -0
  144. package/dist/node/Reset.js +7 -0
  145. package/dist/node/Reset.js.map +1 -0
  146. package/dist/react-native/Host.d.ts +2 -2
  147. package/dist/react-native/Host.d.ts.map +1 -1
  148. package/dist/react-native/Host.js +4 -4
  149. package/dist/react-native/Host.js.map +1 -1
  150. package/dist/react-native/StyleSheet.d.ts +9 -8
  151. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  152. package/dist/react-native/StyleSheet.js +29 -23
  153. package/dist/react-native/StyleSheet.js.map +1 -1
  154. package/dist/react-native/Variants.d.ts +3 -3
  155. package/dist/react-native/Variants.d.ts.map +1 -1
  156. package/dist/react-native/Variants.js +2 -2
  157. package/dist/react-native/react.d.ts +1 -1
  158. package/dist/react-native/react.d.ts.map +1 -1
  159. package/dist/react-native/react.js +5 -5
  160. package/dist/react-native/react.js.map +1 -1
  161. package/dist/rollup/index.d.ts +3 -0
  162. package/dist/rollup/index.d.ts.map +1 -0
  163. package/dist/rollup/index.js +5 -0
  164. package/dist/rollup/index.js.map +1 -0
  165. package/dist/runtime/Appearance.d.ts +7 -7
  166. package/dist/runtime/Appearance.d.ts.map +1 -1
  167. package/dist/runtime/Appearance.js +15 -15
  168. package/dist/runtime/Appearance.js.map +1 -1
  169. package/dist/runtime/Dynamic.d.ts.map +1 -1
  170. package/dist/runtime/Dynamic.js +4 -1
  171. package/dist/runtime/Dynamic.js.map +1 -1
  172. package/dist/runtime/NativeContext.d.ts +4 -4
  173. package/dist/runtime/NativeContext.d.ts.map +1 -1
  174. package/dist/runtime/NativeContext.js +5 -5
  175. package/dist/runtime/NativeContext.js.map +1 -1
  176. package/dist/runtime/NativeDynamic.d.ts +1 -1
  177. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  178. package/dist/runtime/NativeDynamic.js.map +1 -1
  179. package/dist/runtime/Props.d.ts +1 -1
  180. package/dist/runtime/Props.js +3 -3
  181. package/dist/runtime/Props.js.map +1 -1
  182. package/dist/runtime/Selection.d.ts +14 -10
  183. package/dist/runtime/Selection.d.ts.map +1 -1
  184. package/dist/runtime/Selection.js +19 -18
  185. package/dist/runtime/Selection.js.map +1 -1
  186. package/dist/styleFunction.d.ts +14 -14
  187. package/dist/styleFunction.d.ts.map +1 -1
  188. package/dist/styleFunction.js.map +1 -1
  189. package/dist/unplugin/index.d.ts +22 -0
  190. package/dist/unplugin/index.d.ts.map +1 -0
  191. package/dist/unplugin/index.js +500 -0
  192. package/dist/unplugin/index.js.map +1 -0
  193. package/dist/variants.d.ts +3 -3
  194. package/dist/variants.d.ts.map +1 -1
  195. package/dist/variants.js.map +1 -1
  196. package/dist/vite/index.d.ts +2 -0
  197. package/dist/vite/index.d.ts.map +1 -1
  198. package/dist/vite/index.js +44 -12
  199. package/dist/vite/index.js.map +1 -1
  200. package/dist/web/Css.d.ts +4 -3
  201. package/dist/web/Css.d.ts.map +1 -1
  202. package/dist/web/Css.js +4 -4
  203. package/dist/web/Css.js.map +1 -1
  204. package/dist/web/internal/Themes.d.ts +3 -2
  205. package/dist/web/internal/Themes.d.ts.map +1 -1
  206. package/dist/web/internal/Themes.js +42 -6
  207. package/dist/web/internal/Themes.js.map +1 -1
  208. package/dist/webpack/index.d.ts +3 -0
  209. package/dist/webpack/index.d.ts.map +1 -0
  210. package/dist/webpack/index.js +5 -0
  211. package/dist/webpack/index.js.map +1 -0
  212. package/package.json +23 -2
  213. package/src/Config.ts +43 -685
  214. package/src/Style.ts +97 -34
  215. package/src/Vars.ts +299 -0
  216. package/src/babel/index.ts +23 -1
  217. package/src/compiler/Graph.ts +36 -9
  218. package/src/compiler/Native.ts +29 -32
  219. package/src/compiler/Source.ts +64 -22
  220. package/src/compiler/Transform.ts +73 -23
  221. package/src/compiler/internal/Compositions.ts +36 -3
  222. package/src/compiler/internal/Configurations.ts +83 -11
  223. package/src/compiler/internal/Contract.ts +207 -15
  224. package/src/compiler/internal/Contributions.ts +6 -3
  225. package/src/compiler/internal/Dynamic.ts +1 -1
  226. package/src/compiler/internal/Expression.ts +26 -0
  227. package/src/compiler/internal/Identifiers.ts +2 -1
  228. package/src/compiler/internal/NativeBindings.ts +3 -3
  229. package/src/compiler/internal/PackedStyles.ts +22 -26
  230. package/src/compiler/internal/Recipes.ts +1 -1
  231. package/src/compiler/internal/Selectors.ts +1 -1
  232. package/src/compiler/internal/Static.ts +1 -0
  233. package/src/compiler/internal/Themes.ts +266 -57
  234. package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
  235. package/src/default.ts +173 -154
  236. package/src/esbuild/index.ts +5 -0
  237. package/src/index.ts +4 -4
  238. package/src/internal/Authoring.ts +5 -7
  239. package/src/internal/Binding.ts +1 -1
  240. package/src/internal/Completion.ts +42 -0
  241. package/src/internal/Condition.ts +31 -1
  242. package/src/internal/Configuration.ts +970 -0
  243. package/src/{Theme.ts → internal/Theme.ts} +75 -20
  244. package/src/internal/Token.ts +258 -85
  245. package/src/internal/Typography.ts +71 -16
  246. package/src/internal/Value.ts +45 -26
  247. package/src/internal/VariableSets.ts +458 -0
  248. package/src/next/index.ts +34 -12
  249. package/src/next/loader.ts +35 -6
  250. package/src/node/Host.ts +1 -2
  251. package/src/node/Reset.ts +7 -0
  252. package/src/react-native/Host.ts +6 -6
  253. package/src/react-native/StyleSheet.ts +49 -42
  254. package/src/react-native/Variants.ts +3 -3
  255. package/src/react-native/react.ts +6 -6
  256. package/src/rollup/index.ts +5 -0
  257. package/src/runtime/Appearance.ts +20 -20
  258. package/src/runtime/Dynamic.ts +4 -1
  259. package/src/runtime/NativeContext.ts +8 -8
  260. package/src/runtime/NativeDynamic.ts +2 -4
  261. package/src/runtime/Props.ts +3 -3
  262. package/src/runtime/Selection.ts +44 -33
  263. package/src/styleFunction.ts +22 -19
  264. package/src/unplugin/index.ts +604 -0
  265. package/src/variants.ts +7 -5
  266. package/src/vite/index.ts +48 -18
  267. package/src/web/Css.ts +10 -7
  268. package/src/web/internal/Themes.ts +52 -9
  269. package/src/webpack/index.ts +5 -0
  270. package/dist/Theme.d.ts.map +0 -1
  271. package/dist/Theme.js.map +0 -1
  272. package/dist/compiler/internal/Variables.d.ts.map +0 -1
  273. 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, 24,
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,37 @@ 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)
111
189
  if (
112
190
  (data.version as number) < 24 &&
113
191
  Object.hasOwn(definition.tokens, 'typography')
@@ -116,6 +194,15 @@ export function read(
116
194
  'Packed typography sets require contract version 24 or later.',
117
195
  )
118
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
+ )
205
+
119
206
  themes[name] = Token.bind(definition, contract)
120
207
  types[name] = type(input(definition))
121
208
  }
@@ -206,7 +293,8 @@ export function read(
206
293
  const reference = string(entry.reference)
207
294
  if (
208
295
  ![
209
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
296
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
297
+ 27,
210
298
  ].includes(data.version as number) ||
211
299
  ![
212
300
  'cssFunction',
@@ -254,10 +342,7 @@ export function read(
254
342
  }
255
343
 
256
344
  if (entry.kind === 'style-reference') {
257
- if (
258
- entry.style !== undefined &&
259
- ![16, 17, 18, 19, 20, 21, 22, 23, 24].includes(data.version as number)
260
- )
345
+ if (entry.style !== undefined && (data.version as number) < 16)
261
346
  throw new Error(
262
347
  'Packed callable styles require contract version 16 or later.',
263
348
  )
@@ -331,10 +416,17 @@ export function read(
331
416
  : undefined
332
417
 
333
418
  const options =
334
- entry.options === undefined ? undefined : record(entry.options)
419
+ entry.options === undefined ? undefined : record(decode(entry.options))
335
420
 
336
421
  if (options) {
337
- 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)
338
430
  if (
339
431
  (data.version as number) >= 17 &&
340
432
  (options.cssOutput ?? 'atomic') !==
@@ -344,6 +436,14 @@ export function read(
344
436
  'Configuration CSS output disagrees with linked theme metadata.',
345
437
  )
346
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
+
347
447
  if (
348
448
  Shorthands.signature(options.shorthands) !==
349
449
  Shorthands.signature(definition[Token.definition].contract.shorthands)
@@ -357,7 +457,9 @@ export function read(
357
457
  !!options?.themes &&
358
458
  ((data.version as number) < 4 || entry.catalogOnly === true)
359
459
  const fullConfigType = options
360
- ? `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)}>`
361
463
  : ''
362
464
  // Helpers a legacy library did not compile are hidden from its consumers' types.
363
465
  const hidden = [
@@ -376,6 +478,27 @@ export function read(
376
478
  return {
377
479
  binding: string(entry.binding),
378
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
+ : {}),
379
502
  ...(entry.recipe === true ? { recipe: true } : {}),
380
503
  ...(entry.output === 'html' ? { output: 'html' as const } : {}),
381
504
  ...(catalogOnly ? { catalogOnly: true } : {}),
@@ -399,7 +522,7 @@ export function read(
399
522
  ...(options
400
523
  ? {
401
524
  options,
402
- 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']") : ''}`,
403
526
  }
404
527
  : {}),
405
528
  ...(members
@@ -459,6 +582,7 @@ function tokens(tree: Theme.References<Theme.Tokens>): Record<string, unknown> {
459
582
  }
460
583
 
461
584
  function type(value: unknown): string {
585
+ if (Token.is(value)) return Configurations.type(value)
462
586
  if (Array.isArray(value)) return `readonly [${value.map(type).join(',')}]`
463
587
  if (!value || typeof value !== 'object') return JSON.stringify(value)
464
588
 
@@ -525,6 +649,11 @@ export function write(
525
649
  }
526
650
 
527
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
+ : {}),
528
657
  ...(link.call.recipe ? { recipe: true } : {}),
529
658
  ...(link.call.output ? { output: link.call.output } : {}),
530
659
  ...(link.call.script &&
@@ -541,7 +670,7 @@ export function write(
541
670
  ...(link.call.selection ? { selection: true } : {}),
542
671
  ...(link.call.initialization ? { initialization: true } : {}),
543
672
  ...(link.call.root ? { root: true } : {}),
544
- ...(link.call.options ? { options: link.call.options } : {}),
673
+ ...(link.call.options ? { options: encode(link.call.options) } : {}),
545
674
  ...(link.members
546
675
  ? {
547
676
  members: Object.fromEntries(
@@ -572,15 +701,46 @@ export function write(
572
701
  ...(theme[Token.definition].contract.shorthands
573
702
  ? { shorthands: theme[Token.definition].contract.shorthands }
574
703
  : {}),
704
+ ...(theme[Token.definition].contract.defaultLayer !== undefined
705
+ ? { defaultLayer: theme[Token.definition].contract.defaultLayer }
706
+ : {}),
575
707
  ...(theme[Token.definition].contract.cssOutput
576
708
  ? { cssOutput: theme[Token.definition].contract.cssOutput }
577
709
  : {}),
710
+ ...(theme[Token.definition].contract.variableSet
711
+ ? {
712
+ variableSet: true,
713
+ mappings: theme[Token.definition].contract.mappings,
714
+ }
715
+ : {}),
578
716
  identity: theme[Token.definition].contract[Token.identity],
579
- tokens: input(theme),
717
+ tokens: encode(input(theme)),
580
718
  },
581
719
  ]),
582
720
  ),
583
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
+
584
744
  if (
585
745
  Object.values(themes).some((theme) =>
586
746
  Object.hasOwn(theme.tokens, 'typography'),
@@ -858,3 +1018,35 @@ function extended(signature: NonNullable<Themes.Call['function']>): boolean {
858
1018
  )
859
1019
  )
860
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'
@@ -506,12 +506,13 @@ export function extract(
506
506
  scanned: ReturnType<typeof scan>,
507
507
  tokens: ReadonlyMap<number, { end: number; reference: Token.Reference }>,
508
508
  starts?: number[],
509
+ resolve: (node: Ast.Node) => Ast.Node = Expression.unwrap,
509
510
  ): readonly Css.Contribution[] {
510
511
  const result: Css.Contribution[] = []
511
512
  function value(node: Ast.Node, property?: string): unknown {
512
513
  const reference = tokens.get(node.start)
513
514
  if (reference?.end === node.end) return reference.reference
514
- node = Expression.unwrap(node)
515
+ node = Expression.unwrap(resolve(node))
515
516
 
516
517
  const animation = scanned.references.get(node.start)
517
518
  if (animation) return animation
@@ -545,7 +546,9 @@ export function extract(
545
546
 
546
547
  if (node.type === 'TemplateLiteral') {
547
548
  const template = Expression.template(node, 0, (expression, prefix) => {
548
- const node = Expression.unwrap(expression)
549
+ const node = Expression.unwrap(resolve(expression))
550
+ if (node.type === 'Literal' && typeof node.value === 'string')
551
+ return node.value
549
552
  const name = scanned.references.get(node.start)
550
553
  const kind = name ? scanned.kinds.get(name) : undefined
551
554
  if (
@@ -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'
@@ -117,6 +117,7 @@ export function create(
117
117
  const binding = scope.getDeclaration(node.name) ?? null
118
118
  if (!binding && node.name === 'undefined') absent.add(node.start)
119
119
  if (!binding || !values.has(binding.node.start)) return binding
120
+ if (ancestors.some((node) => node.type === 'TSTypeQuery')) return binding
120
121
 
121
122
  references.set(node.start, binding.node.start)
122
123
  const value = Expression.unwrap(values.get(binding.node.start)!)