zyzz 0.0.3 → 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 (247) 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/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 +8 -6
  21. package/dist/compiler/Source.d.ts.map +1 -1
  22. package/dist/compiler/Source.js +47 -14
  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 +58 -22
  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 +155 -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 +147 -2562
  72. package/dist/default.d.ts.map +1 -1
  73. package/dist/default.js +85 -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/{Theme.d.ts → internal/Theme.d.ts} +15 -13
  102. package/dist/internal/Theme.d.ts.map +1 -0
  103. package/dist/{Theme.js → internal/Theme.js} +39 -12
  104. package/dist/internal/Theme.js.map +1 -0
  105. package/dist/internal/Token.d.ts +46 -16
  106. package/dist/internal/Token.d.ts.map +1 -1
  107. package/dist/internal/Token.js +89 -5
  108. package/dist/internal/Token.js.map +1 -1
  109. package/dist/internal/Typography.d.ts +13 -5
  110. package/dist/internal/Typography.d.ts.map +1 -1
  111. package/dist/internal/Typography.js +42 -6
  112. package/dist/internal/Typography.js.map +1 -1
  113. package/dist/internal/Value.d.ts +6 -1
  114. package/dist/internal/Value.d.ts.map +1 -1
  115. package/dist/internal/Value.js.map +1 -1
  116. package/dist/internal/VariableSets.d.ts +20 -0
  117. package/dist/internal/VariableSets.d.ts.map +1 -0
  118. package/dist/internal/VariableSets.js +317 -0
  119. package/dist/internal/VariableSets.js.map +1 -0
  120. package/dist/next/loader.js +15 -5
  121. package/dist/next/loader.js.map +1 -1
  122. package/dist/node/Host.d.ts.map +1 -1
  123. package/dist/node/Host.js +1 -1
  124. package/dist/node/Host.js.map +1 -1
  125. package/dist/react-native/Host.d.ts +2 -2
  126. package/dist/react-native/Host.d.ts.map +1 -1
  127. package/dist/react-native/Host.js +4 -4
  128. package/dist/react-native/Host.js.map +1 -1
  129. package/dist/react-native/StyleSheet.d.ts +9 -8
  130. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  131. package/dist/react-native/StyleSheet.js +29 -23
  132. package/dist/react-native/StyleSheet.js.map +1 -1
  133. package/dist/react-native/Variants.d.ts +3 -3
  134. package/dist/react-native/Variants.d.ts.map +1 -1
  135. package/dist/react-native/Variants.js +2 -2
  136. package/dist/react-native/react.d.ts +1 -1
  137. package/dist/react-native/react.d.ts.map +1 -1
  138. package/dist/react-native/react.js +5 -5
  139. package/dist/react-native/react.js.map +1 -1
  140. package/dist/rollup/index.d.ts +3 -0
  141. package/dist/rollup/index.d.ts.map +1 -0
  142. package/dist/rollup/index.js +5 -0
  143. package/dist/rollup/index.js.map +1 -0
  144. package/dist/runtime/Appearance.d.ts +7 -7
  145. package/dist/runtime/Appearance.d.ts.map +1 -1
  146. package/dist/runtime/Appearance.js +15 -15
  147. package/dist/runtime/Appearance.js.map +1 -1
  148. package/dist/runtime/Dynamic.d.ts.map +1 -1
  149. package/dist/runtime/Dynamic.js +4 -1
  150. package/dist/runtime/Dynamic.js.map +1 -1
  151. package/dist/runtime/NativeContext.d.ts +4 -4
  152. package/dist/runtime/NativeContext.d.ts.map +1 -1
  153. package/dist/runtime/NativeContext.js +5 -5
  154. package/dist/runtime/NativeContext.js.map +1 -1
  155. package/dist/runtime/NativeDynamic.d.ts +1 -1
  156. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  157. package/dist/runtime/NativeDynamic.js.map +1 -1
  158. package/dist/runtime/Props.d.ts +1 -1
  159. package/dist/runtime/Props.js +3 -3
  160. package/dist/runtime/Props.js.map +1 -1
  161. package/dist/runtime/Selection.d.ts +14 -10
  162. package/dist/runtime/Selection.d.ts.map +1 -1
  163. package/dist/runtime/Selection.js +19 -18
  164. package/dist/runtime/Selection.js.map +1 -1
  165. package/dist/styleFunction.d.ts +14 -14
  166. package/dist/styleFunction.d.ts.map +1 -1
  167. package/dist/styleFunction.js.map +1 -1
  168. package/dist/unplugin/index.d.ts +20 -0
  169. package/dist/unplugin/index.d.ts.map +1 -0
  170. package/dist/unplugin/index.js +498 -0
  171. package/dist/unplugin/index.js.map +1 -0
  172. package/dist/variants.d.ts +3 -3
  173. package/dist/variants.d.ts.map +1 -1
  174. package/dist/variants.js.map +1 -1
  175. package/dist/vite/index.d.ts.map +1 -1
  176. package/dist/vite/index.js +6 -3
  177. package/dist/vite/index.js.map +1 -1
  178. package/dist/web/Css.d.ts +4 -3
  179. package/dist/web/Css.d.ts.map +1 -1
  180. package/dist/web/Css.js +4 -4
  181. package/dist/web/Css.js.map +1 -1
  182. package/dist/web/internal/Themes.d.ts +3 -2
  183. package/dist/web/internal/Themes.d.ts.map +1 -1
  184. package/dist/web/internal/Themes.js +42 -6
  185. package/dist/web/internal/Themes.js.map +1 -1
  186. package/dist/webpack/index.d.ts +3 -0
  187. package/dist/webpack/index.d.ts.map +1 -0
  188. package/dist/webpack/index.js +5 -0
  189. package/dist/webpack/index.js.map +1 -0
  190. package/package.json +23 -2
  191. package/src/Config.ts +43 -685
  192. package/src/Style.ts +97 -34
  193. package/src/Vars.ts +299 -0
  194. package/src/compiler/Graph.ts +14 -9
  195. package/src/compiler/Native.ts +29 -32
  196. package/src/compiler/Source.ts +59 -21
  197. package/src/compiler/Transform.ts +73 -23
  198. package/src/compiler/internal/Compositions.ts +36 -3
  199. package/src/compiler/internal/Configurations.ts +83 -11
  200. package/src/compiler/internal/Contract.ts +207 -15
  201. package/src/compiler/internal/Contributions.ts +1 -1
  202. package/src/compiler/internal/Dynamic.ts +1 -1
  203. package/src/compiler/internal/Expression.ts +26 -0
  204. package/src/compiler/internal/Identifiers.ts +2 -1
  205. package/src/compiler/internal/NativeBindings.ts +3 -3
  206. package/src/compiler/internal/PackedStyles.ts +22 -26
  207. package/src/compiler/internal/Recipes.ts +1 -1
  208. package/src/compiler/internal/Selectors.ts +1 -1
  209. package/src/compiler/internal/Themes.ts +266 -57
  210. package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
  211. package/src/default.ts +173 -154
  212. package/src/esbuild/index.ts +5 -0
  213. package/src/index.ts +4 -4
  214. package/src/internal/Authoring.ts +5 -7
  215. package/src/internal/Binding.ts +1 -1
  216. package/src/internal/Completion.ts +42 -0
  217. package/src/internal/Condition.ts +31 -1
  218. package/src/internal/Configuration.ts +970 -0
  219. package/src/{Theme.ts → internal/Theme.ts} +75 -20
  220. package/src/internal/Token.ts +258 -85
  221. package/src/internal/Typography.ts +71 -16
  222. package/src/internal/Value.ts +45 -26
  223. package/src/internal/VariableSets.ts +458 -0
  224. package/src/next/loader.ts +19 -5
  225. package/src/node/Host.ts +1 -2
  226. package/src/react-native/Host.ts +6 -6
  227. package/src/react-native/StyleSheet.ts +49 -42
  228. package/src/react-native/Variants.ts +3 -3
  229. package/src/react-native/react.ts +6 -6
  230. package/src/rollup/index.ts +5 -0
  231. package/src/runtime/Appearance.ts +20 -20
  232. package/src/runtime/Dynamic.ts +4 -1
  233. package/src/runtime/NativeContext.ts +8 -8
  234. package/src/runtime/NativeDynamic.ts +2 -4
  235. package/src/runtime/Props.ts +3 -3
  236. package/src/runtime/Selection.ts +44 -33
  237. package/src/styleFunction.ts +22 -19
  238. package/src/unplugin/index.ts +600 -0
  239. package/src/variants.ts +7 -5
  240. package/src/vite/index.ts +5 -4
  241. package/src/web/Css.ts +10 -7
  242. package/src/web/internal/Themes.ts +52 -9
  243. package/src/webpack/index.ts +5 -0
  244. package/dist/Theme.d.ts.map +0 -1
  245. package/dist/Theme.js.map +0 -1
  246. package/dist/compiler/internal/Variables.d.ts.map +0 -1
  247. package/dist/compiler/internal/Variables.js.map +0 -1
package/src/Config.ts CHANGED
@@ -1,691 +1,49 @@
1
- /**
2
- * Normalizes explicit configuration into isolated typed authoring contracts.
3
- * @module
4
- */
5
- import * as Appearance from './runtime/Appearance.js'
6
- import * as Authoring from './internal/Authoring.js'
7
- import * as Html from './runtime/CompositionHtml.js'
8
- import * as Identity from './internal/Identity.js'
9
- import type * as Binding from './internal/Binding.js'
10
- import type * as Condition from './internal/Condition.js'
11
- import type * as Literal from './internal/Literal.js'
12
- import type { style } from './styleFunction.js'
13
- import { variants } from './variants.js'
14
- import * as Scheme from './internal/Scheme.js'
15
- import * as Shorthands from './internal/Shorthands.js'
16
- import type * as Style from './Style.js'
17
- import * as Theme from './Theme.js'
18
- import * as Token from './internal/Token.js'
19
-
20
- /** Creates token-free authoring without a configuration file or global state. */
21
- export function create(): create.ReturnType<{}>
22
- /**
23
- * Binds inline or reusable themes to an isolated configuration contract.
24
- * Named themes require an explicit default and identical token paths/domains.
25
- * Bound helpers reference extracted CSS; this factory emits no CSS rules.
26
- * @throws {InvalidError} If options, themes, defaults, or layer names are invalid.
27
- */
28
- export function create<const options extends create.Options>(
29
- options: options & NoInfer<Validated<options>>,
30
- ): create.ReturnType<options>
31
- export function create(options: create.Options = {}): unknown {
32
- const input = record(options)
33
-
34
- for (const key of Object.keys(input))
35
- if (
36
- ![
37
- 'cssOutput',
38
- 'id',
39
- 'defaultTheme',
40
- 'layers',
41
- 'output',
42
- 'shorthands',
43
- 'storageKey',
44
- 'theme',
45
- 'themes',
46
- ].includes(key)
47
- )
48
- throw new InvalidError(`Unknown configuration option: ${key}`)
49
-
50
- if (
51
- input.storageKey !== undefined &&
52
- (typeof input.storageKey !== 'string' || !input.storageKey)
53
- )
54
- throw new InvalidError('storageKey must be a nonempty string.')
55
-
56
- // Validated above; the record type erases the literal narrowing.
57
- const storageKey = input.storageKey as string | undefined
58
-
59
- if (
60
- input.output !== undefined &&
61
- input.output !== 'html' &&
62
- input.output !== 'react'
63
- )
64
- throw new InvalidError('output must be html or react.')
65
-
66
- if (
67
- input.cssOutput !== undefined &&
68
- input.cssOutput !== 'atomic' &&
69
- input.cssOutput !== 'grouped'
70
- )
71
- throw new InvalidError('cssOutput must be atomic or grouped.')
72
-
73
- if (input.theme !== undefined && input.themes !== undefined)
74
- throw new InvalidError('Use either theme or themes, not both.')
75
-
76
- if (input.layers !== undefined) {
77
- if (!Array.isArray(input.layers))
78
- throw new InvalidError('layers must be an array.')
79
-
80
- const seen = new Set<string>()
81
-
82
- for (const layer of input.layers) {
83
- if (
84
- typeof layer !== 'string' ||
85
- !/^(?:--|-?[_a-zA-Z])[\w-]*(?:\.(?:--|-?[_a-zA-Z])[\w-]*)*$/.test(
86
- layer,
87
- ) ||
88
- layer
89
- .split('.')
90
- .some((part) =>
91
- [
92
- 'default',
93
- 'inherit',
94
- 'initial',
95
- 'revert',
96
- 'revert-layer',
97
- 'unset',
98
- ].includes(part.toLowerCase()),
99
- )
100
- )
101
- throw new InvalidError(
102
- 'Layer names must be plain CSS identifiers, optionally dotted.',
103
- )
104
-
105
- if (seen.has(layer)) throw new InvalidError(`Duplicate layer: ${layer}`)
106
-
107
- seen.add(layer)
108
- }
109
- }
110
-
111
- const shorthands = (() => {
112
- if (input.shorthands === undefined) return undefined
113
-
114
- try {
115
- return Shorthands.read(input.shorthands)
116
- } catch (error) {
117
- throw new InvalidError((error as Error).message)
118
- }
119
- })()
120
-
121
- const contract = Object.freeze({
122
- cssOutput:
123
- (input.cssOutput as 'atomic' | 'grouped' | undefined) ?? 'atomic',
124
- ...(shorthands ? { shorthands } : {}),
125
- ...(typeof input.id === 'string'
126
- ? {
127
- [Token.identity]: Identity.requireId(input.id, 'Config.create'),
128
- [Token.complete]: true,
129
- }
130
- : {}),
131
- })
132
- function boundStyle(theme?: Theme.Definition) {
133
- return (styles?: unknown, options: style.DefinitionOptions = {}) => {
134
- if (
135
- theme &&
136
- Object.keys(theme[Token.definition].values).length &&
137
- !contract[Token.identity]
1
+ /** Binds shared vars, property mappings, and scoped alternatives to authoring. @module */
2
+ import type * as Shorthands from './internal/Shorthands.js'
3
+ import * as Configuration from './internal/Configuration.js'
4
+
5
+ export { InvalidError } from './internal/Configuration.js'
6
+ export type {
7
+ Body,
8
+ StyleFactory,
9
+ VariableConfig,
10
+ VariableOptions,
11
+ VariableScope,
12
+ } from './internal/Configuration.js'
13
+
14
+ /** Creates isolated authoring with optional vars and named alternatives. */
15
+ export function create<const options extends create.Options = {}>(
16
+ options: options &
17
+ NoInfer<
18
+ options extends Configuration.VariableOptions
19
+ ? Configuration.VariableValidation<options>
20
+ : Record<Exclude<keyof options, keyof create.Options>, never> &
21
+ (options extends { shorthands: infer map extends Shorthands.Map }
22
+ ? { shorthands: Shorthands.Validated<map> }
23
+ : {})
24
+ > = {} as never,
25
+ ): create.ReturnType<options> {
26
+ for (const key of ['theme', 'themes', 'defaultTheme'])
27
+ if (Object.hasOwn(options, key))
28
+ throw new Configuration.InvalidError(
29
+ `Use vars and defaultVars instead of ${key}.`,
138
30
  )
139
- Identity.requireId(undefined, 'Config.create')
140
- return Authoring.create(styles, {
141
- ...options,
142
- theme,
143
- output: input.output as style.Output | undefined,
144
- })
145
- }
146
- }
147
- function boundVariants(
148
- definition: Record<string, unknown>,
149
- options: style.DefinitionOptions = {},
150
- ) {
151
- return Authoring.variants(definition, {
152
- ...options,
153
- output: input.output as style.Output | undefined,
154
- })
155
- }
156
- function handle(theme: Theme.Definition, name: string) {
157
- const original = Token.bind(theme, contract)
158
- const className = () =>
159
- `z_theme-${Identity.requireId(typeof input.id === 'string' ? input.id : undefined, 'Config.create')}-${name.replace(/[^a-zA-Z0-9-]/g, (character) => `_${character.charCodeAt(0).toString(16)}_`)}`
160
- const select = (options: { colorScheme?: string } = {}) => {
161
- const scheme = options.colorScheme
162
- const selection =
163
- scheme !== undefined && Object.hasOwn(Scheme.classes, scheme)
164
- ? ` ${Scheme.classes[scheme as Scheme.Name]}`
165
- : ''
166
- const result = {
167
- className: `${className()}${selection}`,
168
- ...(scheme ? { style: { colorScheme: scheme } } : {}),
169
- }
170
- return input.output === 'html' ? Html.from(result) : result
171
- }
172
- const descriptors = Object.getOwnPropertyDescriptors(original)
173
- delete (descriptors as Record<string, unknown>).className
174
- delete (descriptors as Record<string, unknown>).style
175
- delete (descriptors as Record<string, unknown>).variants
176
- Object.defineProperties(select, descriptors)
177
- Object.defineProperty(select, 'className', {
178
- get: className,
179
- configurable: true,
180
- })
181
- Object.assign(select, {
182
- style: boundStyle(original),
183
- variants: boundVariants,
184
- })
185
- return select
186
- }
187
-
188
- if (input.themes !== undefined) {
189
- const catalog = record(input.themes)
190
- if (
191
- typeof input.defaultTheme !== 'string' ||
192
- !Object.hasOwn(catalog, input.defaultTheme)
193
- )
194
- throw new InvalidError('defaultTheme must name a theme in the catalog.')
195
-
196
- const defaultTheme = input.defaultTheme
197
- const definitions = Object.fromEntries(
198
- Object.entries(catalog).map(([name, value]) => {
199
- if (!name) throw new InvalidError('Theme names must be nonempty.')
200
-
201
- return [name, definition(value)]
202
- }),
203
- )
204
-
205
- const base = definitions[input.defaultTheme]!
206
- const paths = Object.keys(base[Token.definition].values).sort()
207
-
208
- function queries(theme: Theme.Definition) {
209
- const data = theme[Token.definition].queries
210
-
211
- return JSON.stringify({
212
- breakpoints: Object.keys(data?.breakpoints ?? {}).sort(),
213
- containers: Object.keys(data?.containers ?? {}).sort(),
214
- containerNames: [...(data?.containerNames ?? [])].sort(),
215
- })
216
- }
217
-
218
- for (const [name, value] of Object.entries(definitions)) {
219
- const candidate = Object.keys(value[Token.definition].values).sort()
220
- if (
221
- queries(base) !== queries(value) ||
222
- paths.length !== candidate.length ||
223
- paths.some((path, index) => path !== candidate[index])
224
- )
225
- throw new InvalidError(
226
- `Theme ${JSON.stringify(name)} must have the default theme's complete token paths and domains.`,
227
- )
228
- }
229
-
230
- const bound = Object.fromEntries(
231
- Object.entries(definitions).map(([name, value]) => [
232
- name,
233
- handle(value, name),
234
- ]),
235
- )
236
-
237
- const select = (options: { theme: string; colorScheme?: string }) =>
238
- (bound[options.theme] as (options: { colorScheme?: string }) => unknown)(
239
- options,
240
- )
241
-
242
- Object.defineProperties(select, Object.getOwnPropertyDescriptors(bound))
243
-
244
- const entries = () =>
245
- Object.entries(bound).map(([name, value]): readonly [string, string] => [
246
- name,
247
- (value as unknown as Theme.Definition).className,
248
- ])
249
-
250
- // Class names require an identity, so the compiler's collection pass must
251
- // not read them; root controls resolve their entries on first use.
252
- const appearance = ((): Appearance.Root<string> => {
253
- let root: Appearance.Root<string> | undefined
254
- const resolve = () =>
255
- (root ??= Appearance.root(entries(), { defaultTheme, storageKey }))
256
-
257
- return {
258
- get: () => resolve().get(),
259
- set: (selection) => resolve().set(selection),
260
- }
261
- })()
262
-
263
- return Object.freeze({
264
- appearance,
265
- script: () => Appearance.create(entries(), { storageKey })(),
266
- style: boundStyle(
267
- bound[input.defaultTheme] as unknown as Theme.Definition,
268
- ),
269
- theme: bound[input.defaultTheme],
270
- themes: Object.freeze(select),
271
- variants: boundVariants,
272
- })
273
- }
274
-
275
- if (input.defaultTheme !== undefined)
276
- throw new InvalidError('defaultTheme requires a named themes catalog.')
277
-
278
- if (input.theme !== undefined) {
279
- const theme = handle(definition(input.theme), 'theme')
280
- return Object.freeze({
281
- appearance: Appearance.root([], { storageKey }),
282
- script: Appearance.create([], { storageKey }),
283
- style: boundStyle(theme as unknown as Theme.Definition),
284
- theme,
285
- variants: boundVariants,
286
- })
287
- }
288
-
289
- const theme = shorthands ? Token.bind(Theme.define({}), contract) : undefined
290
- return Object.freeze({
291
- appearance: Appearance.root([], { storageKey }),
292
- script: Appearance.create([], { storageKey }),
293
- style: boundStyle(theme),
294
- variants: boundVariants,
295
- })
31
+ return Configuration.create(
32
+ options as Configuration.VariableOptions,
33
+ ) as create.ReturnType<options>
296
34
  }
297
35
 
298
- /** Configuration inputs and inferred results. */
36
+ /** Configuration input and inferred helpers. */
299
37
  export declare namespace create {
300
- /** Optional layer names and mutually exclusive theme modes. */
301
- type Options = {
302
- /** CSS representation inherited by bound helpers; atomic by default. */
303
- readonly cssOutput?: 'atomic' | 'grouped' | undefined
304
- /** Stable theme identity required without source rewriting. */
305
- readonly id?: string | undefined
306
- /** Explicit ordered property aliases; none are installed by default. */
307
- readonly shorthands?: Shorthands.Map | undefined
308
- /** Renderer props format; React is the default. */
309
- readonly output?: style.Output | undefined
310
- /** Ordered plain or dotted CSS layer names; emission follows source integration. */
311
- readonly layers?: readonly string[] | undefined
312
- /** localStorage key shared by `script()` and `appearance`; zyzz by default. */
313
- readonly storageKey?: string | undefined
314
- } & (
315
- | {
316
- /** Single inline or reusable theme. */ readonly theme: Input
317
- /** Named mode is excluded. */ readonly themes?: never
318
- /** Only named catalogs use defaults. */ readonly defaultTheme?: never
319
- }
320
- | {
321
- /** Explicit catalog key. */ readonly defaultTheme: string
322
- /** Single mode is excluded. */ readonly theme?: never
323
- /** Complete named theme alternatives. */ readonly themes: Readonly<
324
- Record<string, Input>
325
- >
326
- }
327
- | {
328
- /** Only named catalogs use defaults. */ readonly defaultTheme?: never
329
- /** Omit themes for token-free authoring. */ readonly theme?: never
330
- /** Omit themes for token-free authoring. */ readonly themes?: never
331
- }
332
- )
333
-
334
- /** Bound authoring and the handles corresponding to the selected theme mode. */
335
- type ReturnType<options extends Options = Options> = {
336
- /** Reads and persists the root theme and scheme selection on the document element. */
337
- readonly appearance: Appearance.Root<
338
- options extends { themes: infer catalog } ? keyof catalog & string : never
339
- >
340
- /** Generates synchronous HTML-safe root preference restoration. */
341
- readonly script: () => string
342
- /** Inferred callable authoring; execution requires a source transform. */
343
- readonly style: StyleFactory<
344
- Tokens<options>,
345
- options extends { layers: readonly (infer name extends string)[] }
346
- ? name
347
- : never,
348
- options extends { output: infer output extends style.Output }
349
- ? output
350
- : 'react',
351
- Mappings<options>
352
- >
353
- /** Theme-, layer-, and mapping-aware recipe authoring. */
354
- readonly variants: variants.Bound<
355
- Tokens<options>,
356
- options extends { output: infer output extends style.Output }
357
- ? output
358
- : 'react',
359
- options extends { layers: readonly (infer name extends string)[] }
360
- ? name
361
- : never,
362
- Mappings<options>
363
- >
364
- } & (options extends { theme: infer input }
365
- ? {
366
- /** Isolated single-theme contract. */ readonly theme: Handle<
367
- ExtractTokens<input>,
368
- Mappings<options>,
369
- options extends { output: infer output extends style.Output }
370
- ? output
371
- : 'react'
38
+ /** Variable sets and optional authoring settings. */
39
+ type Options =
40
+ | Configuration.VariableOptions
41
+ | Omit<Configuration.VariableOptions, 'vars' | 'defaultVars' | 'mappings'>
42
+ /** Typed helpers selected by the supplied variable contract. */
43
+ type ReturnType<options extends Options = Options> =
44
+ options extends Configuration.VariableOptions
45
+ ? Configuration.VariableConfig<options>
46
+ : Configuration.create.ReturnType<
47
+ Extract<options, Configuration.create.Options>
372
48
  >
373
- }
374
- : options extends { themes: infer catalog }
375
- ? {
376
- /** Shared default token and variable contract. */ readonly theme: Handle<
377
- Tokens<options>,
378
- Mappings<options>,
379
- options extends { output: infer output extends style.Output }
380
- ? output
381
- : 'react'
382
- >
383
- /** Selects a compiled named scope; catalog members retain compatibility. */ readonly themes: (<
384
- const selection extends {
385
- readonly colorScheme?: 'dark' | 'light' | 'light dark' | undefined
386
- readonly theme: keyof catalog & string
387
- },
388
- >(
389
- options: selection &
390
- Record<Exclude<keyof selection, 'theme' | 'colorScheme'>, never>,
391
- ) => style.Props<
392
- options extends { output: infer output extends style.Output }
393
- ? output
394
- : 'react'
395
- >) & {
396
- readonly [name in keyof catalog]: Handle<
397
- ExtractTokens<catalog[name]>,
398
- Mappings<options>,
399
- options extends { output: infer output extends style.Output }
400
- ? output
401
- : 'react'
402
- >
403
- }
404
- }
405
- : {})
406
- }
407
-
408
- type Mappings<options> = options extends {
409
- shorthands: infer map extends Shorthands.Map
410
- }
411
- ? string extends keyof map
412
- ? {}
413
- : map
414
- : {}
415
-
416
- /** Theme handle retaining configured shorthands and renderer output in emitted declarations. */
417
- export type Handle<
418
- tokens extends Theme.Tokens,
419
- mappings extends Shorthands.Map,
420
- output extends style.Output,
421
- > = Omit<Theme.Definition<tokens>, 'style' | 'variants'> & {
422
- /** Style factory bound to this handle. */
423
- readonly style: StyleFactory<tokens, never, output, mappings>
424
- /** Variant factory bound to this handle. */
425
- readonly variants: variants.Bound<tokens, output, never, mappings>
426
- }
427
-
428
- /** Configured style factory with a portable name for library declaration emission. */
429
- export type StyleFactory<
430
- tokens extends Theme.Tokens,
431
- layers extends string,
432
- output extends style.Output,
433
- mappings extends Shorthands.Map,
434
- > = {
435
- (): style.ReturnType<output>
436
- <
437
- const values extends Record<string, string | number>,
438
- const styles extends Record<string, unknown>,
439
- const callback extends (...args: never[]) => unknown,
440
- >(
441
- styles: callback &
442
- ((
443
- values: values,
444
- ) => styles &
445
- NoInfer<
446
- Body<styles, tokens, layers, mappings> & Binding.Checked<styles>
447
- >) &
448
- CompletionProperties<tokens, NoInfer<styles>>,
449
- ...options: Parameters<callback> extends [Record<string, string | number>]
450
- ? values extends Binding.Inputs<values>
451
- ? [options?: style.DefinitionOptions]
452
- : [invalid: never, unavailable: never]
453
- : [invalid: never, unavailable: never]
454
- ): style.Dynamic<values, output>
455
- <const styles extends Record<string, unknown>>(
456
- styles: styles &
457
- NoInfer<Body<styles, tokens, layers, mappings>> &
458
- CompletionProperties<tokens>,
459
- options?: style.DefinitionOptions,
460
- ): style.ReturnType<output>
461
- }
462
-
463
- type Keys<styles> = styles extends unknown ? keyof styles : never
464
-
465
- /** Keeps completion hints separate from inferred declaration validation. */
466
- type CompletionProperties<tokens, styles = Record<string, unknown>> = {
467
- readonly [property in keyof Literal.Properties & keyof styles]?:
468
- | (string extends Literal.Properties[property]
469
- ? never
470
- : Literal.Properties[property])
471
- | Token.Names<tokens, property>
472
- | (string & {})
473
- | number
474
- | object
475
- }
476
-
477
- /** Checked declaration body shared by configured styles and recipe choices. */
478
- export type Body<
479
- styles,
480
- tokens extends Theme.Tokens,
481
- layers extends string,
482
- mappings extends Shorthands.Map,
483
- targets extends boolean = true,
484
- > = Record<
485
- Exclude<
486
- Keys<styles>,
487
- | keyof mappings
488
- | 'selectors'
489
- | 'targets'
490
- | 'typography'
491
- | 'variables'
492
- | keyof Style.DeclarationProperties
493
- | Exclude<Condition.Keys<tokens, Keys<styles>>, `@layer${string}`>
494
- | '@layer'
495
- | `@layer ${layers}`
496
- >,
497
- never
498
- > &
499
- (styles extends unknown
500
- ? {
501
- [key in keyof styles]: key extends 'targets'
502
- ? targets extends false
503
- ? never
504
- : styles[key] extends undefined
505
- ? undefined
506
- : {
507
- [target in keyof styles[key]]: target extends 'web'
508
- ?
509
- | Body<
510
- NonNullable<styles[key][target]>,
511
- tokens,
512
- layers,
513
- mappings,
514
- false
515
- >
516
- | Extract<styles[key][target], undefined>
517
- : Style.Accepted<
518
- { targets: Pick<styles[key], target> },
519
- tokens
520
- >['targets'][target]
521
- }
522
- : key extends 'selectors'
523
- ? styles[key] extends Record<string, unknown>
524
- ? {
525
- [selector in keyof styles[key]]: styles[key][selector] extends Record<
526
- string,
527
- unknown
528
- >
529
- ? Body<
530
- styles[key][selector],
531
- tokens,
532
- layers,
533
- mappings,
534
- targets
535
- >
536
- : never
537
- }
538
- : never
539
- : key extends
540
- | Exclude<Condition.Keys<tokens, key>, `@layer${string}`>
541
- | '@layer'
542
- | `@layer ${layers}`
543
- ? styles[key] extends Record<string, unknown>
544
- ? Body<styles[key], tokens, layers, mappings, targets>
545
- : never
546
- : key extends keyof mappings
547
- ? {
548
- [target in mappings[key][number]]: styles[key] extends Style.Accepted<
549
- Record<target, styles[key]>,
550
- tokens
551
- >[target] &
552
- Binding.Checked<Record<target, styles[key]>>[target]
553
- ? never
554
- : target
555
- }[mappings[key][number]] extends never
556
- ? styles[key]
557
- : never
558
- : Style.Accepted<Pick<styles, key>, tokens>[key]
559
- }
560
- : never)
561
-
562
- function definition(value: unknown): Theme.Definition {
563
- try {
564
- if (
565
- value &&
566
- typeof value === 'object' &&
567
- Object.getOwnPropertyDescriptor(value, Token.definition)?.value
568
- )
569
- return value as Theme.Definition
570
-
571
- return Theme.define(record(value) as Theme.Tokens)
572
- } catch (error) {
573
- if (error instanceof InvalidError) throw error
574
-
575
- throw new InvalidError((error as Error).message)
576
- }
577
- }
578
-
579
- type ExtractTokens<input> =
580
- input extends Theme.Definition<infer tokens>
581
- ? tokens
582
- : input extends Theme.Tokens
583
- ? input
584
- : never
585
-
586
- type Input = Theme.Definition | Theme.Tokens
587
-
588
- /** Invalid options or incompatible named themes. */
589
- export class InvalidError extends Error {
590
- /** Creates a configuration diagnostic without generating styles. */
591
- constructor(message: string) {
592
- super(message)
593
- }
594
- /** Stable namespaced error identifier. */
595
- override name = 'Config.InvalidError'
596
- }
597
-
598
- function record(value: unknown): Record<string, unknown> {
599
- if (
600
- !value ||
601
- typeof value !== 'object' ||
602
- Array.isArray(value) ||
603
- ![null, Object.prototype].includes(Object.getPrototypeOf(value))
604
- )
605
- throw new InvalidError('Expected a plain configuration record.')
606
-
607
- const result: Record<string, unknown> = Object.create(null)
608
-
609
- for (const [key, descriptor] of Object.entries(
610
- Object.getOwnPropertyDescriptors(value),
611
- )) {
612
- if (!('value' in descriptor))
613
- throw new InvalidError('Configuration records cannot contain accessors.')
614
-
615
- result[key] = descriptor.value
616
- }
617
-
618
- return result
619
49
  }
620
-
621
- type Tokens<options> = options extends { theme: infer input }
622
- ? ExtractTokens<input>
623
- : options extends { themes: infer catalog; defaultTheme: infer key }
624
- ? key extends keyof catalog
625
- ? ExtractTokens<catalog[key]>
626
- : never
627
- : {}
628
-
629
- type ValidInput<input> = input extends Theme.Definition
630
- ? input
631
- : input extends Theme.Tokens
632
- ? Parameters<typeof Theme.define<input>>[0]
633
- : never
634
-
635
- type Match<input, base> = base extends
636
- | string
637
- | number
638
- | { light: string; dark: string }
639
- ? input
640
- : {
641
- [key in keyof input | keyof base]: key extends keyof input
642
- ? key extends keyof base
643
- ? key extends 'containerNames'
644
- ? input[key] extends readonly string[]
645
- ? base[key] extends readonly string[]
646
- ?
647
- | Exclude<input[key][number], base[key][number]>
648
- | Exclude<
649
- base[key][number],
650
- input[key][number]
651
- > extends never
652
- ? input[key]
653
- : never
654
- : never
655
- : never
656
- : Match<input[key], base[key]>
657
- : never
658
- : never
659
- }
660
-
661
- type Validated<options> = Record<
662
- Exclude<keyof options, keyof create.Options>,
663
- never
664
- > &
665
- (options extends { shorthands: infer mappings extends Shorthands.Map }
666
- ? { shorthands: Shorthands.Validated<mappings> }
667
- : {}) &
668
- (options extends { theme: infer input }
669
- ? { theme: ValidInput<input> }
670
- : options extends { themes: infer catalog; defaultTheme: infer key }
671
- ? {
672
- defaultTheme: keyof catalog
673
- themes: {
674
- [name in keyof catalog]: ValidInput<catalog[name]> &
675
- (key extends keyof catalog
676
- ? catalog[name] extends Theme.Definition
677
- ? Theme.Definition<
678
- ExtractTokens<catalog[name]> &
679
- Match<
680
- ExtractTokens<catalog[name]>,
681
- ExtractTokens<catalog[key]>
682
- >
683
- >
684
- : Match<
685
- ExtractTokens<catalog[name]>,
686
- ExtractTokens<catalog[key]>
687
- >
688
- : never)
689
- }
690
- }
691
- : {})