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
@@ -2,19 +2,28 @@
2
2
  * Carries portable theme references and enforces their property domains.
3
3
  * @module
4
4
  */
5
- import type * as Binding from './Binding.js'
5
+ import * as Binding from './Binding.js'
6
6
  import type * as Query from './Query.js'
7
7
  import type * as Shorthands from './Shorthands.js'
8
- import type * as Theme from '../Theme.js'
8
+ import type * as Theme from './Theme.js'
9
+ import type * as ValueSyntax from './Value.js'
10
+ import type * as VariableSets from '../Vars.js'
9
11
  import * as Literal from './Literal.js'
12
+ import * as VariableData from './VariableSets.js'
10
13
 
11
14
  /** Checks a reference's property domain. */
12
15
  export function accepts(
13
16
  group: Group,
14
17
  property: keyof Literal.Properties,
15
18
  ): boolean {
19
+ if (property.startsWith('--')) return true
20
+ if (group === 'number' || group === 'string') return false
16
21
  if (group === 'color') return Literal.rule(property)?.kind === 'color'
17
22
  if (group === 'borderColor') return /^border.*Color$/.test(property)
23
+ if (group === 'borderWidth')
24
+ return /^border(?:Block|Inline)?(?:Start|End|Top|Right|Bottom|Left)?Width$/.test(
25
+ property,
26
+ )
18
27
  if (group === 'borderRadius') return /^border.*Radius$/.test(property)
19
28
  if (group === 'textColor') return property === 'color'
20
29
 
@@ -57,6 +66,50 @@ export function accepts(
57
66
  return group === property
58
67
  }
59
68
 
69
+ /** Checks explicit variable values independently of shorthand category mappings. */
70
+ export function acceptsReference(
71
+ reference: Reference,
72
+ property: keyof Literal.Properties,
73
+ ): boolean {
74
+ if (!reference.contract.variableSet) return accepts(reference.group, property)
75
+ if (property.startsWith('--')) return true
76
+ function check(value: Value): boolean {
77
+ if (is(value)) return acceptsReference(value, property)
78
+ if (typeof value === 'object') return Object.values(value).every(check)
79
+ if (typeof value === 'number') {
80
+ const rule = Literal.rule(property)
81
+ if (rule?.kind === 'number')
82
+ return (
83
+ value >= rule.min &&
84
+ value <= rule.max &&
85
+ (!rule.integer || Number.isInteger(value))
86
+ )
87
+ return value === 0 && Binding.accepts('length', property)
88
+ }
89
+ if (reference.group === 'color') return Binding.accepts('color', property)
90
+ if (reference.group === 'spacing')
91
+ return (
92
+ (Literal.rule(property)?.kind === 'compound' &&
93
+ accepts('spacing', property)) ||
94
+ Binding.accepts(
95
+ value.endsWith('%')
96
+ ? value.startsWith('-')
97
+ ? 'signedPercentage'
98
+ : 'percentage'
99
+ : value.startsWith('-')
100
+ ? 'signedLength'
101
+ : 'length',
102
+ property,
103
+ )
104
+ )
105
+ return (
106
+ Literal.isLiteral(property, value) ||
107
+ Literal.rule(property)?.kind === 'compound'
108
+ )
109
+ }
110
+ return check(reference.value)
111
+ }
112
+
60
113
  /** Rebinds validated scalar references to a explicitly owned contract identity. */
61
114
  export function bind<tokens extends Theme.Tokens>(
62
115
  original: Theme.Definition<tokens>,
@@ -64,6 +117,9 @@ export function bind<tokens extends Theme.Tokens>(
64
117
  ): Theme.Definition<tokens> {
65
118
  type Tree = { [key: string]: Reference | Tree }
66
119
 
120
+ const metadata = original[definition]
121
+ const values = VariableData.rebind(metadata, contract)
122
+
67
123
  function rebind(tree: Theme.References<Theme.Tokens>): Tree {
68
124
  return Object.freeze(
69
125
  Object.fromEntries(
@@ -74,7 +130,7 @@ export function bind<tokens extends Theme.Tokens>(
74
130
  contract,
75
131
  group: value.group,
76
132
  path: value.path,
77
- value: value.value,
133
+ value: values[value.path]!,
78
134
  })
79
135
  : rebind(value as Theme.References<Theme.Tokens>),
80
136
  ]),
@@ -96,7 +152,7 @@ export function bind<tokens extends Theme.Tokens>(
96
152
  vars: variables(tokens),
97
153
  },
98
154
  definition,
99
- { value: Object.freeze({ ...original[definition], contract }) },
155
+ { value: Object.freeze({ ...metadata, contract, values }) },
100
156
  ),
101
157
  ) as Theme.Definition<tokens>
102
158
  }
@@ -106,8 +162,14 @@ export const complete = Symbol('zyzz.contract.complete')
106
162
 
107
163
  /** Opaque data shared by a definition and its compatible extensions. */
108
164
  export type Contract = {
165
+ /** Whether values belong to independent variables rather than fixed theme categories. */
166
+ readonly variableSet?: boolean | undefined
167
+ /** Configuration-local category-to-property mappings. */
168
+ readonly mappings?: VariableSets.Mappings | false | undefined
109
169
  /** Web emission mode retained by configuration-bound theme handles. */
110
170
  readonly cssOutput?: 'atomic' | 'grouped' | undefined
171
+ /** Fallback layer for declarations without an explicit layer. */
172
+ readonly defaultLayer?: string | undefined
111
173
  /** Configuration-local property aliases, inherited by bound handles. */
112
174
  readonly shorthands?: Shorthands.Map | undefined
113
175
  readonly [complete]?: boolean | undefined
@@ -153,23 +215,24 @@ export function compose(
153
215
  export const web = Symbol('zyzz.web.variable')
154
216
 
155
217
  /** Web reference with the original token domain. */
156
- export type Variable<group extends Group = Group> = Reference<group> & {
157
- readonly [web]: true
158
- }
218
+ export type Variable<group extends Group = Group> = `var(--${string})` &
219
+ Reference<group> & {
220
+ readonly [web]: true
221
+ }
159
222
 
160
223
  /** Replaces portable scalar leaves with web-only references. */
161
- export type Variables<tree> =
224
+ export type Vars<tree> =
162
225
  tree extends Reference<infer group>
163
226
  ? Variable<group>
164
- : { readonly [key in keyof tree]: Variables<tree[key]> }
227
+ : { readonly [key in keyof tree]: Vars<tree[key]> }
165
228
 
166
229
  /** Creates web-only reference leaves without changing contract identities. */
167
- export function variables<tree>(tree: tree): Variables<tree> {
230
+ export function variables<tree>(tree: tree): Vars<tree> {
168
231
  if (is(tree))
169
232
  return Object.freeze({
170
233
  ...tree,
171
234
  [web]: true as const,
172
- }) as unknown as Variables<tree>
235
+ }) as unknown as Vars<tree>
173
236
 
174
237
  return Object.freeze(
175
238
  Object.fromEntries(
@@ -178,7 +241,7 @@ export function variables<tree>(tree: tree): Variables<tree> {
178
241
  variables(value),
179
242
  ]),
180
243
  ),
181
- ) as Variables<tree>
244
+ ) as Vars<tree>
182
245
  }
183
246
 
184
247
  /** Internal definition metadata; never enumerable consumer output. */
@@ -186,9 +249,12 @@ export const definition = Symbol('zyzz.theme')
186
249
 
187
250
  /** Supported scalar token groups. */
188
251
  export type Group =
252
+ | 'number'
253
+ | 'string'
189
254
  | 'backgroundColor'
190
255
  | 'borderColor'
191
256
  | 'borderRadius'
257
+ | 'borderWidth'
192
258
  | 'color'
193
259
  | 'margin'
194
260
  | 'padding'
@@ -223,19 +289,53 @@ export function is(value: unknown): value is Reference {
223
289
 
224
290
  /** Immutable theme data carried directly by each definition. */
225
291
  export type Metadata = {
292
+ /** Original segments for typography paths containing query punctuation. */
293
+ readonly paths?: Readonly<Record<string, readonly string[]>> | undefined
226
294
  readonly queries?: Query.Metadata | undefined
227
295
  readonly contract: Contract
228
296
  readonly values: Readonly<Record<string, Value>>
229
297
  }
230
298
 
231
- /** Inferred shorthand names whose leaves belong to a property's domain. */
232
- export type Names<tokens, property extends keyof Literal.Properties> = {
233
- [group in Extract<keyof tokens, Group>]: property extends Properties<group>
234
- ? Paths<NonNullable<tokens[group]>>
235
- : never
236
- }[Extract<keyof tokens, Group>]
299
+ /** Literal domain carried by explicit variable references during type checking. */
300
+ export const scalar = Symbol('zyzz.variable.scalar')
237
301
 
238
- type Paths<tree> = [tree] extends [never]
302
+ /** Inferred shorthand names whose leaves belong to a property domain. */
303
+ export type Names<
304
+ tokens,
305
+ property extends keyof Literal.Properties,
306
+ > = tokens extends {
307
+ readonly '~vars': { values: infer values; mappings: infer mappings }
308
+ }
309
+ ? mappings extends false
310
+ ? Paths<
311
+ Omit<values, 'breakpoints' | 'containers' | 'containerNames'>,
312
+ property
313
+ >
314
+ : {
315
+ [category in keyof values]: category extends keyof mappings
316
+ ? mappings[category] extends readonly unknown[]
317
+ ? property extends mappings[category][number]
318
+ ? Paths<values[category], property>
319
+ : never
320
+ : never
321
+ : category extends Group
322
+ ? property extends Properties<category>
323
+ ? Paths<values[category], property>
324
+ : never
325
+ : never
326
+ }[keyof values]
327
+ : {
328
+ [group in Extract<
329
+ keyof tokens,
330
+ Group
331
+ >]: property extends Properties<group>
332
+ ? Paths<NonNullable<tokens[group]>>
333
+ : never
334
+ }[Extract<keyof tokens, Group>]
335
+
336
+ type Paths<tree, property extends keyof Literal.Properties = never> = [
337
+ tree,
338
+ ] extends [never]
239
339
  ? never
240
340
  : string extends keyof tree
241
341
  ? string
@@ -243,72 +343,95 @@ type Paths<tree> = [tree] extends [never]
243
343
  [key in Extract<keyof tree, number | string>]: NonNullable<
244
344
  tree[key]
245
345
  > extends Value
246
- ?
247
- | key
248
- | `${key}`
249
- | (key extends `${infer numericKey extends number}`
250
- ? `${numericKey}` extends key
251
- ? numericKey
252
- : never
253
- : never)
254
- : `${key}.${Paths<NonNullable<tree[key]>>}`
346
+ ? [property] extends [never]
347
+ ? PathKey<key>
348
+ : VariableSets.Scalar<
349
+ NonNullable<tree[key]>
350
+ > extends Literal.Properties[property] &
351
+ ValueSyntax.Checked<
352
+ Record<
353
+ property,
354
+ VariableSets.Scalar<NonNullable<tree[key]>>
355
+ >
356
+ >[property]
357
+ ? PathKey<key>
358
+ : never
359
+ : `${key}.${Paths<NonNullable<tree[key]>, property>}`
255
360
  }[Extract<keyof tree, number | string>]
256
361
 
362
+ type PathKey<key extends number | string> =
363
+ | key
364
+ | `${key}`
365
+ | (key extends `${infer numericKey extends number}`
366
+ ? `${numericKey}` extends key
367
+ ? numericKey
368
+ : never
369
+ : never)
370
+
257
371
  /** Property domains accepted by each token group. */
258
- export type Properties<group extends Group> = group extends 'margin' | 'padding'
259
- ? Exclude<
260
- Extract<keyof Literal.Properties, `${group}${string}`>,
261
- 'marginTrim'
262
- >
263
- : group extends 'spacing'
264
- ? Extract<
265
- keyof Literal.Properties,
266
- | `blockSize`
267
- | `bottom`
268
- | `columnGap`
269
- | `flexBasis`
270
- | `gap`
271
- | `height`
272
- | `inlineSize`
273
- | `inset${string}`
274
- | `left`
275
- | Exclude<
276
- Extract<keyof Literal.Properties, `margin${string}`>,
277
- 'marginTrim'
278
- >
279
- | `maxBlockSize`
280
- | `maxHeight`
281
- | `maxInlineSize`
282
- | `maxWidth`
283
- | `minBlockSize`
284
- | `minHeight`
285
- | `minInlineSize`
286
- | `minWidth`
287
- | `padding${string}`
288
- | `right`
289
- | `rowGap`
290
- | `scrollPadding${string}`
291
- | `textDecorationThickness`
292
- | `textIndent`
293
- | `textUnderlineOffset`
294
- | `top`
295
- | `width`
372
+ export type Properties<group extends Group> = `--${string}` | Property<group>
373
+
374
+ type Property<group extends Group> = group extends 'number' | 'string'
375
+ ? never
376
+ : group extends 'margin' | 'padding'
377
+ ? Exclude<
378
+ Extract<keyof Literal.Properties, `${group}${string}`>,
379
+ 'marginTrim'
296
380
  >
297
- : group extends 'textColor'
298
- ? 'color'
299
- : group extends 'color'
300
- ? {
301
- [property in keyof typeof Literal.rules]: (typeof Literal.rules)[property] extends {
302
- kind: 'color'
303
- }
304
- ? property
305
- : never
306
- }[keyof typeof Literal.rules]
307
- : group extends 'borderColor'
308
- ? Extract<keyof Literal.Properties, `border${string}Color`>
309
- : group extends 'borderRadius'
310
- ? Extract<keyof Literal.Properties, `border${string}Radius`>
311
- : group
381
+ : group extends 'spacing'
382
+ ? Extract<
383
+ keyof Literal.Properties,
384
+ | `blockSize`
385
+ | `bottom`
386
+ | `columnGap`
387
+ | `flexBasis`
388
+ | `gap`
389
+ | `height`
390
+ | `inlineSize`
391
+ | `inset${string}`
392
+ | `left`
393
+ | Exclude<
394
+ Extract<keyof Literal.Properties, `margin${string}`>,
395
+ 'marginTrim'
396
+ >
397
+ | `maxBlockSize`
398
+ | `maxHeight`
399
+ | `maxInlineSize`
400
+ | `maxWidth`
401
+ | `minBlockSize`
402
+ | `minHeight`
403
+ | `minInlineSize`
404
+ | `minWidth`
405
+ | `padding${string}`
406
+ | `right`
407
+ | `rowGap`
408
+ | `scrollPadding${string}`
409
+ | `textDecorationThickness`
410
+ | `textIndent`
411
+ | `textUnderlineOffset`
412
+ | `top`
413
+ | `width`
414
+ >
415
+ : group extends 'textColor'
416
+ ? 'color'
417
+ : group extends 'color'
418
+ ? {
419
+ [property in keyof typeof Literal.rules]: (typeof Literal.rules)[property] extends {
420
+ kind: 'color'
421
+ }
422
+ ? property
423
+ : never
424
+ }[keyof typeof Literal.rules]
425
+ : group extends 'borderColor'
426
+ ? Extract<keyof Literal.Properties, `border${string}Color`>
427
+ : group extends 'borderWidth'
428
+ ? Exclude<
429
+ Extract<keyof Literal.Properties, `border${string}Width`>,
430
+ 'borderImageWidth'
431
+ >
432
+ : group extends 'borderRadius'
433
+ ? Extract<keyof Literal.Properties, `border${string}Radius`>
434
+ : group
312
435
 
313
436
  /** Immutable portable reference retaining its defining fallback. */
314
437
  export type Reference<group extends Group = Group> = {
@@ -333,11 +456,11 @@ export function resolve(value: unknown, options: resolve.Options): unknown {
333
456
  ?.value as Metadata | undefined
334
457
  if (!data) throw new Error('Expected a theme definition.')
335
458
 
336
- // Specific groups precede shared colors regardless of authored group order.
337
- for (const group of [
459
+ const groups = [
338
460
  'backgroundColor',
339
461
  'borderColor',
340
462
  'borderRadius',
463
+ 'borderWidth',
341
464
  'margin',
342
465
  'padding',
343
466
  'spacing',
@@ -348,7 +471,49 @@ export function resolve(value: unknown, options: resolve.Options): unknown {
348
471
  'lineHeight',
349
472
  'textColor',
350
473
  'color',
351
- ] as const) {
474
+ ] as const
475
+
476
+ if (data.contract.variableSet) {
477
+ for (const [path, entry] of Object.entries(data.values).sort(
478
+ ([left], [right]) =>
479
+ groups.indexOf(left.split('.')[0] as (typeof groups)[number]) -
480
+ groups.indexOf(right.split('.')[0] as (typeof groups)[number]),
481
+ )) {
482
+ const [category, ...parts] = path.split('.')
483
+ const mappings = data.contract.mappings
484
+ const mapped = mappings === false ? undefined : mappings?.[category!]
485
+ if (
486
+ mappings === false
487
+ ? path !== String(value)
488
+ : parts.join('.') !== String(value) ||
489
+ !(mapped
490
+ ? mapped.includes(options.property)
491
+ : accepts(category as Group, options.property))
492
+ )
493
+ continue
494
+ return create({
495
+ contract: data.contract,
496
+ group: (() => {
497
+ let leaf: unknown = Object.getOwnPropertyDescriptor(
498
+ options.theme,
499
+ 'tokens',
500
+ )?.value
501
+ for (const key of path.split('.'))
502
+ leaf =
503
+ leaf && typeof leaf === 'object'
504
+ ? Object.getOwnPropertyDescriptor(leaf, key)?.value
505
+ : undefined
506
+ return is(leaf) ? leaf.group : (category as Group)
507
+ })(),
508
+ path,
509
+ value: entry,
510
+ })
511
+ }
512
+ return value
513
+ }
514
+
515
+ // Specific groups precede shared colors regardless of authored group order.
516
+ for (const group of groups) {
352
517
  if (!accepts(group, options.property)) continue
353
518
 
354
519
  const path = `${group}.${value}`
@@ -377,4 +542,12 @@ export declare namespace resolve {
377
542
  export type Value =
378
543
  | number
379
544
  | string
380
- | { readonly dark: string; readonly light: string }
545
+ | Reference
546
+ | { readonly dark: Value; readonly light: Value }
547
+ | Conditions
548
+
549
+ /** Ordered conditional values with an unconditional fallback. */
550
+ export type Conditions = {
551
+ readonly default: Value
552
+ readonly [query: `@media ${string}`]: Value
553
+ }
@@ -0,0 +1,106 @@
1
+ /** Describes nested typography sets and their property-aware token paths. @module */
2
+ import type * as Literal from './Literal.js'
3
+ import * as Token from './Token.js'
4
+
5
+ /** Responsive query blocks accepted within a typography set. */
6
+ export type Condition = `@media ${string}` | `@container ${string}`
7
+
8
+ /** Recognizes responsive blocks without accepting selectors or unrelated at-rules. */
9
+ export function condition(key: string): key is Condition {
10
+ return /^@(media|container)\s+\S/.test(key)
11
+ }
12
+
13
+ /** Expands one named set into portable field references and ordered query blocks. */
14
+ export function entries(
15
+ theme: object | undefined,
16
+ name: unknown,
17
+ explicit: ReadonlySet<string> = new Set(),
18
+ important = false,
19
+ ): readonly (readonly [string, unknown])[] {
20
+ if (
21
+ !theme ||
22
+ typeof name !== 'string' ||
23
+ name.split('.').some((part) => part.startsWith('@'))
24
+ )
25
+ return []
26
+ let tree: unknown = Object.getOwnPropertyDescriptor(theme, 'tokens')?.value
27
+ for (const part of ['typography', ...name.split('.')]) {
28
+ if (!tree || typeof tree !== 'object') return []
29
+ tree = Object.getOwnPropertyDescriptor(tree, part)?.value
30
+ }
31
+ function expand(value: unknown): readonly (readonly [string, unknown])[] {
32
+ if (!value || typeof value !== 'object') return []
33
+ return Object.entries(value).flatMap(
34
+ ([key, child]): (readonly [string, unknown])[] => {
35
+ if (
36
+ properties.includes(key as Property) &&
37
+ Token.is(child) &&
38
+ !explicit.has(key)
39
+ )
40
+ return [
41
+ [key, important ? Token.compose([child, ' !important']) : child],
42
+ ]
43
+ if (condition(key)) {
44
+ const nested = expand(child)
45
+ return nested.length ? [[key, Object.fromEntries(nested)]] : []
46
+ }
47
+ return []
48
+ },
49
+ )
50
+ }
51
+ return expand(tree)
52
+ }
53
+
54
+ /** Lists expanded fields and queries in source-map traversal order. */
55
+ export function keys(
56
+ theme: object | undefined,
57
+ name: unknown,
58
+ explicit: ReadonlySet<string>,
59
+ ): readonly string[] {
60
+ function collect(values: readonly (readonly [string, unknown])[]): string[] {
61
+ return values.flatMap(([key, value]) =>
62
+ condition(key)
63
+ ? [key, ...collect(Object.entries(value as object))]
64
+ : [key],
65
+ )
66
+ }
67
+ return collect(entries(theme, name, explicit))
68
+ }
69
+
70
+ /** Names of sets containing at least one typography declaration. */
71
+ export type Names<tokens> = tokens extends { typography: infer tree }
72
+ ? Paths<tree>
73
+ : never
74
+
75
+ type Paths<tree> = string extends keyof tree
76
+ ? string
77
+ : {
78
+ [key in Exclude<
79
+ Extract<keyof tree, string | number>,
80
+ Property | Condition
81
+ >]:
82
+ | (Extract<keyof tree[key], Property | Condition> extends never
83
+ ? never
84
+ : `${key}`)
85
+ | `${key}.${Paths<tree[key]>}`
86
+ }[Exclude<Extract<keyof tree, string | number>, Property | Condition>]
87
+
88
+ /** Scalar properties applied by a typography set. */
89
+ export const properties = [
90
+ 'fontFamily',
91
+ 'fontSize',
92
+ 'fontWeight',
93
+ 'letterSpacing',
94
+ 'lineHeight',
95
+ ] as const
96
+
97
+ /** Property domain retained by each field in a set. */
98
+ export type Property = (typeof properties)[number]
99
+
100
+ /** A set may supply any of the five typography properties. */
101
+ export type Set = Pick<Literal.Properties, Property> & {
102
+ readonly [key in Condition]?: Set
103
+ }
104
+
105
+ /** Nested names may contain sets and additional named variants. */
106
+ export type Sets = { readonly [name: string]: Set | Sets }
@@ -22,37 +22,56 @@ export type Atom<value> =
22
22
  */
23
23
  export type Accepted<style, properties> = {
24
24
  [property in keyof style]: property extends keyof properties
25
- ? style[property] extends Binding.Reference
26
- ? Binding.Reference<style[property]['type']> extends Exclude<
27
- properties[property],
28
- undefined
29
- >
30
- ? style[property]
25
+ ? style[property] extends { readonly [Token.scalar]: infer scalar }
26
+ ? property extends keyof Literal.Properties
27
+ ? [scalar] extends [Literal.Properties[property]]
28
+ ? style[property] & Checked<Record<property, scalar>>[property]
29
+ : never
31
30
  : never
32
- : FunctionValue.Is<style[property]> extends true
33
- ? FunctionValue.Accepted<
34
- style[property],
35
- Exclude<properties[property], undefined>,
36
- property
37
- >
38
- : Exclude<style[property], undefined> extends Exclude<
39
- properties[property],
40
- undefined
41
- >
42
- ? Exclude<style[property], undefined>
43
- : property extends keyof Literal.Properties
44
- ? style[property] extends string | readonly (number | string)[]
45
- ? Fold<style[property]> extends Input<
46
- | Lowercase<Extract<Literal.Properties[property], string>>
47
- | Extract<Literal.Properties[property], number>
31
+ : References<style[property], Exclude<properties[property], undefined>> &
32
+ (style[property] extends Binding.Reference
33
+ ? Binding.Reference<style[property]['type']> extends Exclude<
34
+ properties[property],
35
+ undefined
36
+ >
37
+ ? style[property]
38
+ : never
39
+ : FunctionValue.Is<style[property]> extends true
40
+ ? FunctionValue.Accepted<
41
+ style[property],
42
+ Exclude<properties[property], undefined>,
43
+ property
48
44
  >
49
- ? style[property]
50
- : Exclude<properties[property], undefined>
51
- : Exclude<properties[property], undefined>
52
- : Exclude<properties[property], undefined>
45
+ : Exclude<style[property], undefined> extends Exclude<
46
+ properties[property],
47
+ undefined
48
+ >
49
+ ? Exclude<style[property], undefined>
50
+ : property extends keyof Literal.Properties
51
+ ? style[property] extends
52
+ | string
53
+ | readonly (number | string)[]
54
+ ? Fold<style[property]> extends Input<
55
+ | Lowercase<
56
+ Extract<Literal.Properties[property], string>
57
+ >
58
+ | Extract<Literal.Properties[property], number>
59
+ >
60
+ ? style[property]
61
+ : Exclude<properties[property], undefined>
62
+ : Exclude<properties[property], undefined>
63
+ : Exclude<properties[property], undefined>)
53
64
  : never
54
65
  }
55
66
 
67
+ type References<value, allowed> = value extends Token.Reference
68
+ ? value extends Extract<allowed, Token.Reference>
69
+ ? unknown
70
+ : never
71
+ : value extends readonly unknown[]
72
+ ? { [key in keyof value]: References<value[key], allowed> }
73
+ : unknown
74
+
56
75
  type Fold<value> = value extends string
57
76
  ? Lexical.Fold<Canonical<Spaces<Normalized<Lexical.Normalized<value>>>>>
58
77
  : value extends readonly unknown[]