@yahoo/uds 3.156.2 → 3.157.1

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 (180) 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 +3078 -3089
  6. package/dist/automated-config/dist/generated/generatedConfigs.d.cts +158 -141
  7. package/dist/automated-config/dist/generated/generatedConfigs.d.ts +158 -141
  8. package/dist/automated-config/dist/generated/generatedConfigs.js +3078 -3089
  9. package/dist/automated-config/dist/generated/universalTokensConfigAuto.cjs +1217 -491
  10. package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.cts +4 -1
  11. package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.ts +4 -1
  12. package/dist/automated-config/dist/generated/universalTokensConfigAuto.js +1217 -491
  13. package/dist/automated-config/dist/properties.cjs +9 -2
  14. package/dist/automated-config/dist/properties.d.cts +23 -0
  15. package/dist/automated-config/dist/properties.d.ts +23 -0
  16. package/dist/automated-config/dist/properties.js +9 -2
  17. package/dist/automated-config/dist/types/ComponentConfig.d.cts +77 -4
  18. package/dist/automated-config/dist/types/ComponentConfig.d.ts +77 -4
  19. package/dist/automated-config/dist/types/ConfigSchema.d.cts +14 -2
  20. package/dist/automated-config/dist/types/ConfigSchema.d.ts +14 -2
  21. package/dist/automated-config/dist/types/StateAxis.cjs +90 -0
  22. package/dist/automated-config/dist/types/StateAxis.d.cts +70 -0
  23. package/dist/automated-config/dist/types/StateAxis.d.ts +70 -0
  24. package/dist/automated-config/dist/types/StateAxis.js +84 -0
  25. package/dist/automated-config/dist/utils/buildConfigSchema.cjs +105 -82
  26. package/dist/automated-config/dist/utils/buildConfigSchema.d.cts +41 -12
  27. package/dist/automated-config/dist/utils/buildConfigSchema.d.ts +41 -12
  28. package/dist/automated-config/dist/utils/buildConfigSchema.js +106 -83
  29. package/dist/automated-config/dist/utils/canonicalizeStateKey.cjs +32 -0
  30. package/dist/automated-config/dist/utils/canonicalizeStateKey.d.cts +48 -0
  31. package/dist/automated-config/dist/utils/canonicalizeStateKey.d.ts +48 -0
  32. package/dist/automated-config/dist/utils/canonicalizeStateKey.js +31 -0
  33. package/dist/automated-config/dist/utils/getButtonControlHeight.cjs +129 -0
  34. package/dist/automated-config/dist/utils/getButtonControlHeight.d.cts +133 -0
  35. package/dist/automated-config/dist/utils/getButtonControlHeight.d.ts +133 -0
  36. package/dist/automated-config/dist/utils/getButtonControlHeight.js +122 -0
  37. package/dist/automated-config/dist/utils/getButtonControlHeightPx.cjs +114 -0
  38. package/dist/automated-config/dist/utils/getButtonControlHeightPx.d.cts +78 -0
  39. package/dist/automated-config/dist/utils/getButtonControlHeightPx.d.ts +78 -0
  40. package/dist/automated-config/dist/utils/getButtonControlHeightPx.js +108 -0
  41. package/dist/automated-config/dist/utils/getConfigComponentVariant.d.cts +8 -0
  42. package/dist/automated-config/dist/utils/getConfigComponentVariant.d.ts +8 -0
  43. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +3 -3
  44. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +3 -3
  45. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.cjs +12 -5
  46. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.d.cts +8 -1
  47. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.d.ts +8 -1
  48. package/dist/automated-config/dist/utils/getConfigVariantPseudoStates.js +12 -5
  49. package/dist/automated-config/dist/utils/iconButtonMatchButtonHeight.cjs +110 -0
  50. package/dist/automated-config/dist/utils/iconButtonMatchButtonHeight.d.cts +19 -0
  51. package/dist/automated-config/dist/utils/iconButtonMatchButtonHeight.d.ts +19 -0
  52. package/dist/automated-config/dist/utils/iconButtonMatchButtonHeight.js +108 -0
  53. package/dist/automated-config/dist/utils/index.cjs +478 -111
  54. package/dist/automated-config/dist/utils/index.d.cts +76 -15
  55. package/dist/automated-config/dist/utils/index.d.ts +76 -15
  56. package/dist/automated-config/dist/utils/index.js +479 -113
  57. package/dist/automated-config/dist/utils/isConfiguratorPropertyVisible.cjs +15 -0
  58. package/dist/automated-config/dist/utils/isConfiguratorPropertyVisible.d.cts +20 -0
  59. package/dist/automated-config/dist/utils/isConfiguratorPropertyVisible.d.ts +20 -0
  60. package/dist/automated-config/dist/utils/isConfiguratorPropertyVisible.js +15 -0
  61. package/dist/automated-config/dist/utils/pseudoStateSelectors.cjs +122 -0
  62. package/dist/automated-config/dist/utils/pseudoStateSelectors.d.cts +80 -0
  63. package/dist/automated-config/dist/utils/pseudoStateSelectors.d.ts +80 -0
  64. package/dist/automated-config/dist/utils/pseudoStateSelectors.js +120 -0
  65. package/dist/automated-config/dist/utils/resolvePropertyStates.cjs +131 -0
  66. package/dist/automated-config/dist/utils/resolvePropertyStates.d.cts +49 -0
  67. package/dist/automated-config/dist/utils/resolvePropertyStates.d.ts +49 -0
  68. package/dist/automated-config/dist/utils/resolvePropertyStates.js +130 -0
  69. package/dist/automated-config/dist/utils/resolveSlotByCascade.cjs +118 -0
  70. package/dist/automated-config/dist/utils/resolveSlotByCascade.d.cts +68 -0
  71. package/dist/automated-config/dist/utils/resolveSlotByCascade.d.ts +68 -0
  72. package/dist/automated-config/dist/utils/resolveSlotByCascade.js +117 -0
  73. package/dist/automated-config/dist/utils/variantConfigGuards.d.cts +13 -0
  74. package/dist/automated-config/dist/utils/variantConfigGuards.d.ts +13 -0
  75. package/dist/components/client/Button.cjs +3 -3
  76. package/dist/components/client/Button.js +3 -3
  77. package/dist/components/client/Input/Input.cjs +42 -6
  78. package/dist/components/client/Input/Input.d.cts +13 -0
  79. package/dist/components/client/Input/Input.d.ts +13 -0
  80. package/dist/components/client/Input/Input.js +42 -6
  81. package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
  82. package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
  83. package/dist/config/dist/index.cjs +224 -553
  84. package/dist/config/dist/index.js +224 -553
  85. package/dist/css/dist/commands/css.cjs +1 -0
  86. package/dist/css/dist/commands/css.helpers.cjs +6 -0
  87. package/dist/css/dist/commands/css.helpers.js +6 -0
  88. package/dist/css/dist/commands/css.js +1 -0
  89. package/dist/css/dist/css/generate.cjs +4 -2
  90. package/dist/css/dist/css/generate.d.cts +28 -0
  91. package/dist/css/dist/css/generate.d.ts +28 -0
  92. package/dist/css/dist/css/generate.helpers.cjs +5 -1
  93. package/dist/css/dist/css/generate.helpers.js +6 -2
  94. package/dist/css/dist/css/generate.js +4 -2
  95. package/dist/css/dist/css/postcss.cjs +81 -0
  96. package/dist/css/dist/css/postcss.helpers.cjs +60 -0
  97. package/dist/css/dist/css/postcss.helpers.js +59 -1
  98. package/dist/css/dist/css/postcss.js +82 -2
  99. package/dist/css/dist/css/runner.cjs +12 -2
  100. package/dist/css/dist/css/runner.js +12 -2
  101. package/dist/css/dist/css/theme.d.cts +6 -0
  102. package/dist/css/dist/css/theme.d.ts +6 -0
  103. package/dist/css/dist/packages/automated-config/dist/properties.cjs +9 -2
  104. package/dist/css/dist/packages/automated-config/dist/properties.js +9 -2
  105. package/dist/css/dist/packages/automated-config/dist/utils/index.d.cts +6 -0
  106. package/dist/css/dist/packages/automated-config/dist/utils/index.d.ts +6 -0
  107. package/dist/css/dist/packages/config/dist/index.cjs +224 -553
  108. package/dist/css/dist/packages/config/dist/index.js +224 -553
  109. package/dist/css/dist/utils/optimizeCSS.cjs +59 -0
  110. package/dist/css/dist/utils/optimizeCSS.js +59 -0
  111. package/dist/css-tokens/dist/index.cjs +2 -0
  112. package/dist/css-tokens/dist/index.d.cts +2 -1
  113. package/dist/css-tokens/dist/index.d.ts +2 -1
  114. package/dist/css-tokens/dist/index.js +2 -1
  115. package/dist/index.cjs +48 -0
  116. package/dist/index.d.cts +15 -4
  117. package/dist/index.d.ts +15 -4
  118. package/dist/index.js +14 -3
  119. package/dist/styles/styler.d.cts +8 -7
  120. package/dist/styles/styler.d.ts +8 -7
  121. package/dist/styles/variants.d.cts +9 -4
  122. package/dist/styles/variants.d.ts +9 -4
  123. package/dist/tailwind-internal/dist/packages/automated-config/dist/generated/generatedConfigs.cjs +3078 -3089
  124. package/dist/tailwind-internal/dist/packages/automated-config/dist/generated/generatedConfigs.js +3078 -3089
  125. package/dist/tailwind-internal/dist/packages/automated-config/dist/properties.cjs +9 -2
  126. package/dist/tailwind-internal/dist/packages/automated-config/dist/properties.js +9 -2
  127. package/dist/tailwind-internal/dist/packages/automated-config/dist/types/StateAxis.cjs +81 -0
  128. package/dist/tailwind-internal/dist/packages/automated-config/dist/types/StateAxis.js +76 -0
  129. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/canonicalizeStateKey.cjs +33 -0
  130. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/canonicalizeStateKey.js +32 -0
  131. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/componentStatePseudoStates.cjs +0 -7
  132. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/componentStatePseudoStates.js +1 -7
  133. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/getButtonControlHeight.cjs +126 -0
  134. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/getButtonControlHeight.js +123 -0
  135. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/iconButtonMatchButtonHeight.cjs +20 -0
  136. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/iconButtonMatchButtonHeight.js +20 -0
  137. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.cjs +422 -111
  138. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.d.cts +6 -0
  139. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.d.ts +6 -0
  140. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/index.js +423 -112
  141. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/pseudoStateSelectors.cjs +122 -0
  142. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/pseudoStateSelectors.js +121 -0
  143. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolvePropertyStates.cjs +132 -0
  144. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolvePropertyStates.js +131 -0
  145. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolveSlotByCascade.cjs +95 -0
  146. package/dist/tailwind-internal/dist/packages/automated-config/dist/utils/resolveSlotByCascade.js +95 -0
  147. package/dist/tailwind-internal/dist/packages/config/dist/index.cjs +224 -553
  148. package/dist/tailwind-internal/dist/packages/config/dist/index.js +224 -553
  149. package/dist/tailwind-internal/dist/packages/css-tokens/dist/index.cjs +2 -0
  150. package/dist/tailwind-internal/dist/packages/css-tokens/dist/index.js +2 -1
  151. package/dist/tailwind-internal/dist/plugins/components.cjs +28 -24
  152. package/dist/tailwind-internal/dist/plugins/components.js +28 -24
  153. package/dist/tailwind-internal/dist/utils/composeTailwindPlugins.d.cts +3 -0
  154. package/dist/tailwind-internal/dist/utils/composeTailwindPlugins.d.ts +3 -0
  155. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.cts +2 -2
  156. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.ts +2 -2
  157. package/dist/tokens/automation/index.cjs +47 -0
  158. package/dist/tokens/automation/index.d.cts +13 -2
  159. package/dist/tokens/automation/index.d.ts +13 -2
  160. package/dist/tokens/automation/index.js +13 -2
  161. package/dist/tokens/consts/cssTokens.cjs +1 -0
  162. package/dist/tokens/consts/cssTokens.d.cts +2 -2
  163. package/dist/tokens/consts/cssTokens.d.ts +2 -2
  164. package/dist/tokens/consts/cssTokens.js +2 -2
  165. package/dist/tokens/index.cjs +48 -0
  166. package/dist/tokens/index.d.cts +15 -4
  167. package/dist/tokens/index.d.ts +15 -4
  168. package/dist/tokens/index.js +14 -3
  169. package/dist/tokens/types.d.cts +1 -1
  170. package/dist/tokens/types.d.ts +1 -1
  171. package/dist/uds/generated/componentData.cjs +2177 -2172
  172. package/dist/uds/generated/componentData.js +2177 -2172
  173. package/dist/uds/generated/migrationSchemaVersion.cjs +1 -1
  174. package/dist/uds/generated/migrationSchemaVersion.js +1 -1
  175. package/dist/uds/generated/tailwindPurge.cjs +79 -78
  176. package/dist/uds/generated/tailwindPurge.js +79 -78
  177. package/generated/componentData.json +2718 -2713
  178. package/generated/migrationSchemaVersion.ts +1 -1
  179. package/generated/tailwindPurge.ts +2 -2
  180. package/package.json +1 -1
@@ -2,11 +2,16 @@
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 { atomicAndCompoundStateKeys, resolvePropertyStates } from "./resolvePropertyStates.js";
7
9
  import { isVariantConfigWithComponentStates, isVariantConfigWithProperties } from "./variantConfigGuards.js";
8
10
  import { findFixtureTypeForValue } from "./buildConfigSchema.js";
9
11
  import { generateDefaultClassName } from "./generateDefaultClassName.js";
12
+ import { applyButtonControlHeightDeclarations, applyIconButtonControlHeightDeclarations, getButtonContentLineHeight } from "./getButtonControlHeight.js";
13
+ import { getStateDocsClass, getStateSelector } from "./pseudoStateSelectors.js";
14
+ import { resolveSlotByCascade } from "./resolveSlotByCascade.js";
10
15
  import { isFunction, mergeWith } from "lodash-es";
11
16
  //#region ../tailwind-internal/dist/packages/automated-config/dist/utils/index.js
12
17
  /*! © 2026 Yahoo, Inc. UDS Tailwind Internal v0.0.0-development */
@@ -61,47 +66,59 @@ const COMPONENTS_WITH_SHADOW_BORDERS = [
61
66
  }
62
67
  ];
63
68
  /**
64
- * Map our "states" to pseudo-classes (hover => :hover, pressed => :active, etc.).
65
- * Adjust or extend as needed.
69
+ * Legacy state keys still used by unmigrated component configs via per-property
70
+ * `pseudoStates` arrays. They aren't in the new `StateAxis` taxonomy (so the
71
+ * resolver/StateBuilder don't auto-compose them) but they must remain in
72
+ * `KNOWN_STATE_KEYS` so the docs-mode map / configurator safelist still cover
73
+ * configs that emit them. Drop entries from this list as components migrate.
66
74
  */
67
- const statePseudoMap = {
68
- rest: "",
69
- hover: ":hover:not(:active, :disabled, :has(:disabled))",
70
- pressed: ":active:not(:disabled, :has(:disabled))",
71
- disabled: ":is(:disabled, :has(:disabled))",
72
- visited: ":visited",
73
- focused: ":focus",
74
- "focus-within": ":focus-within",
75
- "focused-keyboard": ":focus-visible",
76
- readonly: ":has(input:read-only)",
77
- invalid: ":has(input[aria-invalid=\"true\"])",
78
- "invalid&hover": ":has(input[aria-invalid=\"true\"]):hover:not(:active, :disabled, :has(:disabled))",
79
- "invalid&pressed": ":has(input[aria-invalid=\"true\"]):active:not(:disabled, :has(:disabled))"
80
- };
81
- const statePseudoMapDocsMode = {
82
- rest: "",
83
- hover: "hover",
84
- pressed: "active",
85
- disabled: "has-disabled",
86
- visited: "visited",
87
- focused: "focus",
88
- "focus-within": "focus-within",
89
- "focused-keyboard": "focus-visible",
90
- readonly: "input-readonly",
91
- invalid: "has-input-invalid",
92
- "invalid&hover": "has-input-invalid-and-hover",
93
- "invalid&pressed": "has-input-invalid-and-active"
94
- };
75
+ const LEGACY_STATE_KEYS = [
76
+ "disabled",
77
+ "focused",
78
+ "focused-keyboard"
79
+ ];
95
80
  /**
96
- * Generates button line-height with icon size minimum.
97
- * Ensures button line-height is at least as tall as the icon to prevent clipping.
98
- * @returns Enhanced line-height CSS value with max(), or original value if icon size unavailable
81
+ * Enumerates every canonical state key the system supports: rest, every atom,
82
+ * every modifier-subset (up to {@link MAX_MODIFIERS_PER_COMPOUND}) on its own
83
+ * and combined with each interactive, plus any legacy keys still in use.
84
+ *
85
+ * Mirrors `resolvePropertyStates` exactly so what the resolver pre-emits in
86
+ * the schema, what the StateBuilder lets users compose, and what the docs
87
+ * map / configurator safelist preserve are all the same set.
99
88
  */
100
- function getButtonLineHeightWithIconMinimum({ lineHeight, schema, iconLayerKey, state, theme }) {
101
- const iconSizeValue = schema.variables?.[iconLayerKey]?.size?.[state]?.value;
102
- if (iconSizeValue) return `max(${lineHeight}, ${theme(configurableProperties.iconSize.twThemePath("iconSizes", iconSizeValue))})`;
103
- return lineHeight;
89
+ function enumerateAllStateKeys() {
90
+ const states = ["rest"];
91
+ const atoms = [...INTERACTIVE_ATOMICS, ...MODIFIER_ATOMICS].sort(comparePriority);
92
+ for (const stateKey of atomicAndCompoundStateKeys(atoms)) states.push(stateKey);
93
+ for (const legacy of LEGACY_STATE_KEYS) states.push(legacy);
94
+ return states;
104
95
  }
96
+ const KNOWN_STATE_KEYS = enumerateAllStateKeys();
97
+ /**
98
+ * Lookup of every known state key to its index in `KNOWN_STATE_KEYS` — i.e. the
99
+ * resolver's emission order. The CSS generator iterates property-state maps
100
+ * in this order (instead of the alphabetical insertion order produced by
101
+ * `syncYosConfig`'s `normalizeConfig`), so cascade tie-breaking under the
102
+ * uniform per-atom specificity actually follows the priority chain. Unknown
103
+ * keys sort to the end.
104
+ */
105
+ const KNOWN_STATE_RANK = new Map(KNOWN_STATE_KEYS.map((key, index) => [key, index]));
106
+ function compareStateKeys(a, b) {
107
+ const ra = KNOWN_STATE_RANK.get(a) ?? Number.POSITIVE_INFINITY;
108
+ const rb = KNOWN_STATE_RANK.get(b) ?? Number.POSITIVE_INFINITY;
109
+ if (ra === rb) return a < b ? -1 : a > b ? 1 : 0;
110
+ return ra - rb;
111
+ }
112
+ function buildStateRecord(transform) {
113
+ const record = {};
114
+ for (const key of KNOWN_STATE_KEYS) record[key] = transform(key);
115
+ return record;
116
+ }
117
+ buildStateRecord(getStateDocsClass);
118
+ /**
119
+ * Layout line-height for button root: icon size only (not textVariant line-height).
120
+ * @see getButtonContentLineHeight
121
+ */
105
122
  /**
106
123
  * Shared pagination control content size: max(icon size, text line-height).
107
124
  * Keeps page numbers and prev/next icons vertically centered when typography exceeds icon height.
@@ -234,7 +251,65 @@ const getTheCssPropertyValue = (schema, theme, propertyName, schemaStateValue, e
234
251
  if (propertyConfig.concatenate && existingValue) return `${existingValue}${propertyConfig.concatenationDelimiter || ", "}${newValue}`;
235
252
  return newValue;
236
253
  };
237
- function generateDeclaration({ componentName, subComponentName, variantKey, variantValue, layer, layerOptionalPseudoSelector, componentStateKey, componentStateValue, schema, propertyKey, originalPropertyDefinition, theme, currentStyles, previewOptions, excludedPseudoStates = [] }) {
254
+ /**
255
+ * Builds the per-state resolution map for a per-componentState OVERRIDE in
256
+ * exhaustive mode: the universal layer's state map with the override's ENABLED
257
+ * (and `rest`) slots layered on top. An unset or disabled override slot defers
258
+ * to the universal layer's value, so `resolveSlotByCascade` picks the
259
+ * most-specific *enabled* slot across both layers (override winning ties) rather
260
+ * than collapsing every unset state to the override's own `rest`.
261
+ */
262
+ function mergeUniversalUnderOverride(universal, override) {
263
+ const merged = { ...universal };
264
+ const overrideRecord = override;
265
+ for (const state of Object.keys(overrideRecord)) {
266
+ const slot = overrideRecord[state];
267
+ if (state === "rest" && slot?.isEnabled !== false || slot?.isEnabled === true) merged[state] = slot;
268
+ }
269
+ return merged;
270
+ }
271
+ /**
272
+ * Replays SELECTIVE emission for a STANDALONE atomicStates layer (no universal
273
+ * fallback) and returns the sparse set of slots it would emit: `rest`, every
274
+ * explicitly-enabled state, and every cascade-correction. Mirrors the inline
275
+ * selective decision in `generateDeclaration` — keep the two in lock-step.
276
+ *
277
+ * The override path seeds its own correction accumulator with this for the
278
+ * UNIVERSAL layer. Universal layers are emitted in a separate pass at the SAME
279
+ * specificity tier as their per-option overrides (see `bumpRootSpecificity`), so
280
+ * at runtime a universal rule wins wherever the override emits nothing. Without
281
+ * this seed, an override that flattens a state to `rest` (e.g. a `filled` help
282
+ * text that's `muted` everywhere) silently inherits the universal's brighter
283
+ * rule for that state in selective mode — a divergence from exhaustive, where
284
+ * the override emits every state explicitly. Seeding makes the override emit a
285
+ * correction whenever the universal would otherwise render a different value.
286
+ */
287
+ function selectiveEmittedStates(stateMap, orderedStateKeys, emittableStates) {
288
+ const emitted = { rest: stateMap.rest };
289
+ for (const stateKey of orderedStateKeys) {
290
+ if (stateKey === "rest" || !emittableStates.has(stateKey)) continue;
291
+ const value = resolveSlotByCascade(stateKey, stateMap);
292
+ if (!value) continue;
293
+ if (!(stateMap[stateKey]?.isEnabled === true)) {
294
+ if (resolveSlotByCascade(stateKey, emitted)?.value === value.value) continue;
295
+ }
296
+ emitted[stateKey] = {
297
+ ...value,
298
+ isEnabled: true
299
+ };
300
+ }
301
+ return emitted;
302
+ }
303
+ function generateDeclaration({ componentName, subComponentName, variantKey, variantValue, layer, layerOptionalPseudoSelector, componentStateKey, componentStateValue, schema, propertyKey, originalPropertyDefinition, declaredStates, layerUsesAtomicStates, theme, currentStyles, previewOptions, excludedPseudoStates = [], emit, fallbackStateMap, bumpRootSpecificity, buttonHeightReferenceSchema }) {
304
+ const shouldUseExhaustive = (emit ?? "exhaustive") === "exhaustive" && layerUsesAtomicStates;
305
+ const { cssProperties: configuredCssProperties, extendedProperties: configuredExtendedGetter } = configurableProperties[originalPropertyDefinition.name];
306
+ const configuredExtendedProperties = isFunction(configuredExtendedGetter) ? configuredExtendedGetter({
307
+ componentName,
308
+ subComponentName,
309
+ layer,
310
+ propertyKey
311
+ }) : configuredExtendedGetter;
312
+ if (!(typeof configuredCssProperties === "string" && configuredCssProperties.length > 0 || Array.isArray(configuredCssProperties) && configuredCssProperties.length > 0 || Array.isArray(configuredExtendedProperties) && configuredExtendedProperties.length > 0)) return {};
238
313
  const schemaKey = generateSchemaKey({
239
314
  variantKey,
240
315
  variantValue,
@@ -255,14 +330,29 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
255
330
  const propertyStateMap = schema.variables?.[schemaKey]?.[propertyKey];
256
331
  if (!propertyStateMap) throw new Error(`Prop definition (${componentName} - ${schemaKey} - ${propertyKey}) not found, this is not expected, please report the bug to the UDS team`);
257
332
  const styles = {};
258
- const skipRestForProperty = originalPropertyDefinition.skipRestState === true;
259
- const declaredPseudoStates = filterPseudoStatesByExclusion(originalPropertyDefinition.pseudoStates, excludedPseudoStates);
260
- const declaredPropertyStates = new Set([...skipRestForProperty ? [] : ["rest"], ...declaredPseudoStates]);
261
- for (const propStateStr in propertyStateMap) {
262
- if (!declaredPropertyStates.has(propStateStr)) continue;
333
+ const excludedStateSet = new Set(excludedPseudoStates);
334
+ const emittableStates = new Set([...declaredStates].filter((state) => !excludedStateSet.has(state)));
335
+ const orderedStateKeys = (shouldUseExhaustive || layerUsesAtomicStates ? [...emittableStates] : Object.keys(propertyStateMap)).sort(compareStateKeys);
336
+ const resolutionStates = fallbackStateMap ? mergeUniversalUnderOverride(fallbackStateMap, propertyStateMap) : propertyStateMap;
337
+ const emittedForSelective = layerUsesAtomicStates && !shouldUseExhaustive ? fallbackStateMap ? selectiveEmittedStates(fallbackStateMap, orderedStateKeys, emittableStates) : { rest: resolutionStates.rest } : {};
338
+ for (const propStateStr of orderedStateKeys) {
339
+ if (!emittableStates.has(propStateStr)) continue;
263
340
  const propertyState = propStateStr;
264
- const propertyStateSelector = statePseudoMap[propertyState] ?? "";
265
- const schemaValueForState = propertyStateMap[propertyState];
341
+ const propertyStateSelector = getStateSelector(propertyState);
342
+ const schemaValueForState = shouldUseExhaustive || layerUsesAtomicStates ? resolveSlotByCascade(propStateStr, resolutionStates) : propertyStateMap[propertyState];
343
+ if (!schemaValueForState) continue;
344
+ if (!shouldUseExhaustive) {
345
+ if (layerUsesAtomicStates) {
346
+ const isExplicitlyEnabled = propertyStateMap[propertyState]?.isEnabled === true;
347
+ if (propStateStr !== "rest" && !isExplicitlyEnabled) {
348
+ if (resolveSlotByCascade(propStateStr, emittedForSelective)?.value === schemaValueForState.value) continue;
349
+ }
350
+ emittedForSelective[propStateStr] = {
351
+ ...schemaValueForState,
352
+ isEnabled: true
353
+ };
354
+ } else if (schemaValueForState.isEnabled === false) continue;
355
+ }
266
356
  let fullClassName = ``;
267
357
  if (layer === "root") if (componentStateKey && componentStateValue) {
268
358
  const rootVariantClass = generateClassName({
@@ -281,7 +371,7 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
281
371
  componentStateValue
282
372
  });
283
373
  fullClassName = `.${rootVariantClass}${propertyStateSelector}.${className}`;
284
- } else fullClassName = `.${className}${propertyStateSelector}`;
374
+ } else fullClassName = bumpRootSpecificity ? `.${className}.${className}${propertyStateSelector}` : `.${className}${propertyStateSelector}`;
285
375
  else {
286
376
  const rootVariantClassName = generateClassName({
287
377
  componentName,
@@ -308,7 +398,17 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
308
398
  subComponentName
309
399
  });
310
400
  fullClassName = `.${rootVariantClassName}${propertyStateSelector}.${rootVariantClassNameWithComponentState} .${className}`;
311
- } else fullClassName = `.${rootVariantClassName}${propertyStateSelector} .${className}`;
401
+ } else {
402
+ className = generateClassName({
403
+ componentName,
404
+ variantKey,
405
+ variantValue,
406
+ layer,
407
+ layerOptionalPseudoSelector,
408
+ subComponentName
409
+ });
410
+ fullClassName = bumpRootSpecificity ? `.${rootVariantClassName}.${rootVariantClassName}${propertyStateSelector} .${className}` : `.${rootVariantClassName}${propertyStateSelector} .${className}`;
411
+ }
312
412
  }
313
413
  const { cssProperties, extendedProperties: extendedPropertiesGetter } = configurableProperties[originalPropertyDefinition.name];
314
414
  const cssDeclarations = {};
@@ -344,6 +444,28 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
344
444
  */
345
445
  if (componentName === "button" && layer === "root") {
346
446
  if (propertyKey === CSS_GAP) cssDeclarations[BUTTON_GAP_VAR] = cssDeclarations[CSS_GAP];
447
+ if (propertyKey === "spacingVertical") {
448
+ const paddingVertical = cssDeclarations["padding-top"];
449
+ if (paddingVertical) applyButtonControlHeightDeclarations({
450
+ cssDeclarations,
451
+ paddingVertical,
452
+ schema,
453
+ rootLayerKey: generateSchemaKey({
454
+ variantKey,
455
+ variantValue,
456
+ layer: "root",
457
+ subComponentName
458
+ }),
459
+ iconLayerKey: generateSchemaKey({
460
+ variantKey,
461
+ variantValue,
462
+ layer: "icon",
463
+ subComponentName
464
+ }),
465
+ state: propertyState,
466
+ theme
467
+ });
468
+ }
347
469
  if (propertyKey === "scaleEffect" && propertyState === "hover") {
348
470
  const rootClassName = `.${className}`;
349
471
  const renderValue = (schemaValue) => configurableProperties.scaleEffect.customValueRenderer?.(schemaValue, schema, () => "") ?? "1";
@@ -352,17 +474,39 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
352
474
  if (propertyStateMap.hover) styles[rootClassName][BUTTON_SCALE_EFFECT_HOVER] = renderValue(propertyStateMap.hover);
353
475
  if (propertyStateMap.pressed) styles[rootClassName][BUTTON_SCALE_EFFECT_PRESSED] = renderValue(propertyStateMap.pressed);
354
476
  }
355
- if (cssDeclarations[CSS_LINE_HEIGHT]) {
356
- const iconLayerKey = generateSchemaKey({
477
+ if (cssDeclarations[CSS_LINE_HEIGHT]) cssDeclarations[CSS_LINE_HEIGHT] = getButtonContentLineHeight({
478
+ schema,
479
+ rootLayerKey: generateSchemaKey({
480
+ variantKey,
481
+ variantValue,
482
+ layer: "root",
483
+ subComponentName
484
+ }),
485
+ iconLayerKey: generateSchemaKey({
357
486
  variantKey,
358
487
  variantValue,
359
488
  layer: "icon",
360
489
  subComponentName
361
- });
362
- cssDeclarations[CSS_LINE_HEIGHT] = getButtonLineHeightWithIconMinimum({
363
- lineHeight: cssDeclarations[CSS_LINE_HEIGHT],
364
- schema,
365
- iconLayerKey,
490
+ }),
491
+ state: propertyState,
492
+ theme
493
+ });
494
+ }
495
+ if (componentName === "iconbutton" && layer === "root") {
496
+ if (propertyKey === "spacing") {
497
+ const paddingVertical = cssDeclarations[CSS_PADDING];
498
+ if (paddingVertical) applyIconButtonControlHeightDeclarations({
499
+ cssDeclarations,
500
+ paddingVertical,
501
+ iconButtonSchema: schema,
502
+ buttonHeightReferenceSchema,
503
+ variantValue,
504
+ iconLayerKey: generateSchemaKey({
505
+ variantKey,
506
+ variantValue,
507
+ layer: "icon",
508
+ subComponentName
509
+ }),
366
510
  state: propertyState,
367
511
  theme
368
512
  });
@@ -450,7 +594,7 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
450
594
  ...styles[fullClassName]
451
595
  };
452
596
  if (previewOptions?.generatePseudoStateClassModifier) {
453
- const pseudoPrefixClass = statePseudoMapDocsMode[propertyState] ?? "";
597
+ const pseudoPrefixClass = getStateDocsClass(propertyState);
454
598
  if (pseudoPrefixClass.length) {
455
599
  const importantCssDeclarations = Object.fromEntries(Object.entries(cssDeclarations).map(([prop, value]) => {
456
600
  const strValue = String(value).trimEnd().replace(/;$/, "");
@@ -466,12 +610,139 @@ function generateDeclaration({ componentName, subComponentName, variantKey, vari
466
610
  }
467
611
  return styles;
468
612
  }
469
- function generateConfigStyles(config, schema, theme, previewOptions) {
613
+ /**
614
+ * Emit CSS for per-state schema entries that target a variant's universal
615
+ * layers — the "override" path. Per-state schema entries can be authored by
616
+ * the Configurator (via `setConfigPseudoStateVariable`) or written by data
617
+ * migrations; they aren't declared in source configs.
618
+ *
619
+ * Iterates the cartesian product of `componentStates.X.options × universal
620
+ * layers × universal properties`. For each combination, calls
621
+ * `generateDeclaration` with the universal property's metadata plus the
622
+ * componentState key/value — the existing schema lookup inside
623
+ * `generateDeclaration` picks up the override slot if one exists and skips
624
+ * the property otherwise.
625
+ */
626
+ function emitSchemaOverrideStyles({ componentName, subComponentName, variantKey, variantOption, variantConfig, schema, theme, previewOptions, emit, currentStyles }) {
627
+ let styles = currentStyles;
628
+ const universalLayers = variantConfig.layers;
629
+ const componentStates = variantConfig.componentStates;
630
+ if (!universalLayers || !componentStates) return styles;
631
+ const variables = schema.variables;
632
+ if (!variables) return styles;
633
+ for (const componentStateKey in componentStates) {
634
+ const componentState = componentStates[componentStateKey];
635
+ for (const componentStateOption of componentState.options) for (const layerKey in universalLayers) {
636
+ const universalLayer = universalLayers[layerKey];
637
+ const schemaEntry = variables[generateSchemaKey({
638
+ variantKey,
639
+ variantValue: variantOption,
640
+ componentStateKey,
641
+ componentStateValue: componentStateOption,
642
+ layer: layerKey,
643
+ subComponentName
644
+ })];
645
+ if (!schemaEntry) continue;
646
+ for (const propertyKey in universalLayer.properties) {
647
+ if (!schemaEntry[propertyKey]) continue;
648
+ const originalPropertyDefinition = universalLayer.properties[propertyKey];
649
+ const fallbackStateMap = variables[generateSchemaKey({
650
+ variantKey,
651
+ variantValue: variantOption,
652
+ layer: layerKey,
653
+ subComponentName
654
+ })]?.[propertyKey];
655
+ const declarations = generateDeclaration({
656
+ componentName,
657
+ subComponentName,
658
+ variantKey,
659
+ variantValue: variantOption,
660
+ componentStateKey,
661
+ componentStateValue: componentStateOption,
662
+ layer: layerKey,
663
+ layerOptionalPseudoSelector: universalLayer.pseudoSelector,
664
+ propertyKey,
665
+ originalPropertyDefinition,
666
+ declaredStates: new Set(resolvePropertyStates(universalLayer, originalPropertyDefinition)),
667
+ layerUsesAtomicStates: (universalLayer.atomicStates?.length ?? 0) > 0,
668
+ theme,
669
+ schema,
670
+ currentStyles: styles,
671
+ previewOptions,
672
+ emit,
673
+ fallbackStateMap
674
+ });
675
+ styles = deepMerge(styles, declarations);
676
+ }
677
+ }
678
+ }
679
+ return styles;
680
+ }
681
+ /**
682
+ * Emit CSS for a set of layers without a component-state segment in the
683
+ * selector. Used by both `VariantConfigWithProperties` (where layers are the
684
+ * only source of styles) and `VariantConfigWithComponentStates` (where these
685
+ * layers express the variant's universal baseline, with per-state overrides
686
+ * winning via class-compound specificity).
687
+ */
688
+ function emitUniversalLayers({ componentName, subComponentName, variantKey, variantOption, layers, schema, theme, previewOptions, emit, currentStyles, bumpRootSpecificity, buttonHeightReferenceSchema }) {
689
+ let styles = currentStyles;
690
+ const variables = schema.variables;
691
+ for (const layerKey in layers) {
692
+ const layer = layers[layerKey];
693
+ const schemaKey = generateSchemaKey({
694
+ variantKey,
695
+ variantValue: variantOption,
696
+ layer: layerKey,
697
+ subComponentName
698
+ });
699
+ const schemaEntry = variables?.[schemaKey];
700
+ for (const propertyKey in layer.properties) {
701
+ if (!schemaEntry || !schemaEntry[propertyKey]) continue;
702
+ const originalPropertyDefinition = layer.properties[propertyKey];
703
+ const declarations = generateDeclaration({
704
+ componentName,
705
+ subComponentName,
706
+ variantKey,
707
+ variantValue: variantOption,
708
+ layer: layerKey,
709
+ layerOptionalPseudoSelector: layer.pseudoSelector,
710
+ propertyKey,
711
+ originalPropertyDefinition,
712
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
713
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
714
+ theme,
715
+ schema,
716
+ currentStyles: styles,
717
+ previewOptions,
718
+ emit,
719
+ bumpRootSpecificity,
720
+ buttonHeightReferenceSchema
721
+ });
722
+ styles = deepMerge(styles, declarations);
723
+ }
724
+ }
725
+ return styles;
726
+ }
727
+ function generateConfigStyles(config, schema, theme, previewOptions, emit, generateStylesContext) {
470
728
  const componentName = config.label.toLowerCase();
471
729
  let styles = {};
472
730
  for (const variantKey in config.variants) {
473
731
  const variantConfig = config.variants[variantKey];
474
732
  for (const variantOption of variantConfig.options) if (isVariantConfigWithComponentStates(variantConfig)) {
733
+ if (variantConfig.layers) styles = emitUniversalLayers({
734
+ componentName,
735
+ variantKey,
736
+ variantOption,
737
+ layers: variantConfig.layers,
738
+ schema,
739
+ theme,
740
+ previewOptions,
741
+ emit,
742
+ currentStyles: styles,
743
+ bumpRootSpecificity: true,
744
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
745
+ });
475
746
  const componentStates = variantConfig.componentStates;
476
747
  for (const componentStateKey in componentStates) {
477
748
  const componentState = componentStates[componentStateKey];
@@ -491,46 +762,64 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
491
762
  layerOptionalPseudoSelector: layer.pseudoSelector,
492
763
  propertyKey,
493
764
  originalPropertyDefinition,
765
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
766
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
494
767
  theme,
495
768
  schema,
496
769
  currentStyles: styles,
497
770
  previewOptions,
498
- excludedPseudoStates
771
+ excludedPseudoStates,
772
+ emit,
773
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
499
774
  });
500
775
  styles = deepMerge(styles, declarations);
501
776
  }
502
777
  }
503
778
  }
504
779
  }
505
- } else if (isVariantConfigWithProperties(variantConfig)) {
506
- const layers = variantConfig.layers;
507
- for (const layerKey in layers) {
508
- const layer = layers[layerKey];
509
- for (const propertyKey in layer.properties) {
510
- const originalPropertyDefinition = layer.properties[propertyKey];
511
- const declarations = generateDeclaration({
512
- componentName,
513
- variantKey,
514
- variantValue: variantOption,
515
- layer: layerKey,
516
- layerOptionalPseudoSelector: layer.pseudoSelector,
517
- propertyKey,
518
- originalPropertyDefinition,
519
- theme,
520
- schema,
521
- currentStyles: styles,
522
- previewOptions
523
- });
524
- styles = deepMerge(styles, declarations);
525
- }
526
- }
527
- }
780
+ styles = emitSchemaOverrideStyles({
781
+ componentName,
782
+ variantKey,
783
+ variantOption,
784
+ variantConfig,
785
+ schema,
786
+ theme,
787
+ previewOptions,
788
+ emit,
789
+ currentStyles: styles
790
+ });
791
+ } else if (isVariantConfigWithProperties(variantConfig)) styles = emitUniversalLayers({
792
+ componentName,
793
+ variantKey,
794
+ variantOption,
795
+ layers: variantConfig.layers,
796
+ schema,
797
+ theme,
798
+ previewOptions,
799
+ emit,
800
+ currentStyles: styles,
801
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
802
+ });
528
803
  }
529
804
  if (config.subComponents) {
530
805
  const { subComponents } = config;
531
806
  for (const subComponentKey in subComponents) for (const variantKey in subComponents[subComponentKey].variants) {
532
807
  const variantConfig = subComponents[subComponentKey].variants[variantKey];
533
808
  for (const variantOption of variantConfig.options) if (isVariantConfigWithComponentStates(variantConfig)) {
809
+ if (variantConfig.layers) styles = emitUniversalLayers({
810
+ componentName,
811
+ subComponentName: subComponentKey,
812
+ variantKey,
813
+ variantOption,
814
+ layers: variantConfig.layers,
815
+ schema,
816
+ theme,
817
+ previewOptions,
818
+ emit,
819
+ currentStyles: styles,
820
+ bumpRootSpecificity: true,
821
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
822
+ });
534
823
  const componentStates = variantConfig.componentStates;
535
824
  for (const componentStateKey in componentStates) {
536
825
  const componentState = componentStates[componentStateKey];
@@ -551,41 +840,46 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
551
840
  layerOptionalPseudoSelector: layer.pseudoSelector,
552
841
  propertyKey,
553
842
  originalPropertyDefinition,
843
+ declaredStates: new Set(resolvePropertyStates(layer, originalPropertyDefinition)),
844
+ layerUsesAtomicStates: (layer.atomicStates?.length ?? 0) > 0,
554
845
  theme,
555
846
  schema,
556
847
  currentStyles: styles,
557
848
  previewOptions,
558
- excludedPseudoStates
849
+ excludedPseudoStates,
850
+ emit,
851
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
559
852
  });
560
853
  styles = deepMerge(styles, declarations);
561
854
  }
562
855
  }
563
856
  }
564
857
  }
565
- } else if (isVariantConfigWithProperties(variantConfig)) {
566
- const layers = variantConfig.layers;
567
- for (const layerKey in layers) {
568
- const layer = layers[layerKey];
569
- for (const propertyKey in layer.properties) {
570
- const originalPropertyDefinition = layer.properties[propertyKey];
571
- const declarations = generateDeclaration({
572
- componentName,
573
- subComponentName: subComponentKey,
574
- variantKey,
575
- variantValue: variantOption,
576
- layer: layerKey,
577
- layerOptionalPseudoSelector: layer.pseudoSelector,
578
- propertyKey,
579
- originalPropertyDefinition,
580
- theme,
581
- schema,
582
- currentStyles: styles,
583
- previewOptions
584
- });
585
- styles = deepMerge(styles, declarations);
586
- }
587
- }
588
- }
858
+ styles = emitSchemaOverrideStyles({
859
+ componentName,
860
+ subComponentName: subComponentKey,
861
+ variantKey,
862
+ variantOption,
863
+ variantConfig,
864
+ schema,
865
+ theme,
866
+ previewOptions,
867
+ emit,
868
+ currentStyles: styles
869
+ });
870
+ } else if (isVariantConfigWithProperties(variantConfig)) styles = emitUniversalLayers({
871
+ componentName,
872
+ subComponentName: subComponentKey,
873
+ variantKey,
874
+ variantOption,
875
+ layers: variantConfig.layers,
876
+ schema,
877
+ theme,
878
+ previewOptions,
879
+ emit,
880
+ currentStyles: styles,
881
+ buttonHeightReferenceSchema: generateStylesContext?.buttonHeightReferenceSchema
882
+ });
589
883
  }
590
884
  }
591
885
  /**
@@ -618,8 +912,8 @@ function generateConfigStyles(config, schema, theme, previewOptions) {
618
912
  * @param previewOptions - Options for generating preview mode class modifiers
619
913
  * @returns CSS styles object with grouped selectors for default aliases
620
914
  */
621
- const generateStyles = (config, schema, theme, previewOptions) => {
622
- const styles = generateConfigStyles(config, schema, theme, previewOptions);
915
+ const generateStylesInner = (config, schema, theme, previewOptions, generateStylesContext) => {
916
+ const styles = generateConfigStyles(config, schema, theme, previewOptions, previewOptions.emit ?? "exhaustive", generateStylesContext);
623
917
  if (!config.variants && !config.subComponents) return styles;
624
918
  const componentName = config.label.toLowerCase();
625
919
  if (componentName !== "button" && componentName !== "iconbutton") return styles;
@@ -627,14 +921,15 @@ const generateStyles = (config, schema, theme, previewOptions) => {
627
921
  /**
628
922
  * Helper: Extract all layer keys from a variant configuration
629
923
  * Handles both simple variants (with direct layers) and variants with component states
924
+ * (which may additionally declare top-level universal layers).
630
925
  */
631
926
  const getLayerKeys = (variantConfig) => {
632
- if (isVariantConfigWithProperties(variantConfig)) return Object.keys(variantConfig.layers);
633
- else if (isVariantConfigWithComponentStates(variantConfig)) {
927
+ if (isVariantConfigWithComponentStates(variantConfig)) {
634
928
  const layerKeysSet = /* @__PURE__ */ new Set();
635
- for (const componentStateConfig of Object.values(variantConfig.componentStates)) Object.keys(componentStateConfig.layers).forEach((key) => layerKeysSet.add(key));
929
+ for (const componentStateConfig of Object.values(variantConfig.componentStates)) Object.keys(componentStateConfig.layers ?? {}).forEach((key) => layerKeysSet.add(key));
930
+ if (variantConfig.layers) Object.keys(variantConfig.layers).forEach((key) => layerKeysSet.add(key));
636
931
  return Array.from(layerKeysSet);
637
- }
932
+ } else if (isVariantConfigWithProperties(variantConfig)) return Object.keys(variantConfig.layers);
638
933
  return [];
639
934
  };
640
935
  /**
@@ -684,5 +979,21 @@ const generateStyles = (config, schema, theme, previewOptions) => {
684
979
  }
685
980
  return finalStyles;
686
981
  };
982
+ /**
983
+ * Public entry point. Generates a component's CSS, emitting each declared state
984
+ * as its own rule (one selector per rule) so the cascade is carried entirely by
985
+ * per-rule specificity — which CSS minifiers preserve.
986
+ *
987
+ * An earlier optimization merged rules sharing a declaration block into a single
988
+ * comma-separated selector list (to avoid repeating invariant declarations per
989
+ * state). It was removed: a minifier's forgiving-`:is()` rewrite — applied to a
990
+ * comma-separated list that contains `:has()` when targeting browsers without
991
+ * native `:has()` support — collapses the list to its single highest
992
+ * specificity, inflating the weakest selector (`rest`) above genuinely
993
+ * customized states and corrupting the cascade. Separate rules never form such a
994
+ * list, so minifiers leave their specificity intact. (gzip already collapses the
995
+ * repeated declaration blocks, so the shipped-size cost is minimal.)
996
+ */
997
+ const generateStyles = (config, schema, theme, previewOptions, generateStylesContext) => generateStylesInner(config, schema, theme, previewOptions, generateStylesContext);
687
998
  //#endregion
688
999
  export { generateStyles };