zyzz 0.0.9 → 0.0.12

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 (119) hide show
  1. package/README.md +1 -1
  2. package/dist/Style.js +2 -2
  3. package/dist/Style.js.map +1 -1
  4. package/dist/Vars.d.ts +2 -2
  5. package/dist/Vars.d.ts.map +1 -1
  6. package/dist/Vars.js.map +1 -1
  7. package/dist/compiler/Source.d.ts.map +1 -1
  8. package/dist/compiler/Source.js +10 -0
  9. package/dist/compiler/Source.js.map +1 -1
  10. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  11. package/dist/compiler/internal/Contract.js +11 -6
  12. package/dist/compiler/internal/Contract.js.map +1 -1
  13. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  14. package/dist/compiler/internal/Contributions.js +592 -556
  15. package/dist/compiler/internal/Contributions.js.map +1 -1
  16. package/dist/compiler/internal/Expression.d.ts +4 -0
  17. package/dist/compiler/internal/Expression.d.ts.map +1 -1
  18. package/dist/compiler/internal/Expression.js +45 -0
  19. package/dist/compiler/internal/Expression.js.map +1 -1
  20. package/dist/compiler/internal/RecipeConditions.js +2 -2
  21. package/dist/compiler/internal/RecipeConditions.js.map +1 -1
  22. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  23. package/dist/compiler/internal/Themes.js +2 -0
  24. package/dist/compiler/internal/Themes.js.map +1 -1
  25. package/dist/default.d.ts +75 -19
  26. package/dist/default.d.ts.map +1 -1
  27. package/dist/default.js +76 -11
  28. package/dist/default.js.map +2 -2
  29. package/dist/default.js.zyzz.json +1 -1
  30. package/dist/internal/Condition.d.ts +1 -1
  31. package/dist/internal/Condition.d.ts.map +1 -1
  32. package/dist/internal/Configuration.js +2 -2
  33. package/dist/internal/Configuration.js.map +1 -1
  34. package/dist/internal/Query.d.ts +2 -2
  35. package/dist/internal/Query.d.ts.map +1 -1
  36. package/dist/internal/Query.js +1 -1
  37. package/dist/internal/Query.js.map +1 -1
  38. package/dist/internal/Theme.d.ts +4 -4
  39. package/dist/internal/Theme.d.ts.map +1 -1
  40. package/dist/internal/Theme.js +6 -6
  41. package/dist/internal/Theme.js.map +1 -1
  42. package/dist/internal/Token.d.ts +185 -2
  43. package/dist/internal/Token.d.ts.map +1 -1
  44. package/dist/internal/Token.js +236 -23
  45. package/dist/internal/Token.js.map +1 -1
  46. package/dist/internal/VariableSets.d.ts.map +1 -1
  47. package/dist/internal/VariableSets.js +9 -6
  48. package/dist/internal/VariableSets.js.map +1 -1
  49. package/dist/unplugin/index.d.ts.map +1 -1
  50. package/dist/unplugin/index.js +14 -0
  51. package/dist/unplugin/index.js.map +1 -1
  52. package/dist/variants.d.ts +13 -2
  53. package/dist/variants.d.ts.map +1 -1
  54. package/dist/variants.js.map +1 -1
  55. package/dist/web/colorProfile.d.ts +9 -5
  56. package/dist/web/colorProfile.d.ts.map +1 -1
  57. package/dist/web/colorProfile.js.map +1 -1
  58. package/dist/web/counterStyle.d.ts +13 -9
  59. package/dist/web/counterStyle.d.ts.map +1 -1
  60. package/dist/web/counterStyle.js.map +1 -1
  61. package/dist/web/cssFunction.d.ts +19 -14
  62. package/dist/web/cssFunction.d.ts.map +1 -1
  63. package/dist/web/cssFunction.js.map +1 -1
  64. package/dist/web/fontFace.d.ts +6 -1
  65. package/dist/web/fontFace.d.ts.map +1 -1
  66. package/dist/web/fontFace.js.map +1 -1
  67. package/dist/web/fontFeatureValues.d.ts +11 -7
  68. package/dist/web/fontFeatureValues.d.ts.map +1 -1
  69. package/dist/web/fontFeatureValues.js.map +1 -1
  70. package/dist/web/fontPaletteValues.d.ts +8 -3
  71. package/dist/web/fontPaletteValues.d.ts.map +1 -1
  72. package/dist/web/fontPaletteValues.js.map +1 -1
  73. package/dist/web/internal/Context.d.ts +3 -3
  74. package/dist/web/internal/Context.d.ts.map +1 -1
  75. package/dist/web/keyframes.d.ts +7 -3
  76. package/dist/web/keyframes.d.ts.map +1 -1
  77. package/dist/web/keyframes.js.map +1 -1
  78. package/dist/web/page.d.ts +11 -4
  79. package/dist/web/page.d.ts.map +1 -1
  80. package/dist/web/page.js.map +1 -1
  81. package/dist/web/positionTry.d.ts +6 -1
  82. package/dist/web/positionTry.d.ts.map +1 -1
  83. package/dist/web/positionTry.js.map +1 -1
  84. package/dist/web/property.d.ts +10 -5
  85. package/dist/web/property.d.ts.map +1 -1
  86. package/dist/web/property.js.map +1 -1
  87. package/dist/web/viewTransition.d.ts +10 -6
  88. package/dist/web/viewTransition.d.ts.map +1 -1
  89. package/dist/web/viewTransition.js.map +1 -1
  90. package/package.json +1 -1
  91. package/src/Style.ts +2 -2
  92. package/src/Vars.ts +2 -3
  93. package/src/compiler/Source.ts +19 -0
  94. package/src/compiler/internal/Contract.ts +19 -8
  95. package/src/compiler/internal/Contributions.ts +734 -685
  96. package/src/compiler/internal/Expression.ts +57 -0
  97. package/src/compiler/internal/RecipeConditions.ts +2 -2
  98. package/src/compiler/internal/Themes.ts +2 -0
  99. package/src/default.ts +175 -30
  100. package/src/internal/Condition.ts +3 -3
  101. package/src/internal/Configuration.ts +2 -2
  102. package/src/internal/Query.ts +3 -3
  103. package/src/internal/Theme.ts +12 -12
  104. package/src/internal/Token.ts +253 -33
  105. package/src/internal/VariableSets.ts +28 -25
  106. package/src/unplugin/index.ts +14 -0
  107. package/src/variants.ts +35 -2
  108. package/src/web/colorProfile.ts +25 -10
  109. package/src/web/counterStyle.ts +29 -14
  110. package/src/web/cssFunction.ts +47 -24
  111. package/src/web/fontFace.ts +16 -3
  112. package/src/web/fontFeatureValues.ts +35 -18
  113. package/src/web/fontPaletteValues.ts +25 -11
  114. package/src/web/internal/Context.ts +9 -3
  115. package/src/web/keyframes.ts +24 -9
  116. package/src/web/page.ts +22 -5
  117. package/src/web/positionTry.ts +20 -5
  118. package/src/web/property.ts +23 -9
  119. package/src/web/viewTransition.ts +28 -13
@@ -11,6 +11,193 @@ import type * as VariableSets from '../Vars.js'
11
11
  import * as Literal from './Literal.js'
12
12
  import * as VariableData from './VariableSets.js'
13
13
 
14
+ // Ordered category fallbacks shared by runtime lookup and inferred token names.
15
+ const propertyGroups = {
16
+ accentColor: ['accentColor', 'color'],
17
+ animation: ['animate'],
18
+ aspectRatio: ['aspect'],
19
+ backgroundColor: ['backgroundColor', 'color'],
20
+ backgroundImage: ['backgroundImage'],
21
+ backgroundPosition: ['backgroundPosition'],
22
+ backgroundSize: ['backgroundSize'],
23
+ blockSize: ['spacing'],
24
+ borderBlockColor: ['borderColor', 'color'],
25
+ borderBlockEndColor: ['borderColor', 'color'],
26
+ borderBlockEndWidth: ['borderWidth'],
27
+ borderBlockStartColor: ['borderColor', 'color'],
28
+ borderBlockStartWidth: ['borderWidth'],
29
+ borderBlockWidth: ['borderWidth'],
30
+ borderBottomColor: ['borderColor', 'color'],
31
+ borderBottomLeftRadius: ['radius'],
32
+ borderBottomRightRadius: ['radius'],
33
+ borderBottomWidth: ['borderWidth'],
34
+ borderColor: ['borderColor', 'color'],
35
+ borderEndEndRadius: ['radius'],
36
+ borderEndStartRadius: ['radius'],
37
+ borderInlineColor: ['borderColor', 'color'],
38
+ borderInlineEndColor: ['borderColor', 'color'],
39
+ borderInlineEndWidth: ['borderWidth'],
40
+ borderInlineStartColor: ['borderColor', 'color'],
41
+ borderInlineStartWidth: ['borderWidth'],
42
+ borderInlineWidth: ['borderWidth'],
43
+ borderLeftColor: ['borderColor', 'color'],
44
+ borderLeftWidth: ['borderWidth'],
45
+ borderRadius: ['radius'],
46
+ borderRightColor: ['borderColor', 'color'],
47
+ borderRightWidth: ['borderWidth'],
48
+ borderSpacing: ['borderSpacing', 'spacing'],
49
+ borderStartEndRadius: ['radius'],
50
+ borderStartStartRadius: ['radius'],
51
+ borderTopColor: ['borderColor', 'color'],
52
+ borderTopLeftRadius: ['radius'],
53
+ borderTopRightRadius: ['radius'],
54
+ borderTopWidth: ['borderWidth'],
55
+ borderWidth: ['borderWidth'],
56
+ bottom: ['inset', 'spacing'],
57
+ boxShadow: ['shadow'],
58
+ caretColor: ['caretColor', 'color'],
59
+ color: ['textColor', 'color'],
60
+ columnGap: ['gap', 'spacing'],
61
+ columnRuleColor: ['color'],
62
+ columns: ['columns', 'container'],
63
+ content: ['content'],
64
+ cursor: ['cursor'],
65
+ fill: ['fill', 'color'],
66
+ flexBasis: ['flexBasis', 'spacing', 'container'],
67
+ floodColor: ['color'],
68
+ fontFamily: ['fontFamily'],
69
+ fontSize: ['fontSize'],
70
+ fontWeight: ['fontWeight'],
71
+ gap: ['gap', 'spacing'],
72
+ gridAutoColumns: ['gridAutoColumns'],
73
+ gridAutoRows: ['gridAutoRows'],
74
+ gridColumn: ['gridColumn'],
75
+ gridColumnEnd: ['gridColumnEnd'],
76
+ gridColumnStart: ['gridColumnStart'],
77
+ gridRow: ['gridRow'],
78
+ gridRowEnd: ['gridRowEnd'],
79
+ gridRowStart: ['gridRowStart'],
80
+ gridTemplateColumns: ['gridTemplateColumns'],
81
+ gridTemplateRows: ['gridTemplateRows'],
82
+ height: ['height', 'spacing'],
83
+ inlineSize: ['spacing', 'container'],
84
+ inset: ['inset', 'spacing'],
85
+ insetBlock: ['inset', 'spacing'],
86
+ insetBlockEnd: ['inset', 'spacing'],
87
+ insetBlockStart: ['inset', 'spacing'],
88
+ insetInline: ['inset', 'spacing'],
89
+ insetInlineEnd: ['inset', 'spacing'],
90
+ insetInlineStart: ['inset', 'spacing'],
91
+ left: ['inset', 'spacing'],
92
+ letterSpacing: ['letterSpacing'],
93
+ lightingColor: ['color'],
94
+ lineClamp: ['lineClamp'],
95
+ lineHeight: ['lineHeight'],
96
+ listStyleImage: ['listStyleImage'],
97
+ listStyleType: ['listStyleType'],
98
+ margin: ['margin', 'spacing'],
99
+ marginBlock: ['margin', 'spacing'],
100
+ marginBlockEnd: ['margin', 'spacing'],
101
+ marginBlockStart: ['margin', 'spacing'],
102
+ marginBottom: ['margin', 'spacing'],
103
+ marginInline: ['margin', 'spacing'],
104
+ marginInlineEnd: ['margin', 'spacing'],
105
+ marginInlineStart: ['margin', 'spacing'],
106
+ marginLeft: ['margin', 'spacing'],
107
+ marginRight: ['margin', 'spacing'],
108
+ marginTop: ['margin', 'spacing'],
109
+ maxBlockSize: ['spacing'],
110
+ maxHeight: ['maxHeight', 'height', 'spacing'],
111
+ maxInlineSize: ['spacing', 'container'],
112
+ maxWidth: ['maxWidth', 'spacing', 'container'],
113
+ minBlockSize: ['spacing'],
114
+ minHeight: ['minHeight', 'height', 'spacing'],
115
+ minInlineSize: ['spacing', 'container'],
116
+ minWidth: ['minWidth', 'spacing', 'container'],
117
+ MsScrollbar3dlightColor: ['color'],
118
+ MsScrollbarArrowColor: ['color'],
119
+ MsScrollbarBaseColor: ['color'],
120
+ MsScrollbarDarkshadowColor: ['color'],
121
+ MsScrollbarFaceColor: ['color'],
122
+ MsScrollbarHighlightColor: ['color'],
123
+ MsScrollbarShadowColor: ['color'],
124
+ MsScrollbarTrackColor: ['color'],
125
+ objectPosition: ['objectPosition'],
126
+ opacity: ['opacity'],
127
+ order: ['order'],
128
+ outlineColor: ['outlineColor', 'color'],
129
+ outlineOffset: ['outlineOffset'],
130
+ outlineWidth: ['outlineWidth'],
131
+ padding: ['padding', 'spacing'],
132
+ paddingBlock: ['padding', 'spacing'],
133
+ paddingBlockEnd: ['padding', 'spacing'],
134
+ paddingBlockStart: ['padding', 'spacing'],
135
+ paddingBottom: ['padding', 'spacing'],
136
+ paddingInline: ['padding', 'spacing'],
137
+ paddingInlineEnd: ['padding', 'spacing'],
138
+ paddingInlineStart: ['padding', 'spacing'],
139
+ paddingLeft: ['padding', 'spacing'],
140
+ paddingRight: ['padding', 'spacing'],
141
+ paddingTop: ['padding', 'spacing'],
142
+ perspective: ['perspective'],
143
+ perspectiveOrigin: ['perspectiveOrigin'],
144
+ right: ['inset', 'spacing'],
145
+ rotate: ['rotate'],
146
+ rowGap: ['gap', 'spacing'],
147
+ scale: ['scale'],
148
+ scrollMargin: ['scrollMargin', 'spacing'],
149
+ scrollMarginBlock: ['scrollMargin', 'spacing'],
150
+ scrollMarginBlockEnd: ['scrollMargin', 'spacing'],
151
+ scrollMarginBlockStart: ['scrollMargin', 'spacing'],
152
+ scrollMarginBottom: ['scrollMargin', 'spacing'],
153
+ scrollMarginInline: ['scrollMargin', 'spacing'],
154
+ scrollMarginInlineEnd: ['scrollMargin', 'spacing'],
155
+ scrollMarginInlineStart: ['scrollMargin', 'spacing'],
156
+ scrollMarginLeft: ['scrollMargin', 'spacing'],
157
+ scrollMarginRight: ['scrollMargin', 'spacing'],
158
+ scrollMarginTop: ['scrollMargin', 'spacing'],
159
+ scrollPadding: ['scrollPadding', 'spacing'],
160
+ scrollPaddingBlock: ['scrollPadding', 'spacing'],
161
+ scrollPaddingBlockEnd: ['scrollPadding', 'spacing'],
162
+ scrollPaddingBlockStart: ['scrollPadding', 'spacing'],
163
+ scrollPaddingBottom: ['scrollPadding', 'spacing'],
164
+ scrollPaddingInline: ['scrollPadding', 'spacing'],
165
+ scrollPaddingInlineEnd: ['scrollPadding', 'spacing'],
166
+ scrollPaddingInlineStart: ['scrollPadding', 'spacing'],
167
+ scrollPaddingLeft: ['scrollPadding', 'spacing'],
168
+ scrollPaddingRight: ['scrollPadding', 'spacing'],
169
+ scrollPaddingTop: ['scrollPadding', 'spacing'],
170
+ stopColor: ['color'],
171
+ stroke: ['stroke', 'color'],
172
+ strokeColor: ['color'],
173
+ strokeWidth: ['strokeWidth'],
174
+ textDecorationColor: ['textDecorationColor', 'color'],
175
+ textDecorationThickness: ['textDecorationThickness'],
176
+ textEmphasisColor: ['color'],
177
+ textIndent: ['textIndent', 'spacing'],
178
+ textShadow: ['textShadow'],
179
+ textUnderlineOffset: ['textUnderlineOffset'],
180
+ top: ['inset', 'spacing'],
181
+ transformOrigin: ['transformOrigin'],
182
+ transitionDelay: ['transitionDelay'],
183
+ transitionDuration: ['transitionDuration'],
184
+ transitionProperty: ['transitionProperty'],
185
+ transitionTimingFunction: ['ease'],
186
+ translate: ['translate', 'spacing'],
187
+ WebkitBorderAfterColor: ['color'],
188
+ WebkitBorderBeforeColor: ['color'],
189
+ WebkitBorderEndColor: ['color'],
190
+ WebkitBorderStartColor: ['color'],
191
+ WebkitLineClamp: ['lineClamp'],
192
+ WebkitTapHighlightColor: ['color'],
193
+ WebkitTextFillColor: ['color'],
194
+ WebkitTextStrokeColor: ['color'],
195
+ width: ['width', 'spacing', 'container'],
196
+ zIndex: ['zIndex'],
197
+ } as const satisfies Partial<
198
+ Record<keyof Literal.Properties, readonly string[]>
199
+ >
200
+
14
201
  /** Checks a reference's property domain. */
15
202
  export function accepts(
16
203
  group: Group,
@@ -84,13 +271,31 @@ export function acceptsReference(
84
271
  value <= rule.max &&
85
272
  (!rule.integer || Number.isInteger(value))
86
273
  )
87
- return value === 0 && Binding.accepts('length', property)
274
+ if (rule?.kind === 'grid-line')
275
+ return Number.isInteger(value) && value !== 0
276
+ if (property === 'columns') return Number.isInteger(value) && value > 0
277
+ if (rule?.kind === 'ratio') return value >= 0
278
+ if (rule && 'numeric' in rule && rule.numeric)
279
+ return ('negative' in rule && rule.negative === true) || value >= 0
280
+ return (
281
+ Binding.accepts('number', property) ||
282
+ (value === 0 && Binding.accepts('length', property))
283
+ )
88
284
  }
89
285
  if (reference.group === 'color') return Binding.accepts('color', property)
90
286
  if (reference.group === 'spacing')
91
287
  return (
92
288
  (Literal.rule(property)?.kind === 'compound' &&
93
- accepts('spacing', property)) ||
289
+ (accepts('spacing', property) ||
290
+ (property === 'columns' &&
291
+ !value.endsWith('%') &&
292
+ !value.startsWith('-')) ||
293
+ [
294
+ 'backgroundPosition',
295
+ 'objectPosition',
296
+ 'perspectiveOrigin',
297
+ 'transformOrigin',
298
+ ].includes(property))) ||
94
299
  Binding.accepts(
95
300
  value.endsWith('%')
96
301
  ? value.startsWith('-')
@@ -104,7 +309,16 @@ export function acceptsReference(
104
309
  )
105
310
  return (
106
311
  Literal.isLiteral(property, value) ||
107
- Literal.rule(property)?.kind === 'compound'
312
+ Literal.rule(property)?.kind === 'compound' ||
313
+ [
314
+ 'ratio',
315
+ 'grid-line',
316
+ 'grid-tracks',
317
+ 'identifier',
318
+ 'rotate',
319
+ 'scale',
320
+ 'translate',
321
+ ].includes(Literal.rule(property)?.kind ?? '')
108
322
  )
109
323
  }
110
324
  return check(reference.value)
@@ -307,10 +521,7 @@ export type Names<
307
521
  readonly '~vars': { values: infer values; mappings: infer mappings }
308
522
  }
309
523
  ? mappings extends false
310
- ? Paths<
311
- Omit<values, 'breakpoints' | 'containers' | 'containerNames'>,
312
- property
313
- >
524
+ ? Paths<Omit<values, 'breakpoint' | 'containerNames'>, property>
314
525
  : {
315
526
  [category in keyof values]: category extends keyof mappings
316
527
  ? mappings[category] extends readonly unknown[]
@@ -318,10 +529,12 @@ export type Names<
318
529
  ? Paths<values[category], property>
319
530
  : never
320
531
  : never
321
- : category extends Group
322
- ? property extends Properties<category>
323
- ? Paths<values[category], property>
324
- : never
532
+ : category extends (
533
+ property extends keyof typeof propertyGroups
534
+ ? (typeof propertyGroups)[property][number]
535
+ : never
536
+ )
537
+ ? Paths<values[category], property>
325
538
  : never
326
539
  }[keyof values]
327
540
  : {
@@ -456,28 +669,14 @@ export function resolve(value: unknown, options: resolve.Options): unknown {
456
669
  ?.value as Metadata | undefined
457
670
  if (!data) throw new Error('Expected a theme definition.')
458
671
 
459
- const groups = [
460
- 'backgroundColor',
461
- 'borderColor',
462
- 'borderRadius',
463
- 'borderWidth',
464
- 'margin',
465
- 'padding',
466
- 'spacing',
467
- 'fontFamily',
468
- 'fontSize',
469
- 'fontWeight',
470
- 'letterSpacing',
471
- 'lineHeight',
472
- 'textColor',
473
- 'color',
474
- ] as const
672
+ const groups: readonly string[] =
673
+ propertyGroups[options.property as keyof typeof propertyGroups] ?? []
475
674
 
476
675
  if (data.contract.variableSet) {
477
676
  for (const [path, entry] of Object.entries(data.values).sort(
478
677
  ([left], [right]) =>
479
- groups.indexOf(left.split('.')[0] as (typeof groups)[number]) -
480
- groups.indexOf(right.split('.')[0] as (typeof groups)[number]),
678
+ groups.indexOf(left.split('.')[0]!) -
679
+ groups.indexOf(right.split('.')[0]!),
481
680
  )) {
482
681
  const [category, ...parts] = path.split('.')
483
682
  const mappings = data.contract.mappings
@@ -488,7 +687,7 @@ export function resolve(value: unknown, options: resolve.Options): unknown {
488
687
  : parts.join('.') !== String(value) ||
489
688
  !(mapped
490
689
  ? mapped.includes(options.property)
491
- : accepts(category as Group, options.property))
690
+ : groups.includes(category!))
492
691
  )
493
692
  continue
494
693
  return create({
@@ -512,8 +711,23 @@ export function resolve(value: unknown, options: resolve.Options): unknown {
512
711
  return value
513
712
  }
514
713
 
515
- // Specific groups precede shared colors regardless of authored group order.
516
- for (const group of groups) {
714
+ const legacyGroups = [
715
+ 'backgroundColor',
716
+ 'borderColor',
717
+ 'borderRadius',
718
+ 'borderWidth',
719
+ 'margin',
720
+ 'padding',
721
+ 'spacing',
722
+ 'fontFamily',
723
+ 'fontSize',
724
+ 'fontWeight',
725
+ 'letterSpacing',
726
+ 'lineHeight',
727
+ 'textColor',
728
+ 'color',
729
+ ] as const
730
+ for (const group of legacyGroups) {
517
731
  if (!accepts(group, options.property)) continue
518
732
 
519
733
  const path = `${group}.${value}`
@@ -547,7 +761,13 @@ export function mapped(
547
761
  data.contract.mappings !== false &&
548
762
  !(targets
549
763
  ? targets.includes(property)
550
- : accepts(category as Group, property))
764
+ : data.contract.variableSet
765
+ ? (
766
+ propertyGroups[property as keyof typeof propertyGroups] as
767
+ | readonly string[]
768
+ | undefined
769
+ )?.includes(category)
770
+ : accepts(category as Group, property))
551
771
  )
552
772
  return false
553
773
  let leaf: unknown = Object.getOwnPropertyDescriptor(theme, 'tokens')?.value
@@ -122,7 +122,7 @@ export function build(
122
122
  }
123
123
  const fields = Object.fromEntries(record(input, []))
124
124
  const queries = { ...baseQueries }
125
- for (const key of ['breakpoints', 'containers', 'containerNames'] as const) {
125
+ for (const key of ['breakpoint', 'container', 'containerNames'] as const) {
126
126
  if (Object.hasOwn(fields, key)) {
127
127
  const value = fields[key]
128
128
  if (base) {
@@ -150,7 +150,8 @@ export function build(
150
150
  ? value
151
151
  : { ...baseQueries?.[key], ...value },
152
152
  })
153
- delete fields[key]
153
+ if (key !== 'container' || Object.keys(value as object).length === 0)
154
+ delete fields[key]
154
155
  }
155
156
  }
156
157
  const queryData = Theme.define(queries as Theme.Tokens)[Token.definition]
@@ -161,7 +162,7 @@ export function build(
161
162
  Condition.normalize(
162
163
  Query.resolve(
163
164
  path.at(-1)!,
164
- queryData ?? { breakpoints: {}, containers: {}, containerNames: [] },
165
+ queryData ?? { breakpoint: {}, container: {}, containerNames: [] },
165
166
  ),
166
167
  )
167
168
  } catch (error) {
@@ -267,8 +268,8 @@ function read(
267
268
  Query.resolve(
268
269
  key,
269
270
  queries ?? {
270
- breakpoints: {},
271
- containers: {},
271
+ breakpoint: {},
272
+ container: {},
272
273
  containerNames: [],
273
274
  },
274
275
  ),
@@ -335,27 +336,29 @@ export function mappings(input: unknown): Vars.Mappings | false | undefined {
335
336
  if (input === undefined || input === false) return input
336
337
  return Object.freeze(
337
338
  Object.fromEntries(
338
- record(input, ['mappings']).map(([category, value]) => {
339
- if (
340
- !category ||
341
- !Array.isArray(value) ||
342
- value.some(
343
- (property) =>
344
- typeof property !== 'string' ||
345
- !Object.hasOwn(Literal.rules, property),
346
- )
347
- )
348
- throw new Vars.InvalidError(
349
- ['mappings', category],
350
- 'Expected an array of CSS property names.',
351
- )
352
- if (new Set(value).size !== value.length)
353
- throw new Vars.InvalidError(
354
- ['mappings', category],
355
- 'Property mappings cannot contain duplicates.',
339
+ record(input, ['mappings'])
340
+ .sort(([left], [right]) => left.localeCompare(right))
341
+ .map(([category, value]) => {
342
+ if (
343
+ !category ||
344
+ !Array.isArray(value) ||
345
+ value.some(
346
+ (property) =>
347
+ typeof property !== 'string' ||
348
+ !Object.hasOwn(Literal.rules, property),
349
+ )
356
350
  )
357
- return [category, Object.freeze([...value])]
358
- }),
351
+ throw new Vars.InvalidError(
352
+ ['mappings', category],
353
+ 'Expected an array of CSS property names.',
354
+ )
355
+ if (new Set(value).size !== value.length)
356
+ throw new Vars.InvalidError(
357
+ ['mappings', category],
358
+ 'Property mappings cannot contain duplicates.',
359
+ )
360
+ return [category, Object.freeze([...value])]
361
+ }),
359
362
  ),
360
363
  )
361
364
  }
@@ -576,6 +576,20 @@ const portable = createUnplugin<Options | undefined, false>(
576
576
  },
577
577
  },
578
578
  webpack(compiler) {
579
+ compiler.hooks.compilation.tap('zyzz', (compilation) => {
580
+ compiler.webpack.NormalModule.getCompilationHooks(compilation)
581
+ .readResource.for(undefined)
582
+ .tapAsync({ name: 'zyzz', stage: -1 }, (context, callback) => {
583
+ void Promise.resolve(pending).then(() => {
584
+ const source = sources.get(context.resourcePath)
585
+ if (source === undefined) return callback()
586
+
587
+ // Loaders and CSS compilation must consume the same source version.
588
+ context.addDependency(context.resourcePath)
589
+ callback(null, source)
590
+ }, callback)
591
+ })
592
+ })
579
593
  compiler.hooks.watchRun.tap('zyzz', () => {
580
594
  // The graph rereads every source, including files absent from Webpack's invalidation batch.
581
595
  for (const file of files) compiler.inputFileSystem?.purge?.(file)
package/src/variants.ts CHANGED
@@ -3,6 +3,7 @@ import * as Authoring from './internal/Authoring.js'
3
3
  import type { style } from './styleFunction.js'
4
4
  import type * as Config from './Config.js'
5
5
  import type * as Binding from './internal/Binding.js'
6
+ import type * as Completion from './internal/Completion.js'
6
7
  import type * as Condition from './internal/Condition.js'
7
8
  import type * as Shorthands from './internal/Shorthands.js'
8
9
  import type * as Style from './Style.js'
@@ -59,6 +60,35 @@ type CheckedChoice<
59
60
  ? unknown
60
61
  : never)
61
62
  : CheckedStyles<style, tokens, layers, mappings>
63
+
64
+ type SuggestedStyles<tokens extends Theme.Tokens> =
65
+ Completion.Properties<tokens> & Readonly<Record<string, unknown>>
66
+
67
+ /** Editor hints remain independent of declaration and selection validation. */
68
+ type Suggestions<tokens extends Theme.Tokens> = {
69
+ readonly base?: SuggestedStyles<tokens> | undefined
70
+ readonly compoundVariants?:
71
+ | readonly {
72
+ readonly style: SuggestedStyles<tokens>
73
+ readonly when: unknown
74
+ }[]
75
+ | undefined
76
+ readonly variants?:
77
+ | Readonly<
78
+ Record<
79
+ string,
80
+ Readonly<
81
+ Record<
82
+ string,
83
+ | SuggestedStyles<tokens>
84
+ | ((...args: never[]) => SuggestedStyles<tokens>)
85
+ >
86
+ >
87
+ >
88
+ >
89
+ | undefined
90
+ }
91
+
62
92
  type Keys<value> = value extends unknown ? keyof value : never
63
93
  type Selections<axes> = {
64
94
  readonly [axis in keyof axes]?: Choice<axes[axis]> | null | undefined
@@ -169,7 +199,9 @@ type Checked<
169
199
  * @throws {Error} When uncompiled authoring omits an explicit identity.
170
200
  */
171
201
  export function variants<const definition extends Record<string, unknown>>(
172
- definition: definition & NoInfer<Checked<definition, {}, never, {}>>,
202
+ definition: definition &
203
+ NoInfer<Checked<definition, {}, never, {}>> &
204
+ Suggestions<{}>,
173
205
  options: style.DefinitionOptions = {},
174
206
  ): variants.ReturnType<definition> {
175
207
  return Authoring.variants(
@@ -188,7 +220,8 @@ export declare namespace variants {
188
220
  mappings extends Shorthands.Map = {},
189
221
  > = <const definition extends Record<string, unknown>>(
190
222
  definition: definition &
191
- NoInfer<Checked<definition, tokens, layers, mappings>>,
223
+ NoInfer<Checked<definition, tokens, layers, mappings>> &
224
+ Suggestions<tokens>,
192
225
  options?: style.DefinitionOptions,
193
226
  ) => ReturnType<definition, output>
194
227
 
@@ -5,16 +5,8 @@ import * as Identity from '../internal/Identity.js'
5
5
  import type * as RuleReference from '../internal/RuleReference.js'
6
6
 
7
7
  /** Emits static descriptors and returns a domain-specific CSS name. */
8
- export function colorProfile<
9
- const options extends Omit<colorProfile.Options, 'renderingIntent'> & {
10
- readonly renderingIntent?: string | undefined
11
- },
12
- >(
13
- options: options &
14
- Record<Exclude<keyof options, keyof colorProfile.Options>, never> &
15
- RuleReference.Checked<options> & {
16
- readonly renderingIntent?: Intent<options['renderingIntent']>
17
- },
8
+ export function colorProfile<const options extends Record<string, unknown>>(
9
+ options: options & NoInfer<Accepted<options>>,
18
10
  context: Context.Options = {},
19
11
  ): colorProfile.Reference {
20
12
  void options
@@ -58,3 +50,26 @@ type Keyword<value extends string> =
58
50
  : value extends `${infer rest}${' ' | '\t' | '\n' | '\r' | '\f'}`
59
51
  ? Keyword<rest>
60
52
  : Lexical.Fold<value>
53
+
54
+ type Accepted<input> = {
55
+ [key in keyof input as key extends Context.Group ? key : never]: Accepted<
56
+ input[key]
57
+ >
58
+ } & (keyof input extends never
59
+ ? Definition<input>
60
+ : Exclude<keyof input, Context.Group> extends never
61
+ ? unknown
62
+ : Definition<Omit<input, Context.Group>>)
63
+
64
+ type Definition<options> = options extends Omit<
65
+ colorProfile.Options,
66
+ 'renderingIntent'
67
+ > & {
68
+ readonly renderingIntent?: string | undefined
69
+ }
70
+ ? options &
71
+ Record<Exclude<keyof options, keyof colorProfile.Options>, never> &
72
+ RuleReference.Checked<options> & {
73
+ readonly renderingIntent?: Intent<options['renderingIntent']>
74
+ }
75
+ : never
@@ -5,20 +5,8 @@ import * as Identity from '../internal/Identity.js'
5
5
  import type * as RuleReference from '../internal/RuleReference.js'
6
6
 
7
7
  /** Emits static descriptors and returns a domain-specific CSS name. */
8
- export function counterStyle<
9
- const options extends Omit<counterStyle.Options, 'system'> & {
10
- readonly system?: string | undefined
11
- },
12
- >(
13
- options: options &
14
- Record<Exclude<keyof options, keyof counterStyle.Options>, never> &
15
- RuleReference.Checked<options> & {
16
- readonly system?: Checked<options['system']>
17
- } & (System<options['system']> extends 'additive'
18
- ? { readonly additiveSymbols: string }
19
- : System<options['system']> extends `extends ${string}`
20
- ? unknown
21
- : { readonly symbols: string }),
8
+ export function counterStyle<const options extends Record<string, unknown>>(
9
+ options: options & NoInfer<Accepted<options>>,
22
10
  context: Context.Options = {},
23
11
  ): counterStyle.Reference {
24
12
  void options
@@ -80,3 +68,30 @@ type Trim<value extends string> = value extends `${Space}${infer rest}`
80
68
  : value extends `${infer rest}${Space}`
81
69
  ? Trim<rest>
82
70
  : value
71
+
72
+ type Accepted<input> = {
73
+ [key in keyof input as key extends Context.Group ? key : never]: Accepted<
74
+ input[key]
75
+ >
76
+ } & (keyof input extends never
77
+ ? Definition<input>
78
+ : Exclude<keyof input, Context.Group> extends never
79
+ ? unknown
80
+ : Definition<Omit<input, Context.Group>>)
81
+
82
+ type Definition<options> = options extends Omit<
83
+ counterStyle.Options,
84
+ 'system'
85
+ > & {
86
+ readonly system?: string | undefined
87
+ }
88
+ ? options &
89
+ Record<Exclude<keyof options, keyof counterStyle.Options>, never> &
90
+ RuleReference.Checked<options> & {
91
+ readonly system?: Checked<options['system']>
92
+ } & (System<options['system']> extends 'additive'
93
+ ? { readonly additiveSymbols: string }
94
+ : System<options['system']> extends `extends ${string}`
95
+ ? unknown
96
+ : { readonly symbols: string })
97
+ : never