@yahoo/uds 3.156.2 → 3.157.0

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 (144) hide show
  1. package/dist/automated-config/dist/generated/autoVariants.cjs +9 -4
  2. package/dist/automated-config/dist/generated/autoVariants.d.cts +2 -1
  3. package/dist/automated-config/dist/generated/autoVariants.d.ts +2 -1
  4. package/dist/automated-config/dist/generated/autoVariants.js +9 -4
  5. package/dist/automated-config/dist/generated/generatedConfigs.cjs +3011 -3038
  6. package/dist/automated-config/dist/generated/generatedConfigs.d.cts +143 -140
  7. package/dist/automated-config/dist/generated/generatedConfigs.d.ts +143 -140
  8. package/dist/automated-config/dist/generated/generatedConfigs.js +3011 -3038
  9. package/dist/automated-config/dist/generated/universalTokensConfigAuto.cjs +1227 -501
  10. package/dist/automated-config/dist/generated/universalTokensConfigAuto.js +1227 -501
  11. package/dist/automated-config/dist/properties.cjs +1 -1
  12. package/dist/automated-config/dist/properties.d.cts +15 -0
  13. package/dist/automated-config/dist/properties.d.ts +15 -0
  14. package/dist/automated-config/dist/properties.js +1 -1
  15. package/dist/automated-config/dist/types/ComponentConfig.d.cts +77 -4
  16. package/dist/automated-config/dist/types/ComponentConfig.d.ts +77 -4
  17. package/dist/automated-config/dist/types/ConfigSchema.d.cts +14 -2
  18. package/dist/automated-config/dist/types/ConfigSchema.d.ts +14 -2
  19. package/dist/automated-config/dist/types/StateAxis.cjs +90 -0
  20. package/dist/automated-config/dist/types/StateAxis.d.cts +70 -0
  21. package/dist/automated-config/dist/types/StateAxis.d.ts +70 -0
  22. package/dist/automated-config/dist/types/StateAxis.js +84 -0
  23. package/dist/automated-config/dist/utils/buildConfigSchema.cjs +98 -82
  24. package/dist/automated-config/dist/utils/buildConfigSchema.d.cts +32 -10
  25. package/dist/automated-config/dist/utils/buildConfigSchema.d.ts +32 -10
  26. package/dist/automated-config/dist/utils/buildConfigSchema.js +99 -83
  27. package/dist/automated-config/dist/utils/canonicalizeStateKey.cjs +32 -0
  28. package/dist/automated-config/dist/utils/canonicalizeStateKey.d.cts +48 -0
  29. package/dist/automated-config/dist/utils/canonicalizeStateKey.d.ts +48 -0
  30. package/dist/automated-config/dist/utils/canonicalizeStateKey.js +31 -0
  31. package/dist/automated-config/dist/utils/getConfigComponentVariant.d.cts +8 -0
  32. package/dist/automated-config/dist/utils/getConfigComponentVariant.d.ts +8 -0
  33. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +3 -3
  34. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +3 -3
  35. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.cjs +12 -5
  36. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.d.cts +8 -1
  37. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.d.ts +8 -1
  38. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.js +12 -5
  39. package/dist/automated-config/dist/utils/index.cjs +407 -97
  40. package/dist/automated-config/dist/utils/index.d.cts +66 -16
  41. package/dist/automated-config/dist/utils/index.d.ts +66 -16
  42. package/dist/automated-config/dist/utils/index.js +408 -99
  43. package/dist/automated-config/dist/utils/pseudoStateSelectors.cjs +122 -0
  44. package/dist/automated-config/dist/utils/pseudoStateSelectors.d.cts +80 -0
  45. package/dist/automated-config/dist/utils/pseudoStateSelectors.d.ts +80 -0
  46. package/dist/automated-config/dist/utils/pseudoStateSelectors.js +120 -0
  47. package/dist/automated-config/dist/utils/resolvePropertyStates.cjs +131 -0
  48. package/dist/automated-config/dist/utils/resolvePropertyStates.d.cts +49 -0
  49. package/dist/automated-config/dist/utils/resolvePropertyStates.d.ts +49 -0
  50. package/dist/automated-config/dist/utils/resolvePropertyStates.js +130 -0
  51. package/dist/automated-config/dist/utils/resolveSlotByCascade.cjs +118 -0
  52. package/dist/automated-config/dist/utils/resolveSlotByCascade.d.cts +68 -0
  53. package/dist/automated-config/dist/utils/resolveSlotByCascade.d.ts +68 -0
  54. package/dist/automated-config/dist/utils/resolveSlotByCascade.js +117 -0
  55. package/dist/automated-config/dist/utils/variantConfigGuards.d.cts +13 -0
  56. package/dist/automated-config/dist/utils/variantConfigGuards.d.ts +13 -0
  57. package/dist/components/client/Input/Input.cjs +42 -6
  58. package/dist/components/client/Input/Input.d.cts +13 -0
  59. package/dist/components/client/Input/Input.d.ts +13 -0
  60. package/dist/components/client/Input/Input.js +42 -6
  61. package/dist/config/dist/index.cjs +221 -550
  62. package/dist/config/dist/index.js +221 -550
  63. package/dist/css/dist/commands/css.cjs +1 -0
  64. package/dist/css/dist/commands/css.helpers.cjs +6 -0
  65. package/dist/css/dist/commands/css.helpers.js +6 -0
  66. package/dist/css/dist/commands/css.js +1 -0
  67. package/dist/css/dist/css/generate.cjs +4 -2
  68. package/dist/css/dist/css/generate.d.cts +28 -0
  69. package/dist/css/dist/css/generate.d.ts +28 -0
  70. package/dist/css/dist/css/generate.helpers.cjs +5 -1
  71. package/dist/css/dist/css/generate.helpers.js +6 -2
  72. package/dist/css/dist/css/generate.js +4 -2
  73. package/dist/css/dist/css/postcss.cjs +81 -0
  74. package/dist/css/dist/css/postcss.helpers.cjs +60 -0
  75. package/dist/css/dist/css/postcss.helpers.js +59 -1
  76. package/dist/css/dist/css/postcss.js +82 -2
  77. package/dist/css/dist/css/runner.cjs +12 -2
  78. package/dist/css/dist/css/runner.js +12 -2
  79. package/dist/css/dist/css/theme.d.cts +6 -0
  80. package/dist/css/dist/css/theme.d.ts +6 -0
  81. package/dist/css/dist/packages/automated-config/dist/properties.cjs +1 -1
  82. package/dist/css/dist/packages/automated-config/dist/properties.js +1 -1
  83. package/dist/css/dist/packages/automated-config/dist/utils/index.d.cts +6 -0
  84. package/dist/css/dist/packages/automated-config/dist/utils/index.d.ts +6 -0
  85. package/dist/css/dist/packages/config/dist/index.cjs +221 -550
  86. package/dist/css/dist/packages/config/dist/index.js +221 -550
  87. package/dist/css/dist/utils/optimizeCSS.cjs +59 -0
  88. package/dist/css/dist/utils/optimizeCSS.js +59 -0
  89. package/dist/index.cjs +25 -0
  90. package/dist/index.d.cts +10 -3
  91. package/dist/index.d.ts +10 -3
  92. package/dist/index.js +9 -2
  93. package/dist/styles/styler.d.cts +12 -11
  94. package/dist/styles/styler.d.ts +12 -11
  95. package/dist/styles/variants.d.cts +9 -4
  96. package/dist/styles/variants.d.ts +9 -4
  97. package/dist/tailwind-internal/dist/packages/automated-config/dist/generated/generatedConfigs.cjs +3011 -3038
  98. package/dist/tailwind-internal/dist/packages/automated-config/dist/generated/generatedConfigs.js +3011 -3038
  99. package/dist/tailwind-internal/dist/packages/automated-config/dist/properties.cjs +1 -1
  100. package/dist/tailwind-internal/dist/packages/automated-config/dist/properties.js +1 -1
  101. package/dist/tailwind-internal/dist/packages/automated-config/dist/types/StateAxis.cjs +81 -0
  102. package/dist/tailwind-internal/dist/packages/automated-config/dist/types/StateAxis.js +76 -0
  103. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/canonicalizeStateKey.cjs +33 -0
  104. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/canonicalizeStateKey.js +32 -0
  105. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/componentStatePseudoStates.cjs +0 -7
  106. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/componentStatePseudoStates.js +1 -7
  107. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.cjs +354 -97
  108. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.d.cts +6 -0
  109. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.d.ts +6 -0
  110. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.js +355 -98
  111. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/pseudoStateSelectors.cjs +122 -0
  112. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/pseudoStateSelectors.js +121 -0
  113. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolvePropertyStates.cjs +132 -0
  114. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolvePropertyStates.js +131 -0
  115. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolveSlotByCascade.cjs +95 -0
  116. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolveSlotByCascade.js +95 -0
  117. package/dist/tailwind-internal/dist/packages/config/dist/index.cjs +221 -550
  118. package/dist/tailwind-internal/dist/packages/config/dist/index.js +221 -550
  119. package/dist/tailwind-internal/dist/plugins/components.cjs +28 -24
  120. package/dist/tailwind-internal/dist/plugins/components.js +28 -24
  121. package/dist/tailwind-internal/dist/utils/composeTailwindPlugins.d.cts +3 -0
  122. package/dist/tailwind-internal/dist/utils/composeTailwindPlugins.d.ts +3 -0
  123. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.cts +2 -2
  124. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.ts +2 -2
  125. package/dist/tokens/automation/index.cjs +25 -0
  126. package/dist/tokens/automation/index.d.cts +9 -2
  127. package/dist/tokens/automation/index.d.ts +9 -2
  128. package/dist/tokens/automation/index.js +9 -2
  129. package/dist/tokens/index.cjs +25 -0
  130. package/dist/tokens/index.d.cts +10 -3
  131. package/dist/tokens/index.d.ts +10 -3
  132. package/dist/tokens/index.js +9 -2
  133. package/dist/tokens/types.d.cts +1 -1
  134. package/dist/tokens/types.d.ts +1 -1
  135. package/dist/uds/generated/componentData.cjs +2202 -2200
  136. package/dist/uds/generated/componentData.js +2202 -2200
  137. package/dist/uds/generated/migrationSchemaVersion.cjs +1 -1
  138. package/dist/uds/generated/migrationSchemaVersion.js +1 -1
  139. package/dist/uds/generated/tailwindPurge.cjs +79 -78
  140. package/dist/uds/generated/tailwindPurge.js +79 -78
  141. package/generated/componentData.json +2720 -2718
  142. package/generated/migrationSchemaVersion.ts +1 -1
  143. package/generated/tailwindPurge.ts +2 -2
  144. package/package.json +1 -1
@@ -2,16 +2,22 @@
2
2
  import { BUTTON_GAP_VAR, BUTTON_SCALE_EFFECT_HOVER, BUTTON_SCALE_EFFECT_PRESSED, BUTTON_SCALE_EFFECT_REST } from "../../../css-tokens/dist/index.js";
3
3
  import { mapTextVariantFixtureToValue } from "../mapTextVariantFixtureToValue.js";
4
4
  import { configurableProperties } from "../properties.js";
5
- import { filterPseudoStatesByExclusion, getExcludedPseudoStatesForComponentStateOption } from "./componentStatePseudoStates.js";
5
+ import { INTERACTIVE_ATOMICS, MODIFIER_ATOMICS, comparePriority } from "../types/StateAxis.js";
6
+ import { getExcludedPseudoStatesForComponentStateOption } from "./componentStatePseudoStates.js";
6
7
  import { generateSchemaKey } from "./generateSchemaKey.js";
8
+ import "./canonicalizeStateKey.js";
9
+ import { atomicAndCompoundStateKeys, resolvePropertyStates } from "./resolvePropertyStates.js";
7
10
  import { isVariantConfigWithComponentStates, isVariantConfigWithProperties } from "./variantConfigGuards.js";
8
11
  import { findFixtureTypeForValue } from "./buildConfigSchema.js";
9
12
  import { generateDefaultClassName } from "./generateDefaultClassName.js";
13
+ import { getStateDocsClass, getStateSelector } from "./pseudoStateSelectors.js";
14
+ import { resolveSlotByCascade } from "./resolveSlotByCascade.js";
10
15
  import "./cartesianProduct.js";
11
16
  import "./subcomponents.js";
12
17
  import "./coalesceConfigVariant.js";
13
18
  import "./defaults.js";
14
19
  import "./generateKeyFromFlatConfigPath.js";
20
+ import "./getConfigComponentVariant.js";
15
21
  import "./getConfigVariantComponentStatesMatrix.js";
16
22
  import "./getConfigVariantProperties.js";
17
23
  import "./getConfigVariantPseudoStates.js";
@@ -70,37 +76,55 @@ const COMPONENTS_WITH_SHADOW_BORDERS = [
70
76
  }
71
77
  ];
72
78
  /**
73
- * Map our "states" to pseudo-classes (hover => :hover, pressed => :active, etc.).
74
- * Adjust or extend as needed.
79
+ * Legacy state keys still used by unmigrated component configs via per-property
80
+ * `pseudoStates` arrays. They aren't in the new `StateAxis` taxonomy (so the
81
+ * resolver/StateBuilder don't auto-compose them) but they must remain in
82
+ * `KNOWN_STATE_KEYS` so the docs-mode map / configurator safelist still cover
83
+ * configs that emit them. Drop entries from this list as components migrate.
75
84
  */
76
- const statePseudoMap = {
77
- rest: "",
78
- hover: ":hover:not(:active, :disabled, :has(:disabled))",
79
- pressed: ":active:not(:disabled, :has(:disabled))",
80
- disabled: ":is(:disabled, :has(:disabled))",
81
- visited: ":visited",
82
- focused: ":focus",
83
- "focus-within": ":focus-within",
84
- "focused-keyboard": ":focus-visible",
85
- readonly: ":has(input:read-only)",
86
- invalid: ":has(input[aria-invalid=\"true\"])",
87
- "invalid&hover": ":has(input[aria-invalid=\"true\"]):hover:not(:active, :disabled, :has(:disabled))",
88
- "invalid&pressed": ":has(input[aria-invalid=\"true\"]):active:not(:disabled, :has(:disabled))"
89
- };
90
- const statePseudoMapDocsMode = {
91
- rest: "",
92
- hover: "hover",
93
- pressed: "active",
94
- disabled: "has-disabled",
95
- visited: "visited",
96
- focused: "focus",
97
- "focus-within": "focus-within",
98
- "focused-keyboard": "focus-visible",
99
- readonly: "input-readonly",
100
- invalid: "has-input-invalid",
101
- "invalid&hover": "has-input-invalid-and-hover",
102
- "invalid&pressed": "has-input-invalid-and-active"
103
- };
85
+ const LEGACY_STATE_KEYS = [
86
+ "disabled",
87
+ "focused",
88
+ "focused-keyboard"
89
+ ];
90
+ /**
91
+ * Enumerates every canonical state key the system supports: rest, every atom,
92
+ * every modifier-subset (up to {@link MAX_MODIFIERS_PER_COMPOUND}) on its own
93
+ * and combined with each interactive, plus any legacy keys still in use.
94
+ *
95
+ * Mirrors `resolvePropertyStates` exactly so what the resolver pre-emits in
96
+ * the schema, what the StateBuilder lets users compose, and what the docs
97
+ * map / configurator safelist preserve are all the same set.
98
+ */
99
+ function enumerateAllStateKeys() {
100
+ const states = ["rest"];
101
+ const atoms = [...INTERACTIVE_ATOMICS, ...MODIFIER_ATOMICS].sort(comparePriority);
102
+ for (const stateKey of atomicAndCompoundStateKeys(atoms)) states.push(stateKey);
103
+ for (const legacy of LEGACY_STATE_KEYS) states.push(legacy);
104
+ return states;
105
+ }
106
+ const KNOWN_STATE_KEYS = enumerateAllStateKeys();
107
+ /**
108
+ * Lookup of every known state key to its index in `KNOWN_STATE_KEYS` — i.e. the
109
+ * resolver's emission order. The CSS generator iterates property-state maps
110
+ * in this order (instead of the alphabetical insertion order produced by
111
+ * `syncYosConfig`'s `normalizeConfig`), so cascade tie-breaking under the
112
+ * uniform per-atom specificity actually follows the priority chain. Unknown
113
+ * keys sort to the end.
114
+ */
115
+ const KNOWN_STATE_RANK = new Map(KNOWN_STATE_KEYS.map((key, index) => [key, index]));
116
+ function compareStateKeys(a, b) {
117
+ const ra = KNOWN_STATE_RANK.get(a) ?? Number.POSITIVE_INFINITY;
118
+ const rb = KNOWN_STATE_RANK.get(b) ?? Number.POSITIVE_INFINITY;
119
+ if (ra === rb) return a < b ? -1 : a > b ? 1 : 0;
120
+ return ra - rb;
121
+ }
122
+ function buildStateRecord(transform) {
123
+ const record = {};
124
+ for (const key of KNOWN_STATE_KEYS) record[key] = transform(key);
125
+ return record;
126
+ }
127
+ const statePseudoMapDocsMode = buildStateRecord(getStateDocsClass);
104
128
  /**
105
129
  * Generates button line-height with icon size minimum.
106
130
  * Ensures button line-height is at least as tall as the icon to prevent clipping.
@@ -243,7 +267,57 @@ const getTheCssPropertyValue = (schema, theme, propertyName, schemaStateValue, e
243
267
  if (propertyConfig.concatenate && existingValue) return `${existingValue}${propertyConfig.concatenationDelimiter || ", "}${newValue}`;
244
268
  return newValue;
245
269
  };
246
- function generateDeclaration({ componentName, subComponentName, variantKey, variantValue, layer, layerOptionalPseudoSelector, componentStateKey, componentStateValue, schema, propertyKey, originalPropertyDefinition, theme, currentStyles, previewOptions, excludedPseudoStates = [] }) {
270
+ /**
271
+ * Builds the per-state resolution map for a per-componentState OVERRIDE in
272
+ * exhaustive mode: the universal layer's state map with the override's ENABLED
273
+ * (and `rest`) slots layered on top. An unset or disabled override slot defers
274
+ * to the universal layer's value, so `resolveSlotByCascade` picks the
275
+ * most-specific *enabled* slot across both layers (override winning ties) rather
276
+ * than collapsing every unset state to the override's own `rest`.
277
+ */
278
+ function mergeUniversalUnderOverride(universal, override) {
279
+ const merged = { ...universal };
280
+ const overrideRecord = override;
281
+ for (const state of Object.keys(overrideRecord)) {
282
+ const slot = overrideRecord[state];
283
+ if (state === "rest" && slot?.isEnabled !== false || slot?.isEnabled === true) merged[state] = slot;
284
+ }
285
+ return merged;
286
+ }
287
+ /**
288
+ * Replays SELECTIVE emission for a STANDALONE atomicStates layer (no universal
289
+ * fallback) and returns the sparse set of slots it would emit: `rest`, every
290
+ * explicitly-enabled state, and every cascade-correction. Mirrors the inline
291
+ * selective decision in `generateDeclaration` — keep the two in lock-step.
292
+ *
293
+ * The override path seeds its own correction accumulator with this for the
294
+ * UNIVERSAL layer. Universal layers are emitted in a separate pass at the SAME
295
+ * specificity tier as their per-option overrides (see `bumpRootSpecificity`), so
296
+ * at runtime a universal rule wins wherever the override emits nothing. Without
297
+ * this seed, an override that flattens a state to `rest` (e.g. a `filled` help
298
+ * text that's `muted` everywhere) silently inherits the universal's brighter
299
+ * rule for that state in selective mode — a divergence from exhaustive, where
300
+ * the override emits every state explicitly. Seeding makes the override emit a
301
+ * correction whenever the universal would otherwise render a different value.
302
+ */
303
+ function selectiveEmittedStates(stateMap, orderedStateKeys, emittableStates) {
304
+ const emitted = { rest: stateMap.rest };
305
+ for (const stateKey of orderedStateKeys) {
306
+ if (stateKey === "rest" || !emittableStates.has(stateKey)) continue;
307
+ const value = resolveSlotByCascade(stateKey, stateMap);
308
+ if (!value) continue;
309
+ if (!(stateMap[stateKey]?.isEnabled === true)) {
310
+ if (resolveSlotByCascade(stateKey, emitted)?.value === value.value) continue;
311
+ }
312
+ emitted[stateKey] = {
313
+ ...value,
314
+ isEnabled: true
315
+ };
316
+ }
317
+ return emitted;
318
+ }
319
+ function generateDeclaration({ componentName, subComponentName, variantKey, variantValue, layer, layerOptionalPseudoSelector, componentStateKey, componentStateValue, schema, propertyKey, originalPropertyDefinition, declaredStates, layerUsesAtomicStates, theme, currentStyles, previewOptions, excludedPseudoStates = [], emit, fallbackStateMap, bumpRootSpecificity }) {
320
+ const shouldUseExhaustive = (emit ?? "exhaustive") === "exhaustive" && layerUsesAtomicStates;
247
321
  const schemaKey = generateSchemaKey({
248
322
  variantKey,
249
323
  variantValue,
@@ -264,14 +338,29 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
264
338
  const propertyStateMap = schema.variables?.[schemaKey]?.[propertyKey];
265
339
  if (!propertyStateMap) throw new Error(`Prop definition (${componentName} - ${schemaKey} - ${propertyKey}) not found, this is not expected, please report the bug to the UDS team`);
266
340
  const styles = {};
267
- const skipRestForProperty = originalPropertyDefinition.skipRestState === true;
268
- const declaredPseudoStates = filterPseudoStatesByExclusion(originalPropertyDefinition.pseudoStates, excludedPseudoStates);
269
- const declaredPropertyStates = new Set([...skipRestForProperty ? [] : ["rest"], ...declaredPseudoStates]);
270
- for (const propStateStr in propertyStateMap) {
271
- if (!declaredPropertyStates.has(propStateStr)) continue;
341
+ const excludedStateSet = new Set(excludedPseudoStates);
342
+ const emittableStates = new Set([...declaredStates].filter((state) => !excludedStateSet.has(state)));
343
+ const orderedStateKeys = (shouldUseExhaustive || layerUsesAtomicStates ? [...emittableStates] : Object.keys(propertyStateMap)).sort(compareStateKeys);
344
+ const resolutionStates = fallbackStateMap ? mergeUniversalUnderOverride(fallbackStateMap, propertyStateMap) : propertyStateMap;
345
+ const emittedForSelective = layerUsesAtomicStates && !shouldUseExhaustive ? fallbackStateMap ? selectiveEmittedStates(fallbackStateMap, orderedStateKeys, emittableStates) : { rest: resolutionStates.rest } : {};
346
+ for (const propStateStr of orderedStateKeys) {
347
+ if (!emittableStates.has(propStateStr)) continue;
272
348
  const propertyState = propStateStr;
273
- const propertyStateSelector = statePseudoMap[propertyState] ?? "";
274
- const schemaValueForState = propertyStateMap[propertyState];
349
+ const propertyStateSelector = getStateSelector(propertyState);
350
+ const schemaValueForState = shouldUseExhaustive || layerUsesAtomicStates ? resolveSlotByCascade(propStateStr, resolutionStates) : propertyStateMap[propertyState];
351
+ if (!schemaValueForState) continue;
352
+ if (!shouldUseExhaustive) {
353
+ if (layerUsesAtomicStates) {
354
+ const isExplicitlyEnabled = propertyStateMap[propertyState]?.isEnabled === true;
355
+ if (propStateStr !== "rest" && !isExplicitlyEnabled) {
356
+ if (resolveSlotByCascade(propStateStr, emittedForSelective)?.value === schemaValueForState.value) continue;
357
+ }
358
+ emittedForSelective[propStateStr] = {
359
+ ...schemaValueForState,
360
+ isEnabled: true
361
+ };
362
+ } else if (schemaValueForState.isEnabled === false) continue;
363
+ }
275
364
  let fullClassName = ``;
276
365
  if (layer === "root") if (componentStateKey && componentStateValue) {
277
366
  const rootVariantClass = generateClassName({
@@ -290,7 +379,7 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
290
379
  componentStateValue
291
380
  });
292
381
  fullClassName = `.${rootVariantClass}${propertyStateSelector}.${className}`;
293
- } else fullClassName = `.${className}${propertyStateSelector}`;
382
+ } else fullClassName = bumpRootSpecificity ? `.${className}.${className}${propertyStateSelector}` : `.${className}${propertyStateSelector}`;
294
383
  else {
295
384
  const rootVariantClassName = generateClassName({
296
385
  componentName,
@@ -317,7 +406,17 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
317
406
  subComponentName
318
407
  });
319
408
  fullClassName = `.${rootVariantClassName}${propertyStateSelector}.${rootVariantClassNameWithComponentState} .${className}`;
320
- } else fullClassName = `.${rootVariantClassName}${propertyStateSelector} .${className}`;
409
+ } else {
410
+ className = generateClassName({
411
+ componentName,
412
+ variantKey,
413
+ variantValue,
414
+ layer,
415
+ layerOptionalPseudoSelector,
416
+ subComponentName
417
+ });
418
+ fullClassName = bumpRootSpecificity ? `.${rootVariantClassName}.${rootVariantClassName}${propertyStateSelector} .${className}` : `.${rootVariantClassName}${propertyStateSelector} .${className}`;
419
+ }
321
420
  }
322
421
  const { cssProperties, extendedProperties: extendedPropertiesGetter } = configurableProperties[originalPropertyDefinition.name];
323
422
  const cssDeclarations = {};
@@ -459,7 +558,7 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
459
558
  ...styles[fullClassName]
460
559
  };
461
560
  if (previewOptions?.generatePseudoStateClassModifier) {
462
- const pseudoPrefixClass = statePseudoMapDocsMode[propertyState] ?? "";
561
+ const pseudoPrefixClass = getStateDocsClass(propertyState);
463
562
  if (pseudoPrefixClass.length) {
464
563
  const importantCssDeclarations = Object.fromEntries(Object.entries(cssDeclarations).map(([prop, value]) => {
465
564
  const strValue = String(value).trimEnd().replace(/;$/, "");
@@ -475,12 +574,137 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
475
574
  }
476
575
  return styles;
477
576
  }
478
- function generateConfigStyles(config, schema, theme, previewOptions) {
577
+ /**
578
+ * Emit CSS for per-state schema entries that target a variant's universal
579
+ * layers — the "override" path. Per-state schema entries can be authored by
580
+ * the Configurator (via `setConfigPseudoStateVariable`) or written by data
581
+ * migrations; they aren't declared in source configs.
582
+ *
583
+ * Iterates the cartesian product of `componentStates.X.options × universal
584
+ * layers × universal properties`. For each combination, calls
585
+ * `generateDeclaration` with the universal property's metadata plus the
586
+ * componentState key/value — the existing schema lookup inside
587
+ * `generateDeclaration` picks up the override slot if one exists and skips
588
+ * the property otherwise.
589
+ */
590
+ function emitSchemaOverrideStyles({ componentName, subComponentName, variantKey, variantOption, variantConfig, schema, theme, previewOptions, emit, currentStyles }) {
591
+ let styles = currentStyles;
592
+ const universalLayers = variantConfig.layers;
593
+ const componentStates = variantConfig.componentStates;
594
+ if (!universalLayers || !componentStates) return styles;
595
+ const variables = schema.variables;
596
+ if (!variables) return styles;
597
+ for (const componentStateKey in componentStates) {
598
+ const componentState = componentStates[componentStateKey];
599
+ for (const componentStateOption of componentState.options) for (const layerKey in universalLayers) {
600
+ const universalLayer = universalLayers[layerKey];
601
+ const schemaEntry = variables[generateSchemaKey({
602
+ variantKey,
603
+ variantValue: variantOption,
604
+ componentStateKey,
605
+ componentStateValue: componentStateOption,
606
+ layer: layerKey,
607
+ subComponentName
608
+ })];
609
+ if (!schemaEntry) continue;
610
+ for (const propertyKey in universalLayer.properties) {
611
+ if (!schemaEntry[propertyKey]) continue;
612
+ const originalPropertyDefinition = universalLayer.properties[propertyKey];
613
+ const fallbackStateMap = variables[generateSchemaKey({
614
+ variantKey,
615
+ variantValue: variantOption,
616
+ layer: layerKey,
617
+ subComponentName
618
+ })]?.[propertyKey];
619
+ const declarations = generateDeclaration({
620
+ componentName,
621
+ subComponentName,
622
+ variantKey,
623
+ variantValue: variantOption,
624
+ componentStateKey,
625
+ componentStateValue: componentStateOption,
626
+ layer: layerKey,
627
+ layerOptionalPseudoSelector: universalLayer.pseudoSelector,
628
+ propertyKey,
629
+ originalPropertyDefinition,
630
+ declaredStates: new Set(resolvePropertyStates(universalLayer, originalPropertyDefinition)),
631
+ layerUsesAtomicStates: (universalLayer.atomicStates?.length ?? 0) > 0,
632
+ theme,
633
+ schema,
634
+ currentStyles: styles,
635
+ previewOptions,
636
+ emit,
637
+ fallbackStateMap
638
+ });
639
+ styles = deepMerge(styles, declarations);
640
+ }
641
+ }
642
+ }
643
+ return styles;
644
+ }
645
+ /**
646
+ * Emit CSS for a set of layers without a component-state segment in the
647
+ * selector. Used by both `VariantConfigWithProperties` (where layers are the
648
+ * only source of styles) and `VariantConfigWithComponentStates` (where these
649
+ * layers express the variant's universal baseline, with per-state overrides
650
+ * winning via class-compound specificity).
651
+ */
652
+ function emitUniversalLayers({ componentName, subComponentName, variantKey, variantOption, layers, schema, theme, previewOptions, emit, currentStyles, bumpRootSpecificity }) {
653
+ let styles = currentStyles;
654
+ const variables = schema.variables;
655
+ for (const layerKey in layers) {
656
+ const layer = layers[layerKey];
657
+ const schemaKey = generateSchemaKey({
658
+ variantKey,
659
+ variantValue: variantOption,
660
+ layer: layerKey,
661
+ subComponentName
662
+ });
663
+ const schemaEntry = variables?.[schemaKey];
664
+ for (const propertyKey in layer.properties) {
665
+ if (!schemaEntry || !schemaEntry[propertyKey]) continue;
666
+ const originalPropertyDefinition = layer.properties[propertyKey];
667
+ const declarations = generateDeclaration({
668
+ componentName,
669
+ subComponentName,
670
+ variantKey,
671
+ variantValue: variantOption,
672
+ layer: layerKey,
673
+ layerOptionalPseudoSelector: layer.pseudoSelector,
674
+ propertyKey,
675
+ originalPropertyDefinition,
676
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
677
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
678
+ theme,
679
+ schema,
680
+ currentStyles: styles,
681
+ previewOptions,
682
+ emit,
683
+ bumpRootSpecificity
684
+ });
685
+ styles = deepMerge(styles, declarations);
686
+ }
687
+ }
688
+ return styles;
689
+ }
690
+ function generateConfigStyles(config, schema, theme, previewOptions, emit) {
479
691
  const componentName = config.label.toLowerCase();
480
692
  let styles = {};
481
693
  for (const variantKey in config.variants) {
482
694
  const variantConfig = config.variants[variantKey];
483
695
  for (const variantOption of variantConfig.options) if (isVariantConfigWithComponentStates(variantConfig)) {
696
+ if (variantConfig.layers) styles = emitUniversalLayers({
697
+ componentName,
698
+ variantKey,
699
+ variantOption,
700
+ layers: variantConfig.layers,
701
+ schema,
702
+ theme,
703
+ previewOptions,
704
+ emit,
705
+ currentStyles: styles,
706
+ bumpRootSpecificity: true
707
+ });
484
708
  const componentStates = variantConfig.componentStates;
485
709
  for (const componentStateKey in componentStates) {
486
710
  const componentState = componentStates[componentStateKey];
@@ -500,46 +724,61 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
500
724
  layerOptionalPseudoSelector: layer.pseudoSelector,
501
725
  propertyKey,
502
726
  originalPropertyDefinition,
727
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
728
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
503
729
  theme,
504
730
  schema,
505
731
  currentStyles: styles,
506
732
  previewOptions,
507
- excludedPseudoStates
733
+ excludedPseudoStates,
734
+ emit
508
735
  });
509
736
  styles = deepMerge(styles, declarations);
510
737
  }
511
738
  }
512
739
  }
513
740
  }
514
- } else if (isVariantConfigWithProperties(variantConfig)) {
515
- const layers = variantConfig.layers;
516
- for (const layerKey in layers) {
517
- const layer = layers[layerKey];
518
- for (const propertyKey in layer.properties) {
519
- const originalPropertyDefinition = layer.properties[propertyKey];
520
- const declarations = generateDeclaration({
521
- componentName,
522
- variantKey,
523
- variantValue: variantOption,
524
- layer: layerKey,
525
- layerOptionalPseudoSelector: layer.pseudoSelector,
526
- propertyKey,
527
- originalPropertyDefinition,
528
- theme,
529
- schema,
530
- currentStyles: styles,
531
- previewOptions
532
- });
533
- styles = deepMerge(styles, declarations);
534
- }
535
- }
536
- }
741
+ styles = emitSchemaOverrideStyles({
742
+ componentName,
743
+ variantKey,
744
+ variantOption,
745
+ variantConfig,
746
+ schema,
747
+ theme,
748
+ previewOptions,
749
+ emit,
750
+ currentStyles: styles
751
+ });
752
+ } else if (isVariantConfigWithProperties(variantConfig)) styles = emitUniversalLayers({
753
+ componentName,
754
+ variantKey,
755
+ variantOption,
756
+ layers: variantConfig.layers,
757
+ schema,
758
+ theme,
759
+ previewOptions,
760
+ emit,
761
+ currentStyles: styles
762
+ });
537
763
  }
538
764
  if (config.subComponents) {
539
765
  const { subComponents } = config;
540
766
  for (const subComponentKey in subComponents) for (const variantKey in subComponents[subComponentKey].variants) {
541
767
  const variantConfig = subComponents[subComponentKey].variants[variantKey];
542
768
  for (const variantOption of variantConfig.options) if (isVariantConfigWithComponentStates(variantConfig)) {
769
+ if (variantConfig.layers) styles = emitUniversalLayers({
770
+ componentName,
771
+ subComponentName: subComponentKey,
772
+ variantKey,
773
+ variantOption,
774
+ layers: variantConfig.layers,
775
+ schema,
776
+ theme,
777
+ previewOptions,
778
+ emit,
779
+ currentStyles: styles,
780
+ bumpRootSpecificity: true
781
+ });
543
782
  const componentStates = variantConfig.componentStates;
544
783
  for (const componentStateKey in componentStates) {
545
784
  const componentState = componentStates[componentStateKey];
@@ -560,41 +799,44 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
560
799
  layerOptionalPseudoSelector: layer.pseudoSelector,
561
800
  propertyKey,
562
801
  originalPropertyDefinition,
802
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
803
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
563
804
  theme,
564
805
  schema,
565
806
  currentStyles: styles,
566
807
  previewOptions,
567
- excludedPseudoStates
808
+ excludedPseudoStates,
809
+ emit
568
810
  });
569
811
  styles = deepMerge(styles, declarations);
570
812
  }
571
813
  }
572
814
  }
573
815
  }
574
- } else if (isVariantConfigWithProperties(variantConfig)) {
575
- const layers = variantConfig.layers;
576
- for (const layerKey in layers) {
577
- const layer = layers[layerKey];
578
- for (const propertyKey in layer.properties) {
579
- const originalPropertyDefinition = layer.properties[propertyKey];
580
- const declarations = generateDeclaration({
581
- componentName,
582
- subComponentName: subComponentKey,
583
- variantKey,
584
- variantValue: variantOption,
585
- layer: layerKey,
586
- layerOptionalPseudoSelector: layer.pseudoSelector,
587
- propertyKey,
588
- originalPropertyDefinition,
589
- theme,
590
- schema,
591
- currentStyles: styles,
592
- previewOptions
593
- });
594
- styles = deepMerge(styles, declarations);
595
- }
596
- }
597
- }
816
+ styles = emitSchemaOverrideStyles({
817
+ componentName,
818
+ subComponentName: subComponentKey,
819
+ variantKey,
820
+ variantOption,
821
+ variantConfig,
822
+ schema,
823
+ theme,
824
+ previewOptions,
825
+ emit,
826
+ currentStyles: styles
827
+ });
828
+ } else if (isVariantConfigWithProperties(variantConfig)) styles = emitUniversalLayers({
829
+ componentName,
830
+ subComponentName: subComponentKey,
831
+ variantKey,
832
+ variantOption,
833
+ layers: variantConfig.layers,
834
+ schema,
835
+ theme,
836
+ previewOptions,
837
+ emit,
838
+ currentStyles: styles
839
+ });
598
840
  }
599
841
  }
600
842
  /**
@@ -627,8 +869,8 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
627
869
  * @param previewOptions - Options for generating preview mode class modifiers
628
870
  * @returns CSS styles object with grouped selectors for default aliases
629
871
  */
630
- const generateStyles = (config, schema, theme, previewOptions) => {
631
- const styles = generateConfigStyles(config, schema, theme, previewOptions);
872
+ const generateStylesInner = (config, schema, theme, previewOptions) => {
873
+ const styles = generateConfigStyles(config, schema, theme, previewOptions, previewOptions.emit ?? "exhaustive");
632
874
  if (!config.variants && !config.subComponents) return styles;
633
875
  const componentName = config.label.toLowerCase();
634
876
  if (componentName !== "button" && componentName !== "iconbutton") return styles;
@@ -636,14 +878,15 @@ const generateStyles = (config, schema, theme, previewOptions) => {
636
878
  /**
637
879
  * Helper: Extract all layer keys from a variant configuration
638
880
  * Handles both simple variants (with direct layers) and variants with component states
881
+ * (which may additionally declare top-level universal layers).
639
882
  */
640
883
  const getLayerKeys = (variantConfig) => {
641
- if (isVariantConfigWithProperties(variantConfig)) return Object.keys(variantConfig.layers);
642
- else if (isVariantConfigWithComponentStates(variantConfig)) {
884
+ if (isVariantConfigWithComponentStates(variantConfig)) {
643
885
  const layerKeysSet = /* @__PURE__ */ new Set();
644
- for (const componentStateConfig of Object.values(variantConfig.componentStates)) Object.keys(componentStateConfig.layers).forEach((key) => layerKeysSet.add(key));
886
+ for (const componentStateConfig of Object.values(variantConfig.componentStates)) Object.keys(componentStateConfig.layers ?? {}).forEach((key) => layerKeysSet.add(key));
887
+ if (variantConfig.layers) Object.keys(variantConfig.layers).forEach((key) => layerKeysSet.add(key));
645
888
  return Array.from(layerKeysSet);
646
- }
889
+ } else if (isVariantConfigWithProperties(variantConfig)) return Object.keys(variantConfig.layers);
647
890
  return [];
648
891
  };
649
892
  /**
@@ -693,7 +936,39 @@ const generateStyles = (config, schema, theme, previewOptions) => {
693
936
  }
694
937
  return finalStyles;
695
938
  };
939
+ /**
940
+ * Public entry point. Generates a component's CSS, emitting each declared state
941
+ * as its own rule (one selector per rule) so the cascade is carried entirely by
942
+ * per-rule specificity — which CSS minifiers preserve.
943
+ *
944
+ * An earlier optimization merged rules sharing a declaration block into a single
945
+ * comma-separated selector list (to avoid repeating invariant declarations per
946
+ * state). It was removed: a minifier's forgiving-`:is()` rewrite — applied to a
947
+ * comma-separated list that contains `:has()` when targeting browsers without
948
+ * native `:has()` support — collapses the list to its single highest
949
+ * specificity, inflating the weakest selector (`rest`) above genuinely
950
+ * customized states and corrupting the cascade. Separate rules never form such a
951
+ * list, so minifiers leave their specificity intact. (gzip already collapses the
952
+ * repeated declaration blocks, so the shipped-size cost is minimal.)
953
+ */
954
+ const generateStyles = (config, schema, theme, previewOptions) => generateStylesInner(config, schema, theme, previewOptions);
955
+ /**
956
+ * Throws if `values` contains a duplicate entry. Runs at config-import time so
957
+ * a typo like `atomicStates: ['hover', 'hover']` fails the UDS build instead
958
+ * of silently degrading the configurator's sidebar (where the resolver would
959
+ * emit two entries for the same state).
960
+ */
961
+ function assertNoDuplicates(values, field, ownerLabel) {
962
+ if (!values) return;
963
+ const seen = /* @__PURE__ */ new Set();
964
+ for (const v of values) {
965
+ if (seen.has(v)) throw new Error(`Duplicate "${v}" in ${field} on ${ownerLabel}. Each entry must appear at most once.`);
966
+ seen.add(v);
967
+ }
968
+ }
696
969
  function createConfigurableProperty(prop) {
970
+ assertNoDuplicates(prop.pseudoStates, "pseudoStates", `property "${prop.label}"`);
971
+ assertNoDuplicates(prop.excludeAtomics, "excludeAtomics", `property "${prop.label}"`);
697
972
  return prop;
698
973
  }
699
974
  function createVariantConfig(config) {
@@ -709,10 +984,44 @@ function createComponentStates(config) {
709
984
  return config;
710
985
  }
711
986
  function createLayerConfig(config) {
987
+ assertNoDuplicates(config.atomicStates, "atomicStates", `layer "${config.label}"`);
988
+ assertNoSkipRestStateOnAtomicLayer(config);
712
989
  return config;
713
990
  }
991
+ /**
992
+ * Disallows pairing `skipRestState: true` properties with a layer that uses
993
+ * `atomicStates`. The combination breaks exhaustive emission's cascade
994
+ * resolution:
995
+ *
996
+ * Under `atomicStates`, `generateDeclaration` emits every declared state and
997
+ * resolves each non-customized compound through `resolveSlotByCascade`, so a
998
+ * deliberate atom customization (e.g. `hover`) flows into every compound that
999
+ * inherits from it (`invalid&hover`, …). That inheritance is what keeps the
1000
+ * higher-specificity compound rules from cancelling a lower-specificity atom
1001
+ * customization.
1002
+ *
1003
+ * But `buildPropertyStateMap` force-marks EVERY slot of a `skipRestState`
1004
+ * property `isEnabled: true` (there's no `rest` fall-through, so each state must
1005
+ * carry its own value). `resolveSlotByCascade` returns an enabled slot as-is,
1006
+ * so each force-enabled compound emits the property's *default* value instead of
1007
+ * inheriting a sibling atom's customization — and the compound's higher
1008
+ * specificity then silently overrides that customization (e.g. a customized
1009
+ * `hover` is cancelled by an unmodified `invalid&hover` carrying the default).
1010
+ *
1011
+ * Resolution path when this becomes a real need (currently the only
1012
+ * `skipRestState` properties are Button's `opacity` and `scaleEffect`, and
1013
+ * Button is on legacy `pseudoStates`):
1014
+ * teach `generateDeclaration` to skip compound state emission entirely for
1015
+ * `skipRestState` properties — atom rules cascade naturally, and designers
1016
+ * who want fine compound control simply drop `skipRestState` for that
1017
+ * property.
1018
+ */
1019
+ function assertNoSkipRestStateOnAtomicLayer(config) {
1020
+ if (!config.atomicStates || config.atomicStates.length === 0) return;
1021
+ for (const [propertyKey, property] of Object.entries(config.properties)) if (property.skipRestState) throw new Error(`Property "${propertyKey}" on layer "${config.label}" uses skipRestState: true, but the layer declares atomicStates. This combination isn't currently supported — see the comment on assertNoSkipRestStateOnAtomicLayer for the trade-offs and resolution path. For now, either drop skipRestState on this property or keep the layer on legacy per-property pseudoStates.`);
1022
+ }
714
1023
  function createSubComponentConfig(config) {
715
1024
  return config;
716
1025
  }
717
1026
  //#endregion
718
- export { applyBoxShadowBorder, createComponentStates, createConfigurableProperty, createLayerConfig, createSubComponentConfig, createVariantConfig, createVariantConfigWithComponentStates, createVariantConfigWithProperties, generateClassName, generateConfigStyles, generateDeclaration, generateStyles, statePseudoMapDocsMode };
1027
+ export { applyBoxShadowBorder, createComponentStates, createConfigurableProperty, createLayerConfig, createSubComponentConfig, createVariantConfig, createVariantConfigWithComponentStates, createVariantConfigWithProperties, generateClassName, generateConfigStyles, generateDeclaration, generateStyles, mergeUniversalUnderOverride, statePseudoMapDocsMode };