@yahoo/uds-v5-wip 1.53.0 → 1.54.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.
@@ -1,4 +1,5 @@
1
1
  import { ComponentRef, CompositeRef, RegisteredComponents, StylePropRef } from "./component-refs.js";
2
+ import * as React$1 from "react";
2
3
  import { ReactNode } from "react";
3
4
 
4
5
  //#region ../config/dist/component-config.d.ts
@@ -15,14 +16,28 @@ type HtmlTag = string;
15
16
  /**
16
17
  * Object form for a primitive (HTML-tag) layer that needs locked attrs
17
18
  * or default CSS-property values.
19
+ *
20
+ * Distributive mapped union over `keyof React.JSX.IntrinsicElements` so
21
+ * `attrs` is narrowed to the HTML props valid for the chosen `tag` at
22
+ * the call site — `{ tag: 'a', attrs: { href: '/x' } }` type-checks;
23
+ * `{ tag: 'div', attrs: { href: '/x' } }` does not. `defaultProps`
24
+ * stays loosely typed: it carries style-prop-keyed CSS declarations
25
+ * (incl. `_hover`/`_focus`/etc. modifier keys) that feed the @utility
26
+ * codegen, NOT HTML props.
18
27
  */
19
- interface PrimitiveLayer {
20
- tag: HtmlTag;
21
- /** HTML attributes always applied to this layer (e.g. `role="alert"`). */
22
- attrs?: Record<string, unknown>;
23
- /** Default style-prop values for this layer. */
28
+ type PrimitiveLayer = { [T in keyof React$1.JSX.IntrinsicElements]: {
29
+ tag: T; /** HTML attributes always applied to this layer (e.g. `role="alert"`). */
30
+ attrs?: Partial<React$1.ComponentPropsWithoutRef<T>>;
31
+ /**
32
+ * Default per-layer CSS declarations. Keys are style-prop names (or
33
+ * raw CSS properties when no registered style prop applies); values
34
+ * are token refs (`'{spacing/4}'`), alias names, or literal CSS.
35
+ * Modifier keys (`_hover`, `_focus`, `_dataDisabled`, ...) nest the
36
+ * same shape recursively. Codegen compiles this into a single
37
+ * `@utility componentName-layerName { ... }` block.
38
+ */
24
39
  defaultProps?: Record<string, unknown>;
25
- }
40
+ } }[keyof React$1.JSX.IntrinsicElements];
26
41
  /**
27
42
  * Object form for a layer that's a composed React component (registered
28
43
  * via `.registerComponents({...})`). The `component` field is a brace-ref
@@ -96,18 +111,38 @@ interface CompositeBinding {
96
111
  }
97
112
  /**
98
113
  * Forward a JSX prop value to one of the component's layers as an
99
- * existing surface key. If the target layer is a primitive, `from` is
100
- * an HTML attr / event name; if it's a composed component, `from` is
101
- * one of that component's existing props.
114
+ * existing surface key. The runtime-side / read-side shape `layer`
115
+ * and `from` are bare strings. Type-guards in `bindRender` use the
116
+ * absence of `styleProp` / `composite` keys to discriminate this shape
117
+ * from the registered-binding shapes.
102
118
  *
103
- * `from` is a bare string (no braces) — the absence of `styleProp` /
104
- * `composite` keys is how the framework discriminates this shape from
105
- * the registered-binding shapes.
119
+ * Authoring sites get the narrower `TypedForwardBinding<TLayers>`
120
+ * (below) via `VerbosePropBinding<TLayers>`, which structurally
121
+ * extends this loose form.
106
122
  */
107
- interface ForwardBinding {
108
- layer: string;
109
- from: string;
110
- }
123
+ /**
124
+ * Authoring-site form of `ForwardBinding`, narrowed against the
125
+ * component's own layer map. Distributes over `keyof TLayers` so:
126
+ *
127
+ * - `layer` is constrained to one of the declared layer names.
128
+ * - `from` is constrained by the target layer's shape:
129
+ * • **ComposedLayer** (`{ component: '{Box}' }`) → one of the
130
+ * wrapped component's exposed JSX props (looked up against
131
+ * `RegisteredComponents['Box']`), so `{ layer: 'label', from:
132
+ * 'variant' }` only type-checks if Text registers `variant`.
133
+ * • **PrimitiveLayer / bare HTML tag** → any string (HTML attr or
134
+ * event name; type-precision here would require pulling
135
+ * `JSX.IntrinsicElements[tag]`, deferred).
136
+ *
137
+ * Structurally extends `ForwardBinding` so the runtime's type-guard
138
+ * (`isForwardBinding`) still recognizes typed entries.
139
+ */
140
+ type TypedForwardBinding<TLayers extends Record<string, LayerInput>> = { [K in keyof TLayers & string]: {
141
+ layer: K;
142
+ from: TLayers[K] extends {
143
+ component: `{${infer C}}`;
144
+ } ? C extends keyof RegisteredComponents ? keyof RegisteredComponents[C] & string : string : string;
145
+ } }[keyof TLayers & string];
111
146
  /**
112
147
  * Boolean prop — toggled on/off, no value beyond presence. Useful for
113
148
  * `loading`, `disabled`, `selected`. Each layer's bundle gets a
@@ -143,22 +178,28 @@ type StylePropShorthand = StylePropRef;
143
178
  * `{ layer, styleProp }` binding — no shorthand. The shorthand
144
179
  * `'{bg}'` is allowed only in the primitive form's props (see
145
180
  * `PrimitivePropBinding`).
181
+ *
182
+ * Generic over `TLayers` so `TypedForwardBinding` can narrow the
183
+ * `layer` + `from` fields against the component's own layer map.
184
+ * Consumers that don't know the layer map (read-side helpers,
185
+ * `bindRender`) parameterize with the wide default
186
+ * `Record<string, LayerInput>` and get the loose `ForwardBinding`.
146
187
  */
147
- type VerbosePropBinding = StylePropBinding | SingleLayerCompositeBinding | CompositeBinding | ForwardBinding | BoolMarker | EnumMarker<any>;
188
+ type VerbosePropBinding<TLayers extends Record<string, LayerInput> = Record<string, LayerInput>> = StylePropBinding | SingleLayerCompositeBinding | CompositeBinding | TypedForwardBinding<TLayers> | BoolMarker | EnumMarker<any>;
148
189
  /**
149
190
  * All allowed shapes for a single entry in the primitive form's `props`
150
191
  * block. Primitive form adds the `StylePropShorthand` brace-ref
151
192
  * (`'{bg}'`) on top of every verbose form — the root layer is
152
193
  * unambiguous so the shorthand resolves trivially.
153
194
  */
154
- type PrimitivePropBinding = StylePropShorthand | VerbosePropBinding;
195
+ type PrimitivePropBinding<TLayers extends Record<string, LayerInput> = Record<string, LayerInput>> = StylePropShorthand | VerbosePropBinding<TLayers>;
155
196
  /**
156
197
  * Union of every legal prop-binding shape across both forms. Read-side
157
198
  * helpers (`Props<TConfig>`, runtime resolution) accept this widest
158
199
  * union; authoring-side input types (`ComponentConfigInput`) take the
159
200
  * tighter `VerbosePropBinding`.
160
201
  */
161
- type PropBinding = PrimitivePropBinding;
202
+ type PropBinding<TLayers extends Record<string, LayerInput> = Record<string, LayerInput>> = PrimitivePropBinding<TLayers>;
162
203
  /**
163
204
  * Marker for a boolean JSX prop. Use inside the `props` block:
164
205
  *
@@ -230,6 +271,30 @@ interface ExampleEntry<TAxis extends string = string> {
230
271
  type Examples<TProps extends Record<string, unknown> = Record<string, unknown>> = {
231
272
  default: ExampleEntry<IterableAxisOf<TProps>>;
232
273
  } & Record<string, ExampleEntry<IterableAxisOf<TProps>>>;
274
+ /**
275
+ * A compound-variant entry — applies a per-layer style override when
276
+ * *all* `conditions` match the incoming JSX props. Mirrors the legacy
277
+ * `compoundVariants: [{ conditions, styles }]` shape (see
278
+ * `componentCompoundClass()` for the emitted class name).
279
+ *
280
+ * compoundVariants: [
281
+ * {
282
+ * conditions: { size: 'sm', variant: 'brand' },
283
+ * styles: { root: { boxShadow: '{shadow/sm}' } },
284
+ * },
285
+ * ]
286
+ *
287
+ * `conditions` keys are JSX-prop names that resolve to `enums()` /
288
+ * `bool()` markers in the `props` block; values are the variant values
289
+ * (or `'true'` / `'false'` for bools) that must all match for the entry
290
+ * to apply. Codegen emits one `@utility componentName-layerName--<sorted
291
+ * conditions>` block per (layer); runtime appends that class when
292
+ * conditions match.
293
+ */
294
+ interface CompoundVariant {
295
+ conditions: Record<string, string>;
296
+ styles: Record<string, Record<string, unknown>>;
297
+ }
233
298
  /**
234
299
  * The architecture-doc-target component config. Distinct from today's
235
300
  * `SingleComponentDef` (`base` + `variants` shape) — this is the
@@ -255,14 +320,20 @@ type Examples<TProps extends Record<string, unknown> = Record<string, unknown>>
255
320
  * When the root isn't a literal tag (brace-ref / composed layer), it's
256
321
  * `undefined` and `Props<TConfig>` falls back to `HTMLAttributes<HTMLElement>`.
257
322
  *
258
- * The component's name is supplied at registration time, not here.
323
+ * `__componentName` is a non-enumerable runtime slot assigned by
324
+ * `.registerComponents({ Name: config })` — the key becomes the name.
325
+ * The renderer reads it to emit `componentName-layerName` @utility
326
+ * classes onto each layer's bundle (matching the classes codegen emits
327
+ * from the same `defaultProps`). Absent until registered.
259
328
  */
260
329
  interface ComponentConfigValue<TLayers extends Record<string, LayerInput>, TProps extends Record<string, PropBinding> = Record<string, PropBinding>, TTag extends HtmlTag | undefined = RootTag<TLayers>> {
261
330
  readonly __kind: 'componentConfig';
262
331
  readonly __tag?: TTag;
332
+ readonly __componentName?: string;
263
333
  readonly layers: TLayers;
264
334
  readonly props?: TProps;
265
335
  readonly defaultProps?: Record<string, unknown>;
336
+ readonly compoundVariants?: CompoundVariant[];
266
337
  /**
267
338
  * Component examples — see {@link Examples}. Carried through from
268
339
  * `ComponentConfigInput.examples`.
@@ -275,4 +346,4 @@ interface ComponentConfigValue<TLayers extends Record<string, LayerInput>, TProp
275
346
  * function destructures `props.<layerName>` into the JSX position.
276
347
  */
277
348
  //#endregion
278
- export { BoolMarker, ComponentConfigValue, ComposedLayer, CompositeBinding, EnumMarker, ForwardBinding, HtmlTag, LayerInput, PrimitiveLayer, PrimitivePropBinding, PropBinding, RootTag, SingleLayerCompositeBinding, StylePropBinding, StylePropShorthand, VerbosePropBinding };
349
+ export { BoolMarker, ComponentConfigValue, ComposedLayer, CompositeBinding, CompoundVariant, EnumMarker, HtmlTag, LayerInput, PrimitiveLayer, PrimitivePropBinding, PropBinding, RootTag, SingleLayerCompositeBinding, StylePropBinding, StylePropShorthand, VerbosePropBinding };
@@ -1 +1 @@
1
- import "react";
1
+ import "../../utils/dist/index.js";
@@ -4,10 +4,10 @@ import "../../utils/dist/index.js";
4
4
  import { getConfigurablePropMapping } from "../../core/dist/configurable-prop-helpers.js";
5
5
  import "../../core/dist/index.js";
6
6
  import { buildMotionReference, resolveComponentMotionAliases, validateComponentVariants } from "./component-resolution.js";
7
- import { setRegisteredStyleProps } from "./runtime-registry.js";
8
- import { applyPresetToData, deepMerge, mergeAtomic } from "./preset-merge.js";
9
7
  import { resolveTokenType, sniffTokenTypeFromValue } from "./resolveTokenTypes.js";
10
8
  import { resolveStyleProp } from "./resolveStyleProp.js";
9
+ import { applyPresetToData, deepMerge, mergeAtomic } from "./preset-merge.js";
10
+ import { setRegisteredStyleProps } from "./runtime-registry.js";
11
11
  //#region ../config/dist/createConfig.js
12
12
  /** biome-ignore-all lint/suspicious/noExplicitAny: necessary for dynamic builder to work correctly */
13
13
  /**
@@ -449,8 +449,16 @@ function createConfigBuilder(data, extensions) {
449
449
  },
450
450
  registerComponents(configs) {
451
451
  const normalized = {};
452
- for (const [name, entry] of Object.entries(configs)) if (typeof entry === "function" && "__config" in entry) normalized[name] = entry.__config;
453
- else normalized[name] = entry;
452
+ for (const [name, entry] of Object.entries(configs)) {
453
+ const config = typeof entry === "function" && "__config" in entry ? entry.__config : entry;
454
+ Object.defineProperty(config, "__componentName", {
455
+ enumerable: false,
456
+ configurable: true,
457
+ writable: true,
458
+ value: name
459
+ });
460
+ normalized[name] = config;
461
+ }
454
462
  return next({ componentConfigs: {
455
463
  ...data.componentConfigs ?? {},
456
464
  ...normalized
@@ -1,5 +1,5 @@
1
1
  import { ComponentRef, CompositeRef, RegisteredComponents, RegisteredComposites, RegisteredStyleProps, StylePropRef } from "./component-refs.js";
2
- import { BoolMarker, ComponentConfigValue, ComposedLayer, CompositeBinding, EnumMarker, ForwardBinding, HtmlTag, LayerInput, PrimitiveLayer, PrimitivePropBinding, PropBinding, RootTag, SingleLayerCompositeBinding, StylePropBinding, StylePropShorthand, VerbosePropBinding } from "./component-config.js";
2
+ import { BoolMarker, ComponentConfigValue, ComposedLayer, CompositeBinding, CompoundVariant, EnumMarker, HtmlTag, LayerInput, PrimitiveLayer, PrimitivePropBinding, PropBinding, RootTag, SingleLayerCompositeBinding, StylePropBinding, StylePropShorthand, VerbosePropBinding } from "./component-config.js";
3
3
  import { Props } from "./Props.js";
4
4
  import { BoundComponent } from "./defineComponent.js";
5
5
  import { ColorFn, ColorKeyword, CssAngle, CssColor, CssLength, CssPercentage, CssRatio, CssTime, CssValue, CssValueTypeName, HexColor, HslColor, RgbColor } from "./types/css-values.js";
@@ -1,6 +1,5 @@
1
1
  import "./component-resolution.js";
2
2
  import "./consts/defaultColors.js";
3
- import "./createComponent.js";
4
3
  import "./propertyAcceptedTypes.js";
5
4
  import "./refs.js";
6
5
  import "./resolveTokenTypes.js";
@@ -27,22 +27,30 @@ import "../../utils/dist/index.js";
27
27
  * still resolves to `var(--uds-color-brand)`, regardless of whether the
28
28
  * brand value itself is a literal or a ref.
29
29
  */
30
- const REF_PATTERN = /^\{([^/{}]+)\/([^{}]+)\}$/;
30
+ const REF_PATTERN = /^\{([^{}]+)\}$/;
31
31
  /**
32
32
  * Parse a value as a token ref. Returns `null` when the value isn't a
33
33
  * brace-wrapped ref of the form `{namespace/name}`. The `name` portion
34
34
  * may contain additional slashes — only the first slash is treated as
35
35
  * the namespace separator.
36
+ *
37
+ * Color-modifier values (`darken` / `lighten`) are a structured object
38
+ * form, not a string-encoded suffix. See {@link TokenWithModifier}.
36
39
  */
37
40
  function parseTokenRef(value) {
38
- const match = REF_PATTERN.exec(value);
39
- if (!match) return null;
40
- const namespace = match[1];
41
- const name = match[2];
42
- if (!namespace || !name) return null;
41
+ const outer = REF_PATTERN.exec(value);
42
+ if (!outer) return null;
43
+ const body = outer[1];
44
+ if (!body) return null;
45
+ return parseRefBody(body);
46
+ }
47
+ function parseRefBody(body) {
48
+ if (body.includes("{") || body.includes("}")) return null;
49
+ const slashIdx = body.indexOf("/");
50
+ if (slashIdx <= 0 || slashIdx >= body.length - 1) return null;
43
51
  return {
44
- namespace,
45
- name
52
+ namespace: body.slice(0, slashIdx),
53
+ name: body.slice(slashIdx + 1)
46
54
  };
47
55
  }
48
56
  /**