@yahoo/uds-v5-wip 1.35.0 → 1.36.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 (51) hide show
  1. package/dist/config/dist/createConfig.d.ts +44 -0
  2. package/dist/config/dist/createConfig.js +20 -2
  3. package/dist/config/dist/defineStyleProp.d.ts +56 -0
  4. package/dist/config/dist/index.d.ts +3 -0
  5. package/dist/config/dist/index.js +2 -2
  6. package/dist/config/dist/propertyAcceptedTypes.js +65 -6
  7. package/dist/config/dist/resolveStyleProp.d.ts +62 -1
  8. package/dist/config/dist/resolveStyleProp.js +188 -2
  9. package/dist/config/dist/types/css-values.d.ts +61 -0
  10. package/dist/core/dist/compositeStyles.d.ts +1 -2
  11. package/dist/core/dist/createComponent.d.ts +1 -2
  12. package/dist/core/dist/createComponentExample.d.ts +1 -2
  13. package/dist/core/dist/createProvider.d.ts +1 -2
  14. package/dist/core/dist/generated/stylePropsTwMap.d.ts +1 -2
  15. package/dist/core/dist/getComponentStyles.d.ts +1 -2
  16. package/dist/core/dist/getStyles.d.ts +1 -2
  17. package/dist/core/dist/propMappings.d.ts +1 -2
  18. package/dist/core/dist/resolveMotionState.d.ts +1 -2
  19. package/dist/core/dist/transformPreset.d.ts +1 -2
  20. package/dist/core/dist/withDefaultStyleProps.d.ts +1 -2
  21. package/dist/foundational-presets/dist/motion.d.ts +1 -2
  22. package/dist/foundational-presets/dist/slate.d.ts +197 -198
  23. package/dist/foundational-presets/dist/sunset.d.ts +197 -198
  24. package/dist/foundational-presets/dist/terminal.d.ts +197 -198
  25. package/dist/foundational-presets/dist/warmOrganic.d.ts +197 -198
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/dist/utils/dist/array-utils/closestItem.d.ts +1 -2
  28. package/dist/utils/dist/array-utils/removeItem.d.ts +1 -2
  29. package/dist/utils/dist/component-style-defaults.d.ts +1 -2
  30. package/dist/utils/dist/math-utils/clamp.d.ts +1 -2
  31. package/dist/utils/dist/motion-utils/interpolate.d.ts +1 -2
  32. package/dist/utils/dist/object-utils/entries.d.ts +1 -2
  33. package/dist/utils/dist/object-utils/flattenObj.d.ts +1 -2
  34. package/dist/utils/dist/object-utils/fromEntries.d.ts +1 -2
  35. package/dist/utils/dist/object-utils/keys.d.ts +1 -2
  36. package/dist/utils/dist/object-utils/mapKeys.d.ts +1 -2
  37. package/dist/utils/dist/object-utils/mapValues.d.ts +1 -2
  38. package/dist/utils/dist/string-utils/arrayToUnion.d.ts +1 -2
  39. package/dist/utils/dist/string-utils/capitalize.d.ts +1 -2
  40. package/dist/utils/dist/string-utils/componentClassName.d.ts +1 -2
  41. package/dist/utils/dist/string-utils/createTemplate.d.ts +1 -2
  42. package/dist/utils/dist/string-utils/cssVar.d.ts +1 -2
  43. package/dist/utils/dist/string-utils/cssVars.d.ts +1 -2
  44. package/dist/utils/dist/string-utils/dedent.d.ts +1 -2
  45. package/dist/utils/dist/string-utils/indent.d.ts +1 -2
  46. package/dist/utils/dist/string-utils/join.d.ts +1 -2
  47. package/dist/utils/dist/string-utils/kebabCase.d.ts +1 -2
  48. package/dist/utils/dist/string-utils/split.d.ts +1 -2
  49. package/dist/utils/dist/string-utils/tsProperties.d.ts +1 -2
  50. package/dist/utils.d.ts +1 -1
  51. package/package.json +3 -3
@@ -1,5 +1,7 @@
1
+ import { AnyStyleProp } from "./defineStyleProp.js";
1
2
  import { PropertyGroupId } from "./propertyGroups.js";
2
3
  import { TokenType, VarsConfig } from "./types.js";
4
+ import { ResolvedStyleProp } from "./resolveStyleProp.js";
3
5
  import { BaseModifierProp, ComponentsConfig, CompositeStylesConfig, ConfigurableProp, ModifierProp, MotionPreset, RemotionComponentDef, RemotionConfig, RemotionTransitionDef, StyleProp } from "@uds/types";
4
6
 
5
7
  //#region ../config/dist/createConfig.d.ts
@@ -232,6 +234,23 @@ interface UdsConfigData {
232
234
  * perspective.
233
235
  */
234
236
  presetTokenNames?: Record<string, string[]>;
237
+ /**
238
+ * Style props registered via `.registerStyleProps([...])`. Authored
239
+ * elsewhere via `defineStyleProp(...)` and imported into the config.
240
+ * The canonical input for codegen + runtime in the new architecture.
241
+ *
242
+ * Map keyed by JSX prop name (e.g. `bg`, `padding`); each value is the
243
+ * style-prop record carrying `cssProperty`, `classPrefix`, `values`, etc.
244
+ */
245
+ styleProps?: Record<string, AnyStyleProp>;
246
+ /**
247
+ * Resolved style props — every registered style prop run through
248
+ * `resolveStyleProp(propName, prop, config)` at `resolveConfig` time.
249
+ * Each entry carries the prop's filtered token list, literal keywords,
250
+ * arbitrary spec, and metadata. Codegen + runtime consume this instead
251
+ * of walking the raw style-prop records.
252
+ */
253
+ resolvedStyleProps?: ResolvedStyleProp[];
235
254
  }
236
255
  interface ComponentConfig<TComponents extends ComponentsConfig<string> = ComponentsConfig<string>, TMotion extends MotionPresetsDef | undefined = MotionPresetsDef | undefined> {
237
256
  name?: string;
@@ -274,6 +293,31 @@ interface UdsConfig<TModifier extends ModifierNameShape = ModifierProp, TTokens
274
293
  tokens: TTokens;
275
294
  }) => M)): ConfigResult<TModifier, TTokens, TMotion, TExt, TCompositeStyles & M, TModeModifiers, TVars>;
276
295
  defineArbitraryTokens(params: ArbitraryTokenGroup[]): ConfigResult<TModifier, TTokens, TMotion, TExt, TCompositeStyles, TModeModifiers, TVars>;
296
+ /**
297
+ * Register style props, keyed by the JSX prop name consumers will use.
298
+ * Calls accumulate — later `.registerStyleProps({...})` calls merge into
299
+ * the existing map (later keys overwrite earlier ones with the same name).
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * uds.registerStyleProps({
304
+ * bg: {
305
+ * cssProperty: 'background-color',
306
+ * classPrefix: 'bg',
307
+ * values: ['{global}', '{spectrum}', '{bg}'],
308
+ * label: 'Background',
309
+ * },
310
+ * padding: {
311
+ * cssProperty: 'padding',
312
+ * classPrefix: 'p',
313
+ * arbitrary: 'length-percentage',
314
+ * values: ['{spacing}'],
315
+ * label: 'Padding',
316
+ * },
317
+ * });
318
+ * ```
319
+ */
320
+ registerStyleProps<const Props extends Record<string, AnyStyleProp>>(props: Props): ConfigResult<TModifier, TTokens, TMotion, TExt, TCompositeStyles, TModeModifiers, TVars>;
277
321
  defineMotion<const M extends MotionPresetsDef>(presets: M | ((tokens: TTokens) => M)): ConfigResult<TModifier, TTokens, { [K in keyof M]: string }, TExt, TCompositeStyles, TModeModifiers, TVars>;
278
322
  defineComponents(params: ComponentsConfig<MotionAliasValue<TMotion> | string> | ((ctx: {
279
323
  tokens: TTokens;
@@ -4,9 +4,10 @@ import "../../utils/dist/index.js";
4
4
  import { getConfigurablePropMapping } from "../../core/dist/propMappings.js";
5
5
  import "../../core/dist/index.js";
6
6
  import { buildMotionReference, resolveComponentMotionAliases, validateComponentVariants } from "./component-resolution.js";
7
+ import { applyPresetToData, deepMerge, mergeAtomic } from "./preset-merge.js";
7
8
  import { expandPropertyGroups } from "./propertyGroups.js";
8
9
  import { resolveTokenType, sniffTokenTypeFromValue } from "./resolveTokenTypes.js";
9
- import { applyPresetToData, deepMerge, mergeAtomic } from "./preset-merge.js";
10
+ import { resolveStyleProp } from "./resolveStyleProp.js";
10
11
  //#region ../config/dist/createConfig.js
11
12
  /** biome-ignore-all lint/suspicious/noExplicitAny: necessary for dynamic builder to work correctly */
12
13
  /**
@@ -266,7 +267,8 @@ function resolveConfig(config) {
266
267
  vars: config.vars,
267
268
  classNames: config.classNames,
268
269
  scopes: config.scopes,
269
- presetTokenNames: config.presetTokenNames
270
+ presetTokenNames: config.presetTokenNames,
271
+ styleProps: config.styleProps
270
272
  };
271
273
  if (configData.vars && configData.scopes) {
272
274
  const synthesized = synthesizeAtomicFromScopesAndVars(configData.vars, configData.scopes, configData.modes);
@@ -276,6 +278,16 @@ function resolveConfig(config) {
276
278
  atomic
277
279
  };
278
280
  }
281
+ if (configData.styleProps) {
282
+ const entries = Object.entries(configData.styleProps);
283
+ if (entries.length > 0) {
284
+ const resolved = entries.map(([propName, prop]) => resolveStyleProp(propName, prop, configData));
285
+ configData = {
286
+ ...configData,
287
+ resolvedStyleProps: resolved
288
+ };
289
+ }
290
+ }
279
291
  return configData;
280
292
  }
281
293
  function mergeRemotionConfig(existing, incoming) {
@@ -480,6 +492,12 @@ function createConfigBuilder(data, extensions) {
480
492
  defineArbitraryTokens(params) {
481
493
  return next({ arbitraryTokens: [...data.arbitraryTokens ?? [], ...params] });
482
494
  },
495
+ registerStyleProps(props) {
496
+ return next({ styleProps: {
497
+ ...data.styleProps ?? {},
498
+ ...props
499
+ } });
500
+ },
483
501
  defineMotion(presets) {
484
502
  const tokenReference = buildTokenReference(data.atomic, data.prefix);
485
503
  const resolved = typeof presets === "function" ? presets(tokenReference) : presets;
@@ -0,0 +1,56 @@
1
+ import { CssValueTypeName } from "./types/css-values.js";
2
+
3
+ //#region ../config/dist/defineStyleProp.d.ts
4
+ /** Runtime input type for `toCss` based on the entry's `type`. */
5
+ type ArbitraryRuntimeValue<T extends CssValueTypeName> = T extends 'integer' | 'number' ? number : string;
6
+ /**
7
+ * One entry in a multi-shape `arbitrary` array. The first entry whose `type`
8
+ * (or `pattern`, for `'regex'`) matches the runtime value wins.
9
+ */
10
+ type ArbitraryEntry = { [T in CssValueTypeName]: {
11
+ type: T;
12
+ toCss?: (value: ArbitraryRuntimeValue<T>) => string;
13
+ } }[CssValueTypeName] | {
14
+ type: 'regex';
15
+ pattern: RegExp;
16
+ toCss?: (value: string) => string;
17
+ };
18
+ /**
19
+ * Shape of the `arbitrary` field on a style prop:
20
+ * - A bare value-type name (`'length-percentage'`, `'color'`, etc.) for the
21
+ * single-shape case.
22
+ * - An array of {@link ArbitraryEntry} for multi-shape acceptance.
23
+ */
24
+ type ArbitrarySpec = CssValueTypeName | readonly ArbitraryEntry[];
25
+ /**
26
+ * The literal-keyword subset of values a property accepts, derived from
27
+ * {@link CssPropertyValues}[P]. For custom CSS properties (`--*`) the value
28
+ * type is governed by the required `cssType` field instead, so any string
29
+ * is accepted at the type level.
30
+ */
31
+ type StylePropMetadata = {
32
+ label?: string;
33
+ description?: string;
34
+ };
35
+ /**
36
+ * A finalized style prop. Returned by `defineStyleProp(spec).metadata(meta)`.
37
+ * Consumers wrap these in `uds.registerStyleProps({ <propName>: ... })`.
38
+ */
39
+ /**
40
+ * Structurally-loose form of {@link StyleProp}. Any concrete `StyleProp<P>`
41
+ * is assignable to this. Used at registration / resolution boundaries where
42
+ * the generic `P` would otherwise cause TS2590 by re-expanding
43
+ * `ValuesEntry<P>` across the full property union.
44
+ */
45
+ interface AnyStyleProp {
46
+ readonly kind: 'styleProp';
47
+ readonly cssProperty: string;
48
+ readonly classPrefix: string;
49
+ readonly values: readonly unknown[];
50
+ readonly arbitrary?: ArbitrarySpec;
51
+ readonly cssType?: CssValueTypeName;
52
+ readonly metadata: StylePropMetadata;
53
+ }
54
+ /** Intermediate builder — the only callable method is `.metadata()`. */
55
+ //#endregion
56
+ export { AnyStyleProp, ArbitraryEntry, ArbitrarySpec, StylePropMetadata };
@@ -1,7 +1,10 @@
1
1
  import { defaultColors } from "./consts/defaultColors.js";
2
+ import { ColorFn, ColorKeyword, CssAngle, CssColor, CssLength, CssPercentage, CssRatio, CssTime, CssValue, CssValueTypeName, HexColor, HslColor, RgbColor } from "./types/css-values.js";
3
+ import { AnyStyleProp, ArbitraryEntry, ArbitrarySpec, StylePropMetadata } from "./defineStyleProp.js";
2
4
  import { PropertyGroupId } from "./propertyGroups.js";
3
5
  import { TokenType, VarGroupDef, VarTokenDef, VarsConfig } from "./types.js";
4
6
  import { ArbitraryTokenGroup, AtomicToken, BuildOptions, CheckForReservedModifiersInput, ComponentConfig, DefineComponentInput, DefineComponentMotionInput, ExampleDef, ExampleEntryDef, ExampleLayoutStyles, GetModifierFromInput, GlobalStylesDef, InterpolateMarker, ModeGroup, ModeOption, ModeOptionInput, ModeSetInput, ModesInput, ModifierDef, MotionPresetsDef, UdsConfig, UdsConfigData, buildTokenReference, createConfigBuilder, darker, lighter, resolveConfig } from "./createConfig.js";
7
+ import { ResolvedStyleProp, ResolvedToken } from "./resolveStyleProp.js";
5
8
  import { SerializedConfig, TokenRef, buildReverseMap, deserializeConfig, serializeConfig } from "./serialize.js";
6
9
  import { ComponentsConfig as ComponentsConfig$1 } from "@uds/types";
7
10
  export { type ComponentsConfig$1 as ComponentsConfig };
@@ -1,8 +1,8 @@
1
1
  import "./consts/defaultColors.js";
2
2
  import "./component-resolution.js";
3
3
  import "./propertyGroups.js";
4
- import "./resolveTokenTypes.js";
5
- import "./createConfig.js";
6
4
  import "./propertyAcceptedTypes.js";
5
+ import "./resolveTokenTypes.js";
7
6
  import "./resolveStyleProp.js";
7
+ import "./createConfig.js";
8
8
  import "./serialize.js";
@@ -12,11 +12,53 @@ const LENGTH_PCT_AUTO = {
12
12
  ],
13
13
  literals: ["auto"]
14
14
  };
15
+ const SIZING = {
16
+ types: [
17
+ "length",
18
+ "percentage",
19
+ "length-percentage"
20
+ ],
21
+ literals: [
22
+ "auto",
23
+ "min-content",
24
+ "max-content",
25
+ "fit-content"
26
+ ]
27
+ };
28
+ const SIZING_WITH_NONE = {
29
+ types: [
30
+ "length",
31
+ "percentage",
32
+ "length-percentage"
33
+ ],
34
+ literals: [
35
+ "auto",
36
+ "min-content",
37
+ "max-content",
38
+ "fit-content",
39
+ "none"
40
+ ]
41
+ };
15
42
  const LENGTH_ONLY = { types: ["length"] };
16
- const COLOR_ONLY = { types: ["color"] };
43
+ const COLOR_ONLY = {
44
+ types: ["color"],
45
+ literals: ["transparent", "currentColor"]
46
+ };
17
47
  const TIME_ONLY = { types: ["time"] };
18
48
  const NUMBER_ONLY = { types: ["number", "integer"] };
19
49
  const ANGLE_ONLY = { types: ["angle"] };
50
+ /**
51
+ * CSS-wide keywords — accepted on every CSS property per the CSS spec.
52
+ * Synthesizer marks these as `$type: 'string'` so they don't match the
53
+ * property's type-based accept rule; they pass via this set instead.
54
+ */
55
+ const CSS_WIDE_KEYWORDS = new Set([
56
+ "inherit",
57
+ "initial",
58
+ "unset",
59
+ "revert",
60
+ "revert-layer"
61
+ ]);
20
62
  const LENGTH_PCT_PROPS = [
21
63
  "gap",
22
64
  "column-gap",
@@ -72,14 +114,15 @@ const LENGTH_PCT_AUTO_PROPS = [
72
114
  "left",
73
115
  "inset",
74
116
  "inset-block",
75
- "inset-inline",
117
+ "inset-inline"
118
+ ];
119
+ const SIZING_PROPS = [
76
120
  "width",
77
121
  "height",
78
122
  "min-width",
79
- "min-height",
80
- "max-width",
81
- "max-height"
123
+ "min-height"
82
124
  ];
125
+ const SIZING_WITH_NONE_PROPS = ["max-width", "max-height"];
83
126
  const LENGTH_ONLY_PROPS = [
84
127
  "border-width",
85
128
  "border-top-width",
@@ -124,9 +167,11 @@ const NUMBER_PROPS = [
124
167
  "-webkit-line-clamp"
125
168
  ];
126
169
  const ANGLE_PROPS = ["rotate"];
127
- new Map([
170
+ const PROPERTY_ACCEPTED_TYPES = new Map([
128
171
  ...LENGTH_PCT_PROPS.map((p) => [p, LENGTH_PCT]),
129
172
  ...LENGTH_PCT_AUTO_PROPS.map((p) => [p, LENGTH_PCT_AUTO]),
173
+ ...SIZING_PROPS.map((p) => [p, SIZING]),
174
+ ...SIZING_WITH_NONE_PROPS.map((p) => [p, SIZING_WITH_NONE]),
130
175
  ...LENGTH_ONLY_PROPS.map((p) => [p, LENGTH_ONLY]),
131
176
  ...COLOR_PROPS.map((p) => [p, COLOR_ONLY]),
132
177
  ...TIME_PROPS.map((p) => [p, TIME_ONLY]),
@@ -145,4 +190,18 @@ new Map([
145
190
  ["aspect-ratio", { types: ["ratio", "number"] }],
146
191
  ["opacity", { types: ["number", "percentage"] }]
147
192
  ]);
193
+ /**
194
+ * Whether a token with the given detected value type AND raw string value
195
+ * is accepted by the CSS property. Returns `true` for any property not in
196
+ * the table.
197
+ */
198
+ function isTokenAcceptedByProperty(cssProperty, valueType, rawValue) {
199
+ if (CSS_WIDE_KEYWORDS.has(rawValue)) return true;
200
+ const entry = PROPERTY_ACCEPTED_TYPES.get(cssProperty);
201
+ if (!entry) return true;
202
+ if (valueType && entry.types?.includes(valueType)) return true;
203
+ if (entry.literals?.includes(rawValue)) return true;
204
+ return false;
205
+ }
148
206
  //#endregion
207
+ export { PROPERTY_ACCEPTED_TYPES, isTokenAcceptedByProperty };
@@ -1 +1,62 @@
1
- export { };
1
+ import { CssValueTypeName } from "./types/css-values.js";
2
+ import { ArbitrarySpec, StylePropMetadata } from "./defineStyleProp.js";
3
+ //#region ../config/dist/resolveStyleProp.d.ts
4
+ //#region src/resolveStyleProp.d.ts
5
+ interface ResolvedToken {
6
+ /** The token's raw key, e.g. `'brand'`. */
7
+ readonly name: string;
8
+ /** Resolved CSS value, e.g. `'#1167f4'` or `'1rem'`. */
9
+ readonly value: string;
10
+ /** Detected CSS value type, used for filtering. `undefined` if not detectable. */
11
+ readonly valueType: CssValueTypeName | undefined;
12
+ /** The token group's namespace (or cssPrefix fallback) the token came from. */
13
+ readonly group: string;
14
+ /**
15
+ * Style-prop-local namespace, set only when the token was sourced via a
16
+ * {@link NamespacedGroupRef}. Used to disambiguate when two groups feed
17
+ * the same prop and share keys.
18
+ */
19
+ readonly namespace?: string;
20
+ /**
21
+ * The user-facing key the consumer writes in JSX. For un-namespaced
22
+ * groups this is just `name`; for namespaced groups, `'${namespace}.${name}'`.
23
+ */
24
+ readonly qualifiedName: string;
25
+ /**
26
+ * The token name with characters that aren't class-name-safe replaced
27
+ * (e.g. `/` → `_`, `.` → `_`). Used as the trailing segment of generated
28
+ * `@utility` class names and CSS variable names. Mirrors
29
+ * `safeTokenName` from `@uds/utils`.
30
+ */
31
+ readonly safeName: string;
32
+ /**
33
+ * Full CSS variable reference for this token at config-build time, e.g.
34
+ * `'--uds-bg-brand'`. Built as `--{config.prefix}-{group.cssPrefix}-{safeName}`,
35
+ * falling back to omit the config prefix when it's empty.
36
+ */
37
+ readonly cssVar: string;
38
+ /**
39
+ * Per-modifier value overrides carried verbatim from the source
40
+ * `AtomicTokenValue`. Used by CSS-gen to emit mode override blocks
41
+ * (e.g. `.dark { --uds-bg-brand: ... }`).
42
+ */
43
+ readonly modifiers?: Record<string, string>;
44
+ }
45
+ interface ResolvedStyleProp {
46
+ /** The JSX prop name — the map key from `registerStyleProps({...})`. */
47
+ readonly propName: string;
48
+ readonly cssProperty: string;
49
+ readonly classPrefix: string;
50
+ readonly tokens: readonly ResolvedToken[];
51
+ readonly literals: readonly string[];
52
+ readonly arbitrary: ArbitrarySpec | undefined;
53
+ readonly metadata: StylePropMetadata;
54
+ }
55
+ /**
56
+ * Structurally-loose input shape for the resolver. Any `StyleProp<P>` from
57
+ * `defineStyleProp` is assignable to this. Defined locally so the
58
+ * resolver's signature doesn't expand `ValuesEntry<P>` over the full CSS
59
+ * property union (TS2590).
60
+ */
61
+ //#endregion
62
+ export { ResolvedStyleProp, ResolvedToken };
@@ -1,2 +1,188 @@
1
- import "./resolveTokenTypes.js";
2
- import "./propertyAcceptedTypes.js";
1
+ import { safeTokenName } from "../../utils/dist/string-utils/cssVar.js";
2
+ import "../../utils/dist/index.js";
3
+ import { isTokenAcceptedByProperty } from "./propertyAcceptedTypes.js";
4
+ import { sniffTokenTypeFromValue } from "./resolveTokenTypes.js";
5
+ //#region ../config/dist/resolveStyleProp.js
6
+ /**
7
+ * Resolve a {@link StyleProp} authored via `defineStyleProp` against the
8
+ * active UDS config, producing a flat list of accepted tokens, literal
9
+ * keywords, and the arbitrary spec — the data that downstream codegen
10
+ * consumes to populate `Custom*` interfaces and emit utility CSS.
11
+ *
12
+ * Filtering invariant: a token is exposed in the resolved pool only when
13
+ * its detected CSS value type is accepted by the prop's `cssProperty`,
14
+ * per {@link PROPERTY_ACCEPTED_TYPES}. Properties absent from that table
15
+ * accept every token.
16
+ *
17
+ * The resolver is pure — given the same `(StyleProp, UdsConfigData)` input
18
+ * it returns the same output. Group lookups are by `namespace` (with a
19
+ * fallback to `cssPrefix`) on the resolved config's `atomic` array.
20
+ */
21
+ /**
22
+ * Map the legacy 8-entry `TokenType` enum to a {@link CssValueTypeName}.
23
+ * The `'dimension'` case is ambiguous (length vs. percentage); callers
24
+ * disambiguate by sniffing the value string.
25
+ */
26
+ function tokenTypeToValueType(t) {
27
+ switch (t) {
28
+ case "color": return "color";
29
+ case "dimension": return "length-percentage";
30
+ case "number": return "number";
31
+ case "fontFamily": return "font-family";
32
+ case "fontWeight": return "font-weight";
33
+ case "duration": return "time";
34
+ case "strokeStyle": return "string";
35
+ case "string": return "string";
36
+ default: return;
37
+ }
38
+ }
39
+ /**
40
+ * A value looks like a CSS shadow when it combines at least one length
41
+ * (offset/blur/spread) with a color reference. Catches both single-shadow
42
+ * (`'0 1px 2px rgba(...)'`) and multi-shadow (`'..., ...'`) forms, plus
43
+ * inset shadows. Used to refine `'string'`-typed tokens to the more precise
44
+ * `'shadow'` value type so they pass the runtime filter on `box-shadow` /
45
+ * `text-shadow` props.
46
+ */
47
+ const SHADOW_LENGTH_RE = /(?:^|[\s,])-?\d+(?:\.\d+)?(?:px|rem|em|ch|ex)/i;
48
+ const SHADOW_COLOR_RE = /(?:rgba?|hsla?|color|oklch|oklab|lch|lab|hwb)\(|#[0-9a-fA-F]{3,8}\b/;
49
+ function looksLikeShadow(value) {
50
+ const trimmed = value.trim();
51
+ return SHADOW_LENGTH_RE.test(trimmed) && SHADOW_COLOR_RE.test(trimmed);
52
+ }
53
+ /**
54
+ * Detect a token's CSS value type. Resolution order:
55
+ * 1. Per-token `type` override.
56
+ * 2. Group-level `type`.
57
+ * 3. Value sniff via {@link sniffTokenTypeFromValue}.
58
+ *
59
+ * When the resolved type is `'length-percentage'` and the raw value ends in
60
+ * `%`, narrow to `'percentage'`; otherwise narrow to `'length'`. When the
61
+ * resolved type is `'string'` but the value looks like a shadow expression,
62
+ * narrow to `'shadow'`.
63
+ */
64
+ function detectTokenValueType(token, group) {
65
+ const explicit = token.type ?? group.type;
66
+ let resolved;
67
+ if (explicit) resolved = tokenTypeToValueType(explicit);
68
+ else {
69
+ const sniffed = sniffTokenTypeFromValue(token.value);
70
+ resolved = sniffed ? tokenTypeToValueType(sniffed) : void 0;
71
+ }
72
+ if (resolved === "length-percentage") return token.value.trim().endsWith("%") ? "percentage" : "length";
73
+ if (resolved === "string" && looksLikeShadow(token.value)) return "shadow";
74
+ return resolved;
75
+ }
76
+ const REF_RE = /^\{([^.{}]+)(?:\.([^.{}]+))?\}$/;
77
+ /**
78
+ * Parse a string ref like `'{palette}'` or `'{spacing.4}'`. Returns
79
+ * `undefined` for any string that isn't a brace ref (so the caller can
80
+ * treat it as a literal keyword).
81
+ */
82
+ function parseGroupRef(raw) {
83
+ const m = REF_RE.exec(raw);
84
+ if (!m) return void 0;
85
+ const [, group, key] = m;
86
+ if (!group) return void 0;
87
+ return key !== void 0 ? {
88
+ group,
89
+ key
90
+ } : { group };
91
+ }
92
+ function findGroup(atomic, name) {
93
+ return atomic.find((g) => g.namespace === name || g.cssPrefix === name);
94
+ }
95
+ function isNamespacedRef(entry) {
96
+ return typeof entry === "object" && entry !== null && "ref" in entry && "namespace" in entry;
97
+ }
98
+ /**
99
+ * Build `--{configPrefix}-{varPrefix}-{safeName}` (or omit the configPrefix
100
+ * when empty). Mirrors `buildTokenVarName` in `@uds/codegen/css/prepareCss`.
101
+ */
102
+ function buildCssVar(configPrefix, varPrefix, safeName) {
103
+ return configPrefix ? `--${configPrefix}-${varPrefix}-${safeName}` : `--${varPrefix}-${safeName}`;
104
+ }
105
+ function resolveGroupTokens(group, cssProperty, configPrefix, namespace) {
106
+ const groupName = group.namespace ?? group.cssPrefix ?? "";
107
+ const varPrefix = group.cssPrefix ?? group.namespace ?? "";
108
+ const out = [];
109
+ for (const token of group.tokens) {
110
+ const valueType = detectTokenValueType(token, group);
111
+ if (!isTokenAcceptedByProperty(cssProperty, valueType, token.value)) continue;
112
+ const safeName = safeTokenName(token.name);
113
+ out.push({
114
+ name: token.name,
115
+ value: token.value,
116
+ valueType,
117
+ group: groupName,
118
+ namespace,
119
+ qualifiedName: namespace !== void 0 ? `${namespace}.${token.name}` : token.name,
120
+ safeName,
121
+ cssVar: buildCssVar(configPrefix, varPrefix, safeName),
122
+ modifiers: token.modifiers
123
+ });
124
+ }
125
+ return out;
126
+ }
127
+ /**
128
+ * Resolve a style prop against the given resolved UDS config. Unknown group
129
+ * refs are silently dropped from `tokens` (callers can detect this by
130
+ * comparing input refs vs. resolved tokens if they need to surface a
131
+ * config-build warning).
132
+ *
133
+ * @param propName - The JSX prop name (the map key from `registerStyleProps`).
134
+ */
135
+ function resolveStyleProp(propName, styleProp, config) {
136
+ const { cssProperty, classPrefix, values, arbitrary, metadata } = styleProp;
137
+ const configPrefix = config.prefix;
138
+ const tokens = [];
139
+ const literals = [];
140
+ for (const entry of values ?? []) {
141
+ if (typeof entry === "string") {
142
+ const parsed = parseGroupRef(entry);
143
+ if (!parsed) {
144
+ literals.push(entry);
145
+ continue;
146
+ }
147
+ const group = findGroup(config.atomic, parsed.group);
148
+ if (!group) continue;
149
+ if (parsed.key !== void 0) {
150
+ const token = group.tokens.find((t) => t.name === parsed.key);
151
+ if (!token) continue;
152
+ const valueType = detectTokenValueType(token, group);
153
+ if (!isTokenAcceptedByProperty(cssProperty, valueType, token.value)) continue;
154
+ const safeName = safeTokenName(token.name);
155
+ const varPrefix = group.cssPrefix ?? group.namespace ?? parsed.group;
156
+ tokens.push({
157
+ name: token.name,
158
+ value: token.value,
159
+ valueType,
160
+ group: group.namespace ?? group.cssPrefix ?? parsed.group,
161
+ qualifiedName: token.name,
162
+ safeName,
163
+ cssVar: buildCssVar(configPrefix, varPrefix, safeName),
164
+ modifiers: token.modifiers
165
+ });
166
+ } else tokens.push(...resolveGroupTokens(group, cssProperty, configPrefix));
167
+ continue;
168
+ }
169
+ if (isNamespacedRef(entry)) {
170
+ const parsed = parseGroupRef(entry.ref);
171
+ if (!parsed || parsed.key !== void 0) continue;
172
+ const group = findGroup(config.atomic, parsed.group);
173
+ if (!group) continue;
174
+ tokens.push(...resolveGroupTokens(group, cssProperty, configPrefix, entry.namespace));
175
+ }
176
+ }
177
+ return {
178
+ propName,
179
+ cssProperty,
180
+ classPrefix,
181
+ tokens,
182
+ literals,
183
+ arbitrary,
184
+ metadata: metadata ?? {}
185
+ };
186
+ }
187
+ //#endregion
188
+ export { resolveStyleProp };
@@ -0,0 +1,61 @@
1
+ //#region ../config/dist/types/css-values.d.ts
2
+ //#region src/types/css-values.d.ts
3
+ /**
4
+ * CSS value-type primitives — building blocks used by {@link CssPropertyValues}
5
+ * in `./css-properties` and by `defineStyleProp` to constrain authored values.
6
+ *
7
+ * Each entry in {@link CssValue} corresponds to a CSS value type name from the
8
+ * CSS specs (length, percentage, color, time, etc.). The CSS-wide keywords
9
+ * (`inherit`, `initial`, `unset`, `revert`) are bundled into {@link ColorKeyword}
10
+ * because color is the most common channel for them; properties that accept
11
+ * those keywords on non-color value types are expected to list them locally.
12
+ *
13
+ * Note: named colors (`red`, `blue`, etc.) are intentionally NOT in the union —
14
+ * authors should use a token, a hex code, or a function form (`rgb(...)`, etc.).
15
+ */
16
+ /** CSS-wide keywords accepted on color-valued properties. */
17
+ type ColorKeyword = 'transparent' | 'currentColor' | 'inherit' | 'initial' | 'unset' | 'revert';
18
+ type HexColor = `#${string}`;
19
+ type RgbColor = `rgb(${string})` | `rgba(${string})`;
20
+ type HslColor = `hsl(${string})` | `hsla(${string})`;
21
+ type ColorFn = `color(${string})` | `lab(${string})` | `lch(${string})` | `oklab(${string})` | `oklch(${string})`;
22
+ type CssColor = HexColor | RgbColor | HslColor | ColorFn | ColorKeyword;
23
+ type CssLength = `${number}px` | `${number}rem` | `${number}em` | `${number}ch` | `${number}ex` | `${number}vh` | `${number}vw` | `${number}vmin` | `${number}vmax` | 0;
24
+ type CssPercentage = `${number}%`;
25
+ type CssAngle = `${number}deg` | `${number}rad` | `${number}grad` | `${number}turn`;
26
+ type CssTime = `${number}ms` | `${number}s`;
27
+ type CssRatio = `${number}/${number}`;
28
+ /**
29
+ * Registry of CSS value types, keyed by their spec-defined names.
30
+ *
31
+ * Used in two places:
32
+ * 1. As the source of truth for what shapes count as e.g. a "length" or a
33
+ * "color" when validating token values and `defineStyleProp` `arbitrary`
34
+ * specs.
35
+ * 2. By {@link import('./css-properties').CssPropertyValues}, which composes
36
+ * these entries (plus per-property keywords) into the union accepted by
37
+ * each CSS property.
38
+ */
39
+ type CssValue = {
40
+ color: CssColor;
41
+ length: CssLength;
42
+ percentage: CssPercentage;
43
+ 'length-percentage': CssLength | CssPercentage;
44
+ number: number;
45
+ integer: number;
46
+ angle: CssAngle;
47
+ time: CssTime;
48
+ ratio: CssRatio;
49
+ image: string;
50
+ url: `url(${string})`;
51
+ 'font-weight': number | 'normal' | 'bold' | 'lighter' | 'bolder';
52
+ 'font-family': string;
53
+ 'easing-function': 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'step-start' | 'step-end' | `cubic-bezier(${string})` | `steps(${string})`;
54
+ shadow: string;
55
+ gradient: string;
56
+ ident: string;
57
+ string: string;
58
+ };
59
+ type CssValueTypeName = keyof CssValue; //#endregion
60
+ //#endregion
61
+ export { ColorFn, ColorKeyword, CssAngle, CssColor, CssLength, CssPercentage, CssRatio, CssTime, CssValue, CssValueTypeName, HexColor, HslColor, RgbColor };
@@ -1,7 +1,6 @@
1
1
  import { CompositeStylesConfig } from "@uds/types";
2
2
 
3
3
  //#region ../core/dist/compositeStyles.d.ts
4
- //#region src/compositeStyles.d.ts
5
4
  /** Set the composite-styles config (called by loader at build time) */
6
5
  declare function setCompositeStylesConfig(config: CompositeStylesConfig): void;
7
6
  /** Get the current composite-styles config */
@@ -17,6 +16,6 @@ declare function getCompositeStylesConfig(): CompositeStylesConfig;
17
16
  declare function expandCompositeStyles(props: Record<string, unknown>, config?: CompositeStylesConfig): {
18
17
  expanded: Record<string, unknown>;
19
18
  markerClasses: string[];
20
- }; //#endregion
19
+ };
21
20
  //#endregion
22
21
  export { expandCompositeStyles, getCompositeStylesConfig, setCompositeStylesConfig };
@@ -1,7 +1,6 @@
1
1
  import { CreateComponentConfig, CreateComponentProps, CreateComponentRenderFn, CreateComponentSlotTagConfig, CreateComponentTypeInput } from "@uds/types";
2
2
 
3
3
  //#region ../core/dist/createComponent.d.ts
4
- //#region src/createComponent.d.ts
5
4
  type PrimitiveTag = keyof React.JSX.IntrinsicElements;
6
5
  type SpecConfig<TSpec> = TSpec extends {
7
6
  config: infer TConfig extends CreateComponentTypeInput;
@@ -52,6 +51,6 @@ declare function createComponent<TSpecOrProps = {}>(tag: PrimitiveTag): React.FC
52
51
  props: infer TOwnProps;
53
52
  } ? CreateComponentProps<TConfig, TOwnProps, PrimitiveTag> : PrimitiveOwnProps<TSpecOrProps>>;
54
53
  declare function createComponent<TSpec>(renderFn: CreateComponentRenderFn<SpecConfig<TSpec>, SpecOwnProps<TSpec>, SpecSlotConfig<TSpec>>): React.FC<CreateComponentProps<SpecConfig<TSpec>, SpecOwnProps<TSpec>, SpecSlotConfig<TSpec>>>;
55
- declare function createComponent(config: CreateComponentConfig<string>, renderFn: CreateComponentRenderFn<any, any, any>): React.FC<any>; //#endregion
54
+ declare function createComponent(config: CreateComponentConfig<string>, renderFn: CreateComponentRenderFn<any, any, any>): React.FC<any>;
56
55
  //#endregion
57
56
  export { createComponent };
@@ -1,7 +1,6 @@
1
1
  import { ComponentProps, ComponentType } from "react";
2
2
 
3
3
  //#region ../core/dist/createComponentExample.d.ts
4
- //#region src/createComponentExample.d.ts
5
4
  /**
6
5
  * Extracts variant fixtures from a Component's props type.
7
6
  * If Button has `variant?: 'brand' | 'outline'` and `size?: 'sm' | 'md'`,
@@ -37,6 +36,6 @@ type ExamplesResult<TComponent extends ComponentType<any>> = {
37
36
  * }));
38
37
  * ```
39
38
  */
40
- declare function createComponentExample<TComponent extends ComponentType<any>, T extends Record<string, ExampleFn<TComponent>>>(Component: TComponent, examplesFn: (fixtures: VariantFixtures<TComponent>) => ExamplesResult<TComponent>): ComponentExample<T>; //#endregion
39
+ declare function createComponentExample<TComponent extends ComponentType<any>, T extends Record<string, ExampleFn<TComponent>>>(Component: TComponent, examplesFn: (fixtures: VariantFixtures<TComponent>) => ExamplesResult<TComponent>): ComponentExample<T>;
41
40
  //#endregion
42
41
  export { ComponentExample, createComponentExample };