zyzz 0.0.19 → 0.0.21

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 (167) hide show
  1. package/README.md +9 -9
  2. package/dist/Config.d.ts +1 -0
  3. package/dist/Config.d.ts.map +1 -1
  4. package/dist/Config.js.map +1 -1
  5. package/dist/Style.d.ts +7 -0
  6. package/dist/Style.d.ts.map +1 -1
  7. package/dist/Style.js +1 -5
  8. package/dist/Style.js.map +1 -1
  9. package/dist/Vars.d.ts +22 -15
  10. package/dist/Vars.d.ts.map +1 -1
  11. package/dist/Vars.js +26 -0
  12. package/dist/Vars.js.map +1 -1
  13. package/dist/cli/index.js +5 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/compiler/Graph.d.ts +3 -0
  16. package/dist/compiler/Graph.d.ts.map +1 -1
  17. package/dist/compiler/Graph.js +44 -37
  18. package/dist/compiler/Graph.js.map +1 -1
  19. package/dist/compiler/Source.d.ts +4 -0
  20. package/dist/compiler/Source.d.ts.map +1 -1
  21. package/dist/compiler/Source.js +66 -6
  22. package/dist/compiler/Source.js.map +1 -1
  23. package/dist/compiler/Transform.d.ts +4 -1
  24. package/dist/compiler/Transform.d.ts.map +1 -1
  25. package/dist/compiler/Transform.js +32 -46
  26. package/dist/compiler/Transform.js.map +1 -1
  27. package/dist/compiler/internal/Catalogs.d.ts.map +1 -1
  28. package/dist/compiler/internal/Catalogs.js +6 -1
  29. package/dist/compiler/internal/Catalogs.js.map +1 -1
  30. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  31. package/dist/compiler/internal/Compositions.js +5 -0
  32. package/dist/compiler/internal/Compositions.js.map +1 -1
  33. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  34. package/dist/compiler/internal/Configurations.js +5 -1
  35. package/dist/compiler/internal/Configurations.js.map +1 -1
  36. package/dist/compiler/internal/Contract.d.ts +4 -1
  37. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  38. package/dist/compiler/internal/Contract.js +73 -138
  39. package/dist/compiler/internal/Contract.js.map +1 -1
  40. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  41. package/dist/compiler/internal/Contributions.js +1 -3
  42. package/dist/compiler/internal/Contributions.js.map +1 -1
  43. package/dist/compiler/internal/Dynamic.d.ts +1 -1
  44. package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
  45. package/dist/compiler/internal/Dynamic.js +5 -5
  46. package/dist/compiler/internal/Dynamic.js.map +1 -1
  47. package/dist/compiler/internal/Names.d.ts +5 -0
  48. package/dist/compiler/internal/Names.d.ts.map +1 -0
  49. package/dist/compiler/internal/Names.js +37 -0
  50. package/dist/compiler/internal/Names.js.map +1 -0
  51. package/dist/compiler/internal/Selectors.d.ts +1 -1
  52. package/dist/compiler/internal/Selectors.d.ts.map +1 -1
  53. package/dist/compiler/internal/Selectors.js +5 -2
  54. package/dist/compiler/internal/Selectors.js.map +1 -1
  55. package/dist/compiler/internal/Stylesheets.js +2 -2
  56. package/dist/compiler/internal/Stylesheets.js.map +1 -1
  57. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  58. package/dist/compiler/internal/Themes.js +85 -24
  59. package/dist/compiler/internal/Themes.js.map +1 -1
  60. package/dist/compiler/internal/Vars.d.ts +2 -0
  61. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  62. package/dist/compiler/internal/Vars.js +7 -1
  63. package/dist/compiler/internal/Vars.js.map +1 -1
  64. package/dist/default.d.ts +11 -15
  65. package/dist/default.d.ts.map +1 -1
  66. package/dist/default.js +13 -14
  67. package/dist/default.js.map +2 -2
  68. package/dist/default.js.zyzz.json +1 -1
  69. package/dist/index.d.ts +15 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +15 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/internal/Authoring.d.ts.map +1 -1
  74. package/dist/internal/Authoring.js +8 -3
  75. package/dist/internal/Authoring.js.map +1 -1
  76. package/dist/internal/Binding.d.ts +4 -0
  77. package/dist/internal/Binding.d.ts.map +1 -1
  78. package/dist/internal/Binding.js +2 -0
  79. package/dist/internal/Binding.js.map +1 -1
  80. package/dist/internal/Configuration.d.ts +2 -2
  81. package/dist/internal/Configuration.d.ts.map +1 -1
  82. package/dist/internal/Configuration.js +4 -2
  83. package/dist/internal/Configuration.js.map +1 -1
  84. package/dist/internal/Identity.d.ts +3 -3
  85. package/dist/internal/Identity.d.ts.map +1 -1
  86. package/dist/internal/Identity.js +11 -9
  87. package/dist/internal/Identity.js.map +1 -1
  88. package/dist/internal/Theme.js +2 -2
  89. package/dist/internal/Theme.js.map +1 -1
  90. package/dist/internal/Token.d.ts +16 -3
  91. package/dist/internal/Token.d.ts.map +1 -1
  92. package/dist/internal/Token.js +11 -2
  93. package/dist/internal/Token.js.map +1 -1
  94. package/dist/internal/VariableSets.d.ts.map +1 -1
  95. package/dist/internal/VariableSets.js +19 -2
  96. package/dist/internal/VariableSets.js.map +1 -1
  97. package/dist/node/Host.d.ts +2 -0
  98. package/dist/node/Host.d.ts.map +1 -1
  99. package/dist/node/Host.js +9 -0
  100. package/dist/node/Host.js.map +1 -1
  101. package/dist/react-native/StyleSheet.js +2 -0
  102. package/dist/react-native/StyleSheet.js.map +1 -1
  103. package/dist/runtime/Composition.d.ts +1 -1
  104. package/dist/runtime/ConditionalRecipe.d.ts +1 -1
  105. package/dist/runtime/PayloadRecipe.d.ts +1 -1
  106. package/dist/runtime/Recipe.d.ts +1 -1
  107. package/dist/styleFunction.d.ts +1 -1
  108. package/dist/styleFunction.d.ts.map +1 -1
  109. package/dist/styleFunction.js.map +1 -1
  110. package/dist/variable.js +1 -1
  111. package/dist/variable.js.map +1 -1
  112. package/dist/variants.d.ts +14 -6
  113. package/dist/variants.d.ts.map +1 -1
  114. package/dist/variants.js.map +1 -1
  115. package/dist/vite/index.d.ts +2 -0
  116. package/dist/vite/index.d.ts.map +1 -1
  117. package/dist/vite/index.js +111 -42
  118. package/dist/vite/index.js.map +1 -1
  119. package/dist/web/Css.d.ts +7 -2
  120. package/dist/web/Css.d.ts.map +1 -1
  121. package/dist/web/Css.js +46 -39
  122. package/dist/web/Css.js.map +1 -1
  123. package/dist/web/internal/ClassName.d.ts +13 -2
  124. package/dist/web/internal/ClassName.d.ts.map +1 -1
  125. package/dist/web/internal/ClassName.js +17 -30
  126. package/dist/web/internal/ClassName.js.map +1 -1
  127. package/dist/web/internal/Themes.d.ts +3 -0
  128. package/dist/web/internal/Themes.d.ts.map +1 -1
  129. package/dist/web/internal/Themes.js +52 -24
  130. package/dist/web/internal/Themes.js.map +1 -1
  131. package/package.json +1 -1
  132. package/src/Config.ts +5 -0
  133. package/src/Style.ts +4 -1
  134. package/src/Vars.ts +88 -29
  135. package/src/cli/index.ts +5 -0
  136. package/src/compiler/Graph.ts +60 -46
  137. package/src/compiler/Source.ts +86 -5
  138. package/src/compiler/Transform.ts +42 -60
  139. package/src/compiler/internal/Catalogs.ts +9 -1
  140. package/src/compiler/internal/Compositions.ts +7 -0
  141. package/src/compiler/internal/Configurations.ts +5 -1
  142. package/src/compiler/internal/Contract.ts +104 -239
  143. package/src/compiler/internal/Contributions.ts +1 -5
  144. package/src/compiler/internal/Dynamic.ts +14 -9
  145. package/src/compiler/internal/Names.ts +48 -0
  146. package/src/compiler/internal/Selectors.ts +6 -1
  147. package/src/compiler/internal/Stylesheets.ts +2 -2
  148. package/src/compiler/internal/Themes.ts +115 -35
  149. package/src/compiler/internal/Vars.ts +9 -1
  150. package/src/default.ts +17 -20
  151. package/src/index.ts +15 -0
  152. package/src/internal/Authoring.ts +9 -3
  153. package/src/internal/Binding.ts +5 -0
  154. package/src/internal/Configuration.ts +7 -4
  155. package/src/internal/Identity.ts +14 -12
  156. package/src/internal/Theme.ts +2 -2
  157. package/src/internal/Token.ts +52 -12
  158. package/src/internal/VariableSets.ts +26 -2
  159. package/src/node/Host.ts +22 -0
  160. package/src/react-native/StyleSheet.ts +6 -0
  161. package/src/styleFunction.ts +1 -3
  162. package/src/variable.ts +1 -1
  163. package/src/variants.ts +38 -16
  164. package/src/vite/index.ts +137 -51
  165. package/src/web/Css.ts +83 -49
  166. package/src/web/internal/ClassName.ts +31 -36
  167. package/src/web/internal/Themes.ts +79 -29
@@ -144,6 +144,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
144
144
  const imports = new Set<number>()
145
145
  const variableImports = new Set<number>()
146
146
  const configImports = new Set<number>()
147
+ const factoryImports = new Map<number, 'create' | 'define' | 'extend'>()
147
148
  const configs = new Map<string, Link>()
148
149
  const configBindings = new Map<number, Link>()
149
150
  const factoryReferences = new Set<number>()
@@ -188,11 +189,31 @@ export function collect(program: Ast.Program, options: collect.Options) {
188
189
  : specifier.imported.value) === 'Config'
189
190
  )
190
191
  configImports.add(specifier.start)
192
+ else if (
193
+ specifier.type === 'ImportSpecifier' &&
194
+ specifier.importKind !== 'type' &&
195
+ ['defineConfig', 'defineVars', 'extendVars'].includes(
196
+ specifier.imported.type === 'Identifier'
197
+ ? specifier.imported.name
198
+ : specifier.imported.value,
199
+ )
200
+ ) {
201
+ const name =
202
+ specifier.imported.type === 'Identifier'
203
+ ? specifier.imported.name
204
+ : specifier.imported.value
205
+ if (name === 'defineConfig')
206
+ factoryImports.set(specifier.start, 'create')
207
+ else if (name === 'defineVars')
208
+ factoryImports.set(specifier.start, 'define')
209
+ else factoryImports.set(specifier.start, 'extend')
210
+ }
191
211
  }
192
212
 
193
213
  if (
194
214
  !imports.size &&
195
215
  !configImports.size &&
216
+ !factoryImports.size &&
196
217
  !Object.keys(options.links ?? {}).length
197
218
  )
198
219
  return undefined
@@ -251,6 +272,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
251
272
 
252
273
  const namespaces = new Set<string>()
253
274
  const configNamespaces = new Set<string>()
275
+ const factoryFunctions = new Map<string, 'create' | 'define' | 'extend'>()
254
276
  const variableNamespaces = new Set<string>()
255
277
  for (const node of program.body)
256
278
  if (node.type === 'ImportDeclaration')
@@ -264,6 +286,11 @@ export function collect(program: Ast.Program, options: collect.Options) {
264
286
  if (imports.has(specifier.start)) namespaces.add(specifier.local.name)
265
287
  else if (configImports.has(specifier.start))
266
288
  configNamespaces.add(specifier.local.name)
289
+ else if (factoryImports.has(specifier.start))
290
+ factoryFunctions.set(
291
+ specifier.local.name,
292
+ factoryImports.get(specifier.start)!,
293
+ )
267
294
 
268
295
  function resolve(node: Ast.Node): Link | undefined {
269
296
  if (node.type === 'Identifier') {
@@ -426,6 +453,35 @@ export function collect(program: Ast.Program, options: collect.Options) {
426
453
  if (node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression')
427
454
  return data(node.expression, derived)
428
455
 
456
+ if (node.type === 'CallExpression' && !node.optional) {
457
+ const callee = node.callee
458
+ if (
459
+ callee.type === 'MemberExpression' &&
460
+ !callee.computed &&
461
+ !callee.optional &&
462
+ callee.object.type === 'Identifier' &&
463
+ variableNamespaces.has(callee.object.name) &&
464
+ derived?.name !== callee.object.name &&
465
+ callee.property.type === 'Identifier' &&
466
+ callee.property.name === 'compose'
467
+ ) {
468
+ if (node.arguments.length !== 2)
469
+ return fail(
470
+ 'Vars.compose requires a literal domain and parts array.',
471
+ node,
472
+ )
473
+ const group = data(node.arguments[0]!, derived)
474
+ const parts = data(node.arguments[1]!, derived)
475
+ if ((group !== 'color' && group !== 'spacing') || !Array.isArray(parts))
476
+ return fail(
477
+ 'Vars.compose requires a literal domain and parts array.',
478
+ node,
479
+ )
480
+ factoryReferences.add(callee.start)
481
+ return Vars.compose(group, parts)
482
+ }
483
+ }
484
+
429
485
  if (
430
486
  node.type === 'Literal' &&
431
487
  (typeof node.value === 'string' || typeof node.value === 'number')
@@ -536,37 +592,52 @@ export function collect(program: Ast.Program, options: collect.Options) {
536
592
  registerAlias({ declaration, statement, variable })
537
593
 
538
594
  const expression = variable.init
539
- if (
540
- expression?.type !== 'CallExpression' ||
541
- expression.callee.type !== 'MemberExpression' ||
542
- expression.callee.object.type !== 'Identifier' ||
543
- (!namespaces.has(expression.callee.object.name) &&
544
- !configNamespaces.has(expression.callee.object.name))
545
- )
546
- continue
595
+ if (expression?.type !== 'CallExpression' || expression.optional) continue
547
596
 
548
597
  const member = expression.callee
598
+ const directFactory =
599
+ member.type === 'Identifier'
600
+ ? factoryFunctions.get(member.name)
601
+ : undefined
549
602
  if (
550
- member.computed ||
551
- member.optional ||
552
- expression.optional ||
553
- member.property.type !== 'Identifier' ||
554
- !(
555
- configNamespaces.has(expression.callee.object.name)
556
- ? ['create']
557
- : ['define', 'extend']
558
- ).includes(member.property.name)
603
+ !directFactory &&
604
+ (member.type !== 'MemberExpression' ||
605
+ member.object.type !== 'Identifier' ||
606
+ (!namespaces.has(member.object.name) &&
607
+ !configNamespaces.has(member.object.name)) ||
608
+ member.computed ||
609
+ member.optional ||
610
+ member.property.type !== 'Identifier' ||
611
+ !(
612
+ configNamespaces.has(member.object.name)
613
+ ? ['create']
614
+ : ['define', 'extend']
615
+ ).includes(member.property.name))
559
616
  )
560
617
  continue
561
618
 
619
+ const config =
620
+ directFactory === 'create' ||
621
+ (member.type === 'MemberExpression' &&
622
+ member.object.type === 'Identifier' &&
623
+ configNamespaces.has(member.object.name))
624
+ const method =
625
+ member.type === 'MemberExpression' &&
626
+ member.property.type === 'Identifier'
627
+ ? member.property.name
628
+ : directFactory
629
+ const variableSet =
630
+ directFactory === 'define' ||
631
+ directFactory === 'extend' ||
632
+ (member.type === 'MemberExpression' &&
633
+ member.object.type === 'Identifier' &&
634
+ variableNamespaces.has(member.object.name))
635
+
562
636
  if (
563
637
  (statement.type === 'ExportNamedDeclaration' && !options.linked) ||
564
638
  declaration.kind !== 'const' ||
565
639
  (variable.id.type !== 'Identifier' &&
566
- !(
567
- configNamespaces.has(expression.callee.object.name) &&
568
- variable.id.type === 'ObjectPattern'
569
- ))
640
+ !(config && variable.id.type === 'ObjectPattern'))
570
641
  )
571
642
  fail(
572
643
  'Define local themes with a module-level const; exported themes require source linking.',
@@ -601,10 +672,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
601
672
  fail('Configuration destructuring requires a binding.', variable)
602
673
 
603
674
  let name = `${options.namespace}-${binding}`
604
- if (
605
- !configNamespaces.has(expression.callee.object.name) &&
606
- member.property.name === 'define'
607
- ) {
675
+ if (!config && method === 'define') {
608
676
  const argument = expression.arguments[1]
609
677
  const callback = argument && Expression.unwrap(argument)
610
678
  const id = Identifiers.explicit(
@@ -617,7 +685,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
617
685
  if (id !== undefined) name = Identity.requireId(id, 'Vars.define')
618
686
  }
619
687
 
620
- if (configNamespaces.has(expression.callee.object.name)) {
688
+ if (config) {
621
689
  try {
622
690
  const link = Configurations.collect({
623
691
  data,
@@ -772,7 +840,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
772
840
  let output: Call['output']
773
841
 
774
842
  try {
775
- if (member.property.name === 'define') {
843
+ if (method === 'define') {
776
844
  if (
777
845
  expression.arguments.length < 1 ||
778
846
  expression.arguments.length > 3
@@ -786,9 +854,6 @@ export function collect(program: Ast.Program, options: collect.Options) {
786
854
 
787
855
  tokenType = type(expression.arguments[0]!)
788
856
 
789
- const variableSet = variableNamespaces.has(
790
- expression.callee.object.name,
791
- )
792
857
  const argument = expression.arguments[1]
793
858
  const callback = argument && Expression.unwrap(argument)
794
859
  if (
@@ -860,7 +925,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
860
925
  )
861
926
 
862
927
  factoryReferences.add(base!.start)
863
- definition = variableNamespaces.has(expression.callee.object.name)
928
+ definition = variableSet
864
929
  ? VariableSets.theme(
865
930
  Vars.extend(
866
931
  VariableSets.from(themes[parent.name]![Token.definition]),
@@ -876,7 +941,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
876
941
  'id-',
877
942
  )
878
943
  )
879
- name = definition.className.slice('z_theme-'.length)
944
+ name = definition.className.slice('z-theme-'.length)
880
945
  tokenType = parent.tokenType
881
946
  output = parent.output
882
947
  }
@@ -892,7 +957,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
892
957
  }
893
958
 
894
959
  const call = Object.freeze({
895
- ...(variableNamespaces.has(expression.callee.object.name)
960
+ ...(variableSet
896
961
  ? {
897
962
  variableSet: true,
898
963
  directVariables: true,
@@ -912,6 +977,11 @@ export function collect(program: Ast.Program, options: collect.Options) {
912
977
  : {}),
913
978
  })
914
979
 
980
+ definition = Token.bind(
981
+ definition,
982
+ definition[Token.definition].contract,
983
+ binding,
984
+ )
915
985
  calls.push(call)
916
986
  definitions.set(variable.id.start, call)
917
987
  factories.add(expression.start)
@@ -1286,12 +1356,22 @@ export function collect(program: Ast.Program, options: collect.Options) {
1286
1356
 
1287
1357
  if (
1288
1358
  binding?.type === 'Import' &&
1289
- (imports.has(binding.node.start) || configImports.has(binding.node.start))
1359
+ (imports.has(binding.node.start) ||
1360
+ configImports.has(binding.node.start) ||
1361
+ factoryImports.has(binding.node.start))
1290
1362
  ) {
1363
+ if (
1364
+ factoryImports.has(binding.node.start) &&
1365
+ parent.type === 'CallExpression' &&
1366
+ factories.has(parent.start)
1367
+ )
1368
+ return true
1369
+
1291
1370
  if (
1292
1371
  parent.type === 'MemberExpression' &&
1293
1372
  grandparent?.type === 'CallExpression' &&
1294
- factories.has(grandparent.start)
1373
+ (factories.has(grandparent.start) ||
1374
+ factoryReferences.has(parent.start))
1295
1375
  )
1296
1376
  return true
1297
1377
 
@@ -6,6 +6,7 @@ import * as Theme from '../../internal/Theme.js'
6
6
  import type * as Css from '../../web/Css.js'
7
7
  import * as Identity from '../../internal/Identity.js'
8
8
  import * as Expression from './Expression.js'
9
+ import * as Names from './Names.js'
9
10
  import type * as Scope from './Scope.js'
10
11
  import type * as Themes from './Themes.js'
11
12
  import { InvalidError } from './Themes.js'
@@ -14,6 +15,8 @@ import { InvalidError } from './Themes.js'
14
15
  export type Call = {
15
16
  /** Exclusive source offset. */
16
17
  readonly end: number
18
+ /** Whether the consumer supplied a portable variable identity. */
19
+ readonly explicit?: boolean | undefined
17
20
  /** Fixed scalar reference retained in portable metadata. */
18
21
  readonly slots: Readonly<Record<string, Binding.Reference>>
19
22
  /** Inclusive source offset. */
@@ -28,6 +31,7 @@ export function collect(
28
31
  links: Readonly<Record<string, Themes.Link>> = {},
29
32
  moduleId = namespace,
30
33
  ) {
34
+ const authoredNames = Names.collect(program)
31
35
  const imports = new Set<number>()
32
36
  const external = new Map<number, Themes.Link>()
33
37
  for (const statement of program.body) {
@@ -187,6 +191,7 @@ export function collect(
187
191
  })
188
192
 
189
193
  const calls: Call[] = []
194
+ const explicit = new Set<number>()
190
195
  const definitions = new Map<number, Themes.Link>()
191
196
  const registrations: Css.Contribution[] = []
192
197
  const registrationStarts: number[] = []
@@ -275,8 +280,10 @@ export function collect(
275
280
  descriptor[key] = literal as string | number | boolean
276
281
  }
277
282
 
283
+ if (descriptor.id !== undefined) explicit.add(call.start)
284
+
278
285
  const name =
279
- `--z-v${descriptor.id === undefined ? `${namespace}-${call.start}` : Identity.requireId(typeof descriptor.id === 'string' ? descriptor.id : undefined, 'variable')}` as const
286
+ `--z-${descriptor.id === undefined ? authoredNames.get(call.start)! : Identity.requireId(typeof descriptor.id === 'string' ? descriptor.id : undefined, 'variable').slice(3)}` as const
280
287
  if (value && Object.keys(descriptor).some((key) => key !== 'id')) {
281
288
  const syntax =
282
289
  kind === 'signedLength'
@@ -325,6 +332,7 @@ export function collect(
325
332
  variable: true as const,
326
333
  })
327
334
  const entry = Object.freeze({
335
+ explicit: explicit.has(call.start),
328
336
  start: call.start,
329
337
  end: call.end,
330
338
  slots: Object.freeze({ value: slot }),
package/src/default.ts CHANGED
@@ -41,11 +41,10 @@ void [spin, ping, pulse, bounce]
41
41
  */
42
42
  export const tokens = {
43
43
  animate: {
44
- spin: 'z-kid-7a-79-7a-7a-2d-73-70-69-6e 1s linear infinite',
45
- ping: 'z-kid-7a-79-7a-7a-2d-70-69-6e-67 1s cubic-bezier(0, 0, 0.2, 1) infinite',
46
- pulse:
47
- 'z-kid-7a-79-7a-7a-2d-70-75-6c-73-65 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
48
- bounce: 'z-kid-7a-79-7a-7a-2d-62-6f-75-6e-63-65 1s infinite',
44
+ spin: 'z-kid-zyzz_2d_spin 1s linear infinite',
45
+ ping: 'z-kid-zyzz_2d_ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
46
+ pulse: 'z-kid-zyzz_2d_pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
47
+ bounce: 'z-kid-zyzz_2d_bounce 1s infinite',
49
48
  },
50
49
  aspect: {
51
50
  video: '16 / 9',
@@ -80,8 +79,8 @@ export const tokens = {
80
79
  1000: { dark: '#fef3dc', light: '#4e2009' },
81
80
  },
82
81
  background: {
83
- 100: { dark: '#0a0a0a', light: '#fff' },
84
- 200: { dark: '#000', light: '#fafafa' },
82
+ primary: { dark: '#000', light: '#fafafa' },
83
+ surface: { dark: '#0a0a0a', light: '#fff' },
85
84
  },
86
85
  black: '#000',
87
86
  blue: {
@@ -169,7 +168,6 @@ export const tokens = {
169
168
  900: { dark: '#ff6166', light: '#cb2a2f' },
170
169
  1000: { dark: '#feecee', light: '#391417' },
171
170
  },
172
- surface: { dark: '#0a0a0a', light: '#fff' },
173
171
  teal: {
174
172
  100: { dark: '#04201b', light: '#eefcf9' },
175
173
  200: { dark: '#062822', light: '#e5faf6' },
@@ -428,14 +426,14 @@ export const tokens = {
428
426
  fontSize: '20px',
429
427
  fontWeight: 400,
430
428
  letterSpacing: '0px',
431
- lineHeight: '36px',
429
+ lineHeight: '28px',
432
430
  strong: {
433
431
  fontFamily:
434
432
  'Geist, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
435
433
  fontSize: '20px',
436
434
  fontWeight: 550,
437
435
  letterSpacing: '0px',
438
- lineHeight: '36px',
436
+ lineHeight: '28px',
439
437
  },
440
438
  },
441
439
  '24': {
@@ -681,13 +679,13 @@ export const tokens = {
681
679
  /** Default appearance, restoration script, and authoring helpers with bundled light/dark tokens. */
682
680
  // Generated from tokens by scripts/default-theme.ts; edit tokens and regenerate.
683
681
  const config = Config.create({
682
+ id: 'default',
684
683
  vars: {
685
684
  animate: {
686
- spin: 'z-kid-7a-79-7a-7a-2d-73-70-69-6e 1s linear infinite',
687
- ping: 'z-kid-7a-79-7a-7a-2d-70-69-6e-67 1s cubic-bezier(0, 0, 0.2, 1) infinite',
688
- pulse:
689
- 'z-kid-7a-79-7a-7a-2d-70-75-6c-73-65 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
690
- bounce: 'z-kid-7a-79-7a-7a-2d-62-6f-75-6e-63-65 1s infinite',
685
+ spin: 'z-kid-zyzz_2d_spin 1s linear infinite',
686
+ ping: 'z-kid-zyzz_2d_ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
687
+ pulse: 'z-kid-zyzz_2d_pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
688
+ bounce: 'z-kid-zyzz_2d_bounce 1s infinite',
691
689
  },
692
690
  aspect: {
693
691
  video: '16 / 9',
@@ -722,8 +720,8 @@ const config = Config.create({
722
720
  1000: { dark: '#fef3dc', light: '#4e2009' },
723
721
  },
724
722
  background: {
725
- 100: { dark: '#0a0a0a', light: '#fff' },
726
- 200: { dark: '#000', light: '#fafafa' },
723
+ primary: { dark: '#000', light: '#fafafa' },
724
+ surface: { dark: '#0a0a0a', light: '#fff' },
727
725
  },
728
726
  black: '#000',
729
727
  blue: {
@@ -811,7 +809,6 @@ const config = Config.create({
811
809
  900: { dark: '#ff6166', light: '#cb2a2f' },
812
810
  1000: { dark: '#feecee', light: '#391417' },
813
811
  },
814
- surface: { dark: '#0a0a0a', light: '#fff' },
815
812
  teal: {
816
813
  100: { dark: '#04201b', light: '#eefcf9' },
817
814
  200: { dark: '#062822', light: '#e5faf6' },
@@ -1070,14 +1067,14 @@ const config = Config.create({
1070
1067
  fontSize: '20px',
1071
1068
  fontWeight: 400,
1072
1069
  letterSpacing: '0px',
1073
- lineHeight: '36px',
1070
+ lineHeight: '28px',
1074
1071
  strong: {
1075
1072
  fontFamily:
1076
1073
  'Geist, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
1077
1074
  fontSize: '20px',
1078
1075
  fontWeight: 550,
1079
1076
  letterSpacing: '0px',
1080
- lineHeight: '36px',
1077
+ lineHeight: '28px',
1081
1078
  },
1082
1079
  },
1083
1080
  '24': {
package/src/index.ts CHANGED
@@ -8,6 +8,21 @@ export * as Config from './Config.js'
8
8
  export { style } from './styleFunction.js'
9
9
  /** Ordered composition of applied styling props. */
10
10
  export { cx } from './cx.js'
11
+ /**
12
+ * Creates isolated authoring with optional vars and named alternatives.
13
+ * @alias Config.create
14
+ */
15
+ export { create as defineConfig } from './Config.js'
16
+ /**
17
+ * Creates immutable typed variable sets without emitting CSS.
18
+ * @alias Vars.define
19
+ */
20
+ export { define as defineVars } from './Vars.js'
21
+ /**
22
+ * Overrides variable values while preserving their shared contract.
23
+ * @alias Vars.extend
24
+ */
25
+ export { extend as extendVars } from './Vars.js'
11
26
  /** Inferred component inputs from callable style definitions. */
12
27
  export type * as Props from './Props.js'
13
28
  /** Typed literal style definitions and validation diagnostics. */
@@ -3,6 +3,7 @@ import type { style } from '../styleFunction.js'
3
3
  import * as Html from '../runtime/CompositionHtml.js'
4
4
  import * as Identity from './Identity.js'
5
5
  import * as Props from '../runtime/Props.js'
6
+ import * as Token from './Token.js'
6
7
  import * as Style from '../Style.js'
7
8
  import type * as Theme from './Theme.js'
8
9
 
@@ -66,10 +67,12 @@ export function create(
66
67
  options: Options = {},
67
68
  ): style.ReturnType {
68
69
  const dynamic = typeof input === 'function'
70
+ const identity = options.theme?.[Token.definition].contract[Token.identity]
71
+ const namespace = identity?.startsWith('id-') ? identity.slice(3) : undefined
69
72
  const id =
70
73
  options.id === undefined
71
74
  ? undefined
72
- : Identity.requireId(options.id, 'style')
75
+ : `id-${namespace ? `${namespace}-` : ''}${Identity.requireId(options.id, 'style').slice(3)}`
73
76
  if (dynamic && !id) Identity.requireId(undefined, 'Dynamic style')
74
77
  if (!dynamic && !id && Object.keys(input as object).length === 0)
75
78
  Identity.requireId(undefined, 'Empty style')
@@ -90,6 +93,7 @@ export function create(
90
93
  { style: body(input as Record<string, unknown>) },
91
94
  { vars: options.theme },
92
95
  ).styles[0]!,
96
+ namespace,
93
97
  )
94
98
  const props = Props.create({ className })
95
99
  const apply = (values?: style.Options & Record<string, unknown>) => {
@@ -128,7 +132,9 @@ export function variants(
128
132
  input: Record<string, unknown>,
129
133
  options: Options = {},
130
134
  ): unknown {
131
- const id = Identity.requireId(options.id, 'variants')
135
+ const identity = options.theme?.[Token.definition].contract[Token.identity]
136
+ const namespace = identity?.startsWith('id-') ? identity.slice(3) : undefined
137
+ const id = `id-${namespace ? `${namespace}-` : ''}${Identity.requireId(options.id, 'variants').slice(3)}`
132
138
  if (options.theme) {
133
139
  const styles = [
134
140
  input.base,
@@ -157,7 +163,7 @@ export function variants(
157
163
  return (values: Record<string, unknown> & style.Options = {}) => {
158
164
  const result = { ...props(values as style.Options) } as {
159
165
  className: string
160
- style?: style.Props['style']
166
+ style?: NonNullable<style.Props['style']>
161
167
  [key: `data-${string}`]: string | undefined
162
168
  }
163
169
  const bindings: Record<string, string | number> = {}
@@ -15,10 +15,15 @@ export type Kind =
15
15
  | 'signedLength'
16
16
  | 'signedPercentage'
17
17
 
18
+ /** Marks callback inputs that require an explicit custom token escape. */
19
+ export const dynamic = Symbol('zyzz.binding.dynamic')
20
+
18
21
  /** A compiler-assigned web custom property with its scalar domain. */
19
22
  export type Reference<kind extends Domain = Domain> = {
20
23
  /** Fixed CSS custom-property name. */
21
24
  readonly name: `--${string}`
25
+ /** Internal callback provenance, independent of the emitted variable name. */
26
+ readonly [dynamic]?: true | undefined
22
27
  /** Scalar domain used by authoring types and runtime primitive checks. */
23
28
  readonly type: kind
24
29
  /** Distinguishes slots from theme references. */
@@ -163,6 +163,9 @@ export function create(
163
163
  )
164
164
  throw new InvalidError(`Unknown configuration option: ${key}`)
165
165
 
166
+ if (input.id !== undefined && (typeof input.id !== 'string' || !input.id))
167
+ throw new InvalidError('id must be a nonempty string.')
168
+
166
169
  if (
167
170
  input.storageKey !== undefined &&
168
171
  (typeof input.storageKey !== 'string' || !input.storageKey)
@@ -291,7 +294,7 @@ export function create(
291
294
  function handle(theme: Theme.Definition, name: string) {
292
295
  const original = Token.bind(theme, contract)
293
296
  const className = () =>
294
- `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)}_`)}`
297
+ `z-theme-${Identity.requireId(typeof input.id === 'string' ? input.id : undefined, 'Config.create').slice(3)}-${Identity.name(name)}`
295
298
  const select = (options: { colorScheme?: string } = {}) => {
296
299
  const scheme = options.colorScheme
297
300
  const selection =
@@ -433,7 +436,7 @@ export function create(
433
436
  }
434
437
 
435
438
  const theme =
436
- shorthands || input.defaultLayer !== undefined
439
+ shorthands || input.defaultLayer !== undefined || input.id !== undefined
437
440
  ? Token.bind(Theme.define({}), contract)
438
441
  : undefined
439
442
  return finish({
@@ -452,7 +455,7 @@ export declare namespace create {
452
455
  readonly cssOutput?: 'atomic' | 'grouped' | undefined
453
456
  /** Fallback CSS layer for bound styles and variants; unlayered when omitted. */
454
457
  readonly defaultLayer?: string | undefined
455
- /** Stable theme identity required without source rewriting. */
458
+ /** Consumer-owned namespace; required for uncompiled variable configs. */
456
459
  readonly id?: string | undefined
457
460
  /** Explicit ordered property aliases; none are installed by default. */
458
461
  readonly shorthands?: Shorthands.Map | undefined
@@ -839,7 +842,7 @@ export type VariableOptions = {
839
842
  readonly defaultLayer?: string | undefined
840
843
  /** Required default key when vars contains named sets. */
841
844
  readonly defaultVars?: string | undefined
842
- /** Stable identity required without source rewriting. */
845
+ /** Consumer-owned namespace; required for uncompiled variable configs. */
843
846
  readonly id?: string | undefined
844
847
  /** Ordered CSS layer names. */
845
848
  readonly layers?: readonly string[] | undefined
@@ -25,13 +25,6 @@ export function compact(value: string): string {
25
25
  return result
26
26
  }
27
27
 
28
- /** Encodes an explicit identity without losing punctuation or Unicode distinctions. */
29
- export function encode(value: string): string {
30
- return Array.from(value, (character) =>
31
- character.codePointAt(0)!.toString(16),
32
- ).join('-')
33
- }
34
-
35
28
  /** Keeps an authored label readable while its separate hash disambiguates spelling. */
36
29
  export function label(value: string): string {
37
30
  return (
@@ -42,18 +35,27 @@ export function label(value: string): string {
42
35
  )
43
36
  }
44
37
 
38
+ /** Encodes one name segment, reserving hyphens for path boundaries. */
39
+ export function name(value: string): string {
40
+ return Array.from(value, (character) =>
41
+ /^[a-zA-Z0-9]$/.test(character)
42
+ ? character
43
+ : `_${character.codePointAt(0)!.toString(16)}_`,
44
+ ).join('')
45
+ }
46
+
45
47
  /** Requires an explicit identity at an uncompiled authoring boundary. */
46
48
  export function requireId(id: string | undefined, kind: string): string {
47
49
  if (!id)
48
50
  throw new Error(
49
51
  `${kind} requires an explicit id without the compiler plugin.`,
50
52
  )
51
- return `id-${encode(id)}`
53
+ return `id-${name(id)}`
52
54
  }
53
55
 
54
56
  /** Names one callback input independently of its declaration order. */
55
57
  export function slot(id: string, field: string): `--${string}` {
56
- return `--z-d${id}-${encode(field)}`
58
+ return `--z-${id.startsWith('id-') ? id.slice(3) : id}-${name(field)}`
57
59
  }
58
60
 
59
61
  /** Hashes a canonical value using two independent 32-bit accumulators. */
@@ -69,7 +71,7 @@ export function hash(value: string): string {
69
71
  }
70
72
 
71
73
  /** Names ordered style data consistently in runtime and extraction. */
72
- export function style(input: Style.NamedStyle): string {
74
+ export function style(input: Style.NamedStyle, namespace?: string): string {
73
75
  function value(input: Style.Declaration['value']): unknown {
74
76
  if (Binding.is(input)) return ['variable', input.name]
75
77
  if (Token.is(input))
@@ -105,12 +107,12 @@ export function style(input: Style.NamedStyle): string {
105
107
  !!declaration.important,
106
108
  ])
107
109
  }
108
- return `z-content-${hash(JSON.stringify(shape(input)))}`
110
+ return `z-${namespace ? `${namespace}-` : ''}content-${name(JSON.stringify(shape(input)))}`
109
111
  }
110
112
 
111
113
  /** Names a complete ordered composition, including repeated definitions. */
112
114
  export function composition(names: readonly string[]): string {
113
- return `z-compose-${hash(JSON.stringify(names))}`
115
+ return `z-compose-${name(JSON.stringify(names))}`
114
116
  }
115
117
 
116
118
  /** Names a stylesheet declaration with a caller-owned identity. */
@@ -599,10 +599,10 @@ function build(
599
599
  Object.defineProperty(
600
600
  {
601
601
  get className(): string {
602
- if (scope) return `z_theme-${scope}`
602
+ if (scope) return `z-theme-${scope}`
603
603
  const id = contract[Token.identity]
604
604
  if (!id?.startsWith('id-')) throw new MissingTransformError()
605
- return `z_theme-${id}-${Identity.hash(JSON.stringify(values))}`
605
+ return `z-theme-${id.slice(3)}`
606
606
  },
607
607
  style: (styles?: unknown, options: style.DefinitionOptions = {}) => {
608
608
  if (!contract[Token.identity])