@yahoo/uds-create-config 1.1.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 (130) hide show
  1. package/dist/AssetGroup.d.ts +77 -0
  2. package/dist/AssetGroup.js +125 -0
  3. package/dist/Component.d.ts +308 -0
  4. package/dist/Component.js +896 -0
  5. package/dist/ComponentGroup.d.ts +20 -0
  6. package/dist/ComponentGroup.js +46 -0
  7. package/dist/CompositeStyle.d.ts +27 -0
  8. package/dist/CompositeStyle.js +52 -0
  9. package/dist/Config.d.ts +423 -0
  10. package/dist/Config.js +1429 -0
  11. package/dist/Mode.d.ts +41 -0
  12. package/dist/Mode.js +81 -0
  13. package/dist/Modifier.d.ts +51 -0
  14. package/dist/Modifier.js +97 -0
  15. package/dist/MotionDef.d.ts +49 -0
  16. package/dist/MotionDef.js +97 -0
  17. package/dist/Props.d.ts +317 -0
  18. package/dist/Props.js +35 -0
  19. package/dist/Provider.d.ts +20 -0
  20. package/dist/Provider.js +14 -0
  21. package/dist/StyleProp.d.ts +112 -0
  22. package/dist/StyleProp.js +197 -0
  23. package/dist/Token.d.ts +55 -0
  24. package/dist/Token.js +112 -0
  25. package/dist/TokenGroup.d.ts +32 -0
  26. package/dist/TokenGroup.js +68 -0
  27. package/dist/asset-kind.d.ts +55 -0
  28. package/dist/asset-kind.js +29 -0
  29. package/dist/brands.d.ts +30 -0
  30. package/dist/brands.js +20 -0
  31. package/dist/captureCallerPath.d.ts +48 -0
  32. package/dist/captureCallerPath.js +95 -0
  33. package/dist/colorExpressions.d.ts +131 -0
  34. package/dist/colorExpressions.js +148 -0
  35. package/dist/defineAssetGroup.d.ts +166 -0
  36. package/dist/defineAssetGroup.js +264 -0
  37. package/dist/defineProvider.d.ts +29 -0
  38. package/dist/defineProvider.js +60 -0
  39. package/dist/element-marker.d.ts +54 -0
  40. package/dist/element-marker.js +113 -0
  41. package/dist/entity-utils.d.ts +56 -0
  42. package/dist/entity-utils.js +105 -0
  43. package/dist/factories.d.ts +707 -0
  44. package/dist/factories.js +393 -0
  45. package/dist/foreign-component-name.d.ts +21 -0
  46. package/dist/foreign-component-name.js +42 -0
  47. package/dist/index.d.ts +32 -0
  48. package/dist/index.js +28 -0
  49. package/dist/interpolate.d.ts +20 -0
  50. package/dist/interpolate.js +10 -0
  51. package/dist/jsx/__fixtures__/cross-component-preview.d.ts +3 -0
  52. package/dist/jsx/__fixtures__/cross-component-preview.js +15 -0
  53. package/dist/jsx/jsx-dev-runtime.d.ts +15 -0
  54. package/dist/jsx/jsx-dev-runtime.js +11 -0
  55. package/dist/jsx/jsx-runtime.d.ts +48 -0
  56. package/dist/jsx/jsx-runtime.js +305 -0
  57. package/dist/markers.d.ts +217 -0
  58. package/dist/markers.js +67 -0
  59. package/dist/refs.d.ts +158 -0
  60. package/dist/refs.js +104 -0
  61. package/dist/renderer/RendererErrorBoundary.d.ts +26 -0
  62. package/dist/renderer/RendererErrorBoundary.js +30 -0
  63. package/dist/renderer/UdsRenderer.d.ts +80 -0
  64. package/dist/renderer/UdsRenderer.js +33 -0
  65. package/dist/renderer/assetRenderable.d.ts +13 -0
  66. package/dist/renderer/assetRenderable.js +13 -0
  67. package/dist/renderer/index.d.ts +14 -0
  68. package/dist/renderer/index.js +14 -0
  69. package/dist/renderer/makeRegistry.d.ts +34 -0
  70. package/dist/renderer/makeRegistry.js +52 -0
  71. package/dist/renderer/makeUdsRenderer.d.ts +29 -0
  72. package/dist/renderer/makeUdsRenderer.js +35 -0
  73. package/dist/renderer/primitives/FragmentRenderer.d.ts +12 -0
  74. package/dist/renderer/primitives/FragmentRenderer.js +11 -0
  75. package/dist/renderer/primitives/SlotRenderer.d.ts +21 -0
  76. package/dist/renderer/primitives/SlotRenderer.js +20 -0
  77. package/dist/renderer/wrapRegistry.d.ts +64 -0
  78. package/dist/renderer/wrapRegistry.js +39 -0
  79. package/dist/renderer/wrappers/component-slots.d.ts +41 -0
  80. package/dist/renderer/wrappers/component-slots.js +66 -0
  81. package/dist/renderer/wrappers/event-bridge.d.ts +20 -0
  82. package/dist/renderer/wrappers/event-bridge.js +78 -0
  83. package/dist/renderer/wrappers/hex-normalize.d.ts +14 -0
  84. package/dist/renderer/wrappers/hex-normalize.js +35 -0
  85. package/dist/renderer/wrappers/html-aliases.d.ts +24 -0
  86. package/dist/renderer/wrappers/html-aliases.js +62 -0
  87. package/dist/renderer/wrappers/inline-styles.d.ts +16 -0
  88. package/dist/renderer/wrappers/inline-styles.js +104 -0
  89. package/dist/renderer/wrappers/slot-resolution.d.ts +25 -0
  90. package/dist/renderer/wrappers/slot-resolution.js +68 -0
  91. package/dist/renderer/wrappers/void-elements.d.ts +23 -0
  92. package/dist/renderer/wrappers/void-elements.js +28 -0
  93. package/dist/spec/apply-forced-modifiers.d.ts +19 -0
  94. package/dist/spec/apply-forced-modifiers.js +49 -0
  95. package/dist/spec/asset-jsx.d.ts +48 -0
  96. package/dist/spec/asset-jsx.js +48 -0
  97. package/dist/spec/collapse-text-labels.d.ts +44 -0
  98. package/dist/spec/collapse-text-labels.js +107 -0
  99. package/dist/spec/empty-node-slots.d.ts +51 -0
  100. package/dist/spec/empty-node-slots.js +141 -0
  101. package/dist/spec/index.d.ts +10 -0
  102. package/dist/spec/index.js +10 -0
  103. package/dist/spec/jsxToSpec.d.ts +48 -0
  104. package/dist/spec/jsxToSpec.js +506 -0
  105. package/dist/spec/layer-props.d.ts +52 -0
  106. package/dist/spec/layer-props.js +149 -0
  107. package/dist/spec/preview-controls.d.ts +44 -0
  108. package/dist/spec/preview-controls.js +139 -0
  109. package/dist/spec/slot-refs.d.ts +39 -0
  110. package/dist/spec/slot-refs.js +56 -0
  111. package/dist/spec/specToJsx.d.ts +35 -0
  112. package/dist/spec/specToJsx.js +127 -0
  113. package/dist/token-override-rows.d.ts +66 -0
  114. package/dist/token-override-rows.js +223 -0
  115. package/dist/tokenValueType.d.ts +34 -0
  116. package/dist/tokenValueType.js +138 -0
  117. package/dist/tsconfig.tsbuildinfo +1 -0
  118. package/dist/types/css-properties.d.ts +232 -0
  119. package/dist/types/css-properties.js +14 -0
  120. package/dist/types/css-property-keywords.d.ts +156 -0
  121. package/dist/types/css-property-keywords.js +616 -0
  122. package/dist/types/css-values.d.ts +63 -0
  123. package/dist/types/css-values.js +16 -0
  124. package/dist/types.d.ts +708 -0
  125. package/dist/types.js +12 -0
  126. package/dist/units.d.ts +14 -0
  127. package/dist/units.js +16 -0
  128. package/dist/utils/index.d.ts +4 -0
  129. package/dist/utils/index.js +4 -0
  130. package/package.json +81 -0
@@ -0,0 +1,95 @@
1
+ //#region src/captureCallerPath.ts
2
+ /**
3
+ * Inspect the current call stack and return the first frame whose file
4
+ * path sits outside the `@yahoo/uds-create-config` package itself — i.e. the
5
+ * user's authoring site.
6
+ *
7
+ * Stashing the path at definition time gives every config object its
8
+ * origin for free. Consumers (codegen, CSS scanner, AI prompt builder)
9
+ * read `__sourcePath` off the config map directly instead of walking
10
+ * the AST to re-derive where each registration was authored.
11
+ *
12
+ * The skip predicate matches `/packages/config/` (workspace
13
+ * layout) and `/@yahoo/uds-create-config/` (consumer node_modules layout) so
14
+ * internal frames never leak through. Returns `undefined` when no
15
+ * eligible frame is found.
16
+ *
17
+ * Stack format coverage:
18
+ * - Bun / V8 in-process: ` at fn (/abs/path.ts:L:C)` or bare
19
+ * ` at /abs/path.ts:L:C` (no parens).
20
+ * - Node native stacks: `file:///abs/path.ts:L:C` URL form.
21
+ * - Source-mapped frames downleveled through tsdown: `.js` files.
22
+ *
23
+ * The regex picks the first `(...).ext:line:col` token; the
24
+ * surrounding `at fn` / paren wrapping is ignored.
25
+ */
26
+ const INTERNAL_FRAME_MARKERS = ["/packages/config/", "/@yahoo/uds-create-config/"];
27
+ const FRAME_PATH_RE = /\(?(?:file:\/\/)?(\/[^):\s]+?\.[cm]?[jt]sx?):\d+(?::\d+)?\)?/;
28
+ const TEST_FILE_RE = /\.test\.[jt]sx?$/;
29
+ function isInternalFrame(path) {
30
+ if (TEST_FILE_RE.test(path)) return false;
31
+ return INTERNAL_FRAME_MARKERS.some((marker) => path.includes(marker));
32
+ }
33
+ /**
34
+ * `@yahoo/uds-create-codegen`'s `loadConfig` bundles `uds.config.ts` with
35
+ * `Bun.build` and runs the bundle from `<cwd>/.uds/config-bundle/`.
36
+ * The bundle's inline sourcemap maps frames back to paths *relative
37
+ * to the bundle output dir* — e.g.
38
+ * `apps/docs/.uds/config-bundle/src/uds/components/button.tsx`,
39
+ * not the original `apps/docs/src/uds/components/button.tsx`.
40
+ * Strip the segment so `Component.sourceFilePath` resolves to a
41
+ * readable on-disk path. Matches `/.uds/config-bundle/` so it's
42
+ * agnostic to which app the bundle was emitted under.
43
+ */
44
+ const CONFIG_BUNDLE_PATH_SEGMENT = "/.uds/config-bundle/";
45
+ function normalizeBundlePath(path) {
46
+ const idx = path.indexOf(CONFIG_BUNDLE_PATH_SEGMENT);
47
+ if (idx === -1) return path;
48
+ return path.slice(0, idx + 1) + path.slice(idx + 20);
49
+ }
50
+ function captureCallerPath() {
51
+ const stack = (/* @__PURE__ */ new Error()).stack;
52
+ if (!stack) return void 0;
53
+ for (const line of stack.split("\n")) {
54
+ const match = line.match(FRAME_PATH_RE);
55
+ if (!match) continue;
56
+ const path = normalizeBundlePath(match[1]);
57
+ if (isInternalFrame(path)) continue;
58
+ return path;
59
+ }
60
+ }
61
+ /**
62
+ * Non-enumerable `__sourcePath` slot key. Centralized so codegen
63
+ * consumers and authoring helpers agree on one spelling.
64
+ */
65
+ const SOURCE_PATH_KEY = "__sourcePath";
66
+ /**
67
+ * Attach `__sourcePath` to a config object non-enumerably.
68
+ * `JSON.stringify` ignores non-enumerable properties so the wire format
69
+ * stays clean.
70
+ *
71
+ * No-op when `path` is `undefined` — keeps the config shape stable
72
+ * when the stack-walk yields no eligible frame.
73
+ */
74
+ function attachSourcePath(target, path) {
75
+ if (!path) return target;
76
+ Object.defineProperty(target, SOURCE_PATH_KEY, {
77
+ enumerable: false,
78
+ configurable: true,
79
+ writable: true,
80
+ value: path
81
+ });
82
+ return target;
83
+ }
84
+ /**
85
+ * Read `__sourcePath` off a config object. Returns `undefined` when
86
+ * the slot was never set (e.g. configs produced outside the `define*`
87
+ * helpers).
88
+ */
89
+ function readSourcePath(target) {
90
+ if (target === null || typeof target !== "object" && typeof target !== "function") return;
91
+ const value = target[SOURCE_PATH_KEY];
92
+ return typeof value === "string" ? value : void 0;
93
+ }
94
+ //#endregion
95
+ export { SOURCE_PATH_KEY, attachSourcePath, captureCallerPath, readSourcePath };
@@ -0,0 +1,131 @@
1
+ import { TokenRef } from "./refs.js";
2
+ import { CssAngle, CssColor, CssLength, CssPercentage } from "./types/css-values.js";
3
+
4
+ //#region src/colorExpressions.d.ts
5
+ /** Position used for gradient stops + radial center — a CSS length or percentage. */
6
+ type LengthOrPercent = CssLength | CssPercentage;
7
+ /** Line direction keyword for `linear-gradient(to <dir>, …)`. */
8
+ type LineDirection = 'top' | 'right' | 'bottom' | 'left' | 'top right' | 'top left' | 'bottom right' | 'bottom left';
9
+ /** Color space accepted by `color-mix()` and gradient `<color-interpolation-method>`. */
10
+ type ColorSpace = 'srgb' | 'srgb-linear' | 'oklab' | 'oklch' | 'lab' | 'lch' | 'hsl' | 'hwb';
11
+ /** Radial gradient extent keyword. */
12
+ type RadialSize = 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner';
13
+ interface MixExpr {
14
+ readonly __kind: 'mix';
15
+ readonly from: ColorValue;
16
+ readonly to: ColorValue;
17
+ readonly amount: CssPercentage;
18
+ readonly colorSpace?: ColorSpace;
19
+ }
20
+ /**
21
+ * `darken(color, N)` / `lighten(color, N)` — one-arg shade shorthands that
22
+ * blend a color toward black (darken) or white (lighten) by `amount`%, using
23
+ * `light-dark(...)` so the blend direction flips per color scheme. A focused
24
+ * pair alongside the general `mix`; resolves through the same pipeline.
25
+ */
26
+ interface ShadeExpr {
27
+ readonly __kind: 'darken' | 'lighten';
28
+ readonly color: ColorValue;
29
+ /** Mix percentage toward black/white — `10` → `10%`. */
30
+ readonly amount: number;
31
+ }
32
+ interface GradientStop {
33
+ readonly color: ColorValue;
34
+ readonly at?: LengthOrPercent;
35
+ }
36
+ interface LinearGradientExpr {
37
+ readonly __kind: 'linear-gradient';
38
+ readonly angle?: CssAngle | `to ${LineDirection}`;
39
+ readonly stops: readonly GradientStop[];
40
+ readonly interpolation?: ColorSpace;
41
+ readonly repeating?: boolean;
42
+ }
43
+ interface RadialGradientExpr {
44
+ readonly __kind: 'radial-gradient';
45
+ readonly shape?: 'circle' | 'ellipse';
46
+ readonly size?: RadialSize;
47
+ readonly position?: LengthOrPercent | 'center' | 'top' | 'right' | 'bottom' | 'left';
48
+ readonly stops: readonly GradientStop[];
49
+ readonly interpolation?: ColorSpace;
50
+ readonly repeating?: boolean;
51
+ }
52
+ /**
53
+ * Any expression / marker that resolves to a CSS color value.
54
+ *
55
+ * `TokenRef` here is intentionally un-narrowed by token type. When
56
+ * the `Registered*` augmentations grow a `__type` slot, this can
57
+ * narrow to color-typed tokens — until then runtime + patch
58
+ * validation catches type mismatches.
59
+ */
60
+ type ColorValue = CssColor | TokenRef | MixExpr;
61
+ /** Anything that resolves to a CSS `background-image`-eligible value. */
62
+ type GradientValue = TokenRef | LinearGradientExpr | RadialGradientExpr;
63
+ /** Union of every structured expression authored via these helpers. */
64
+ type ColorExpression = MixExpr | ShadeExpr | LinearGradientExpr | RadialGradientExpr;
65
+ declare function isMixExpr(value: unknown): value is MixExpr;
66
+ declare function isLinearGradientExpr(value: unknown): value is LinearGradientExpr;
67
+ declare function isRadialGradientExpr(value: unknown): value is RadialGradientExpr;
68
+ declare function isColorExpression(value: unknown): value is ColorExpression;
69
+ /**
70
+ * `color-mix(in <space>, <from> <amount>, <to>)` — blend `from` and
71
+ * `to` at the given percentage. Inputs can be CSS color literals,
72
+ * `token('ns/name')` markers, or other `mix()` outputs.
73
+ *
74
+ * mix(token('bg/primary'), 'transparent', '20%')
75
+ * mix('#000', token('bg/accent'), '40%', 'oklab')
76
+ */
77
+ declare function mix(from: ColorValue, to: ColorValue, amount: CssPercentage, colorSpace?: ColorSpace): MixExpr;
78
+ /**
79
+ * Opacity sugar — `alpha(color, 0.2)` resolves to
80
+ * `color-mix(in srgb, color 20%, transparent)`, which renders as
81
+ * `color` at 20% opacity. The numeric API matches `rgba()` and the
82
+ * CSS `opacity` property (both 0..1).
83
+ *
84
+ * Out-of-range values clamp to `[0, 1]`. The mix amount is the
85
+ * color's share of the blend (`color-mix(in srgb, A X%, B)` defines
86
+ * `X%` as A's proportion), so `opacity * 100` is exactly what goes on
87
+ * the wire.
88
+ */
89
+ declare function alpha(color: ColorValue, opacity: number): MixExpr;
90
+ /**
91
+ * `darken(color, 10)` → `color-mix(in oklch, color, light-dark(black, white) 10%)`
92
+ * — blends `color` toward black in light mode, white in dark mode. Pairs with
93
+ * `lighten`. `color` is usually a `token('bg/brand')` ref but accepts any
94
+ * `ColorValue`.
95
+ */
96
+ declare function darken(color: ColorValue, amount: number): ShadeExpr;
97
+ /** Mirror of `darken()`; blends toward white in light mode, black in dark. */
98
+ declare function lighten(color: ColorValue, amount: number): ShadeExpr;
99
+ /**
100
+ * `linear-gradient(<angle>, <stop1>, <stop2>, …)` — directional
101
+ * gradient. `angle` accepts a CSS angle (`'135deg'`) or a `to <dir>`
102
+ * keyword. Stops carry a `color` and optional `at` position — bare
103
+ * stops let the engine space evenly.
104
+ */
105
+ declare function linearGradient(spec: {
106
+ angle?: CssAngle | `to ${LineDirection}`;
107
+ stops: readonly GradientStop[];
108
+ interpolation?: ColorSpace;
109
+ repeating?: boolean;
110
+ }): LinearGradientExpr;
111
+ /**
112
+ * `radial-gradient(<shape> <size> at <position>, <stop1>, …)` —
113
+ * gradient radiating outward from `position`. Defaults match CSS
114
+ * (ellipse at center).
115
+ */
116
+ declare function radialGradient(spec: {
117
+ shape?: 'circle' | 'ellipse';
118
+ size?: RadialSize;
119
+ position?: LengthOrPercent | 'center' | 'top' | 'right' | 'bottom' | 'left';
120
+ stops: readonly GradientStop[];
121
+ interpolation?: ColorSpace;
122
+ repeating?: boolean;
123
+ }): RadialGradientExpr;
124
+ type TokenRefToCss = (ref: string) => string;
125
+ /**
126
+ * Resolve any structured color expression to its CSS string. The
127
+ * single entry point codegen calls after `isColorExpression` fires.
128
+ */
129
+ declare function resolveColorExpression(expr: ColorExpression, tokenRefToCss: TokenRefToCss): string;
130
+ //#endregion
131
+ export { ColorExpression, ColorSpace, ColorValue, GradientStop, GradientValue, LengthOrPercent, LineDirection, LinearGradientExpr, MixExpr, RadialGradientExpr, RadialSize, TokenRefToCss, alpha, darken, isColorExpression, isLinearGradientExpr, isMixExpr, isRadialGradientExpr, lighten, linearGradient, mix, radialGradient, resolveColorExpression };
@@ -0,0 +1,148 @@
1
+ import { isTokenRef } from "./refs.js";
2
+ //#region src/colorExpressions.ts
3
+ function hasKind(value, kind) {
4
+ return typeof value === "object" && value !== null && value.__kind === kind;
5
+ }
6
+ function isMixExpr(value) {
7
+ return hasKind(value, "mix");
8
+ }
9
+ function isShadeExpr(value) {
10
+ return hasKind(value, "darken") || hasKind(value, "lighten");
11
+ }
12
+ function isLinearGradientExpr(value) {
13
+ return hasKind(value, "linear-gradient");
14
+ }
15
+ function isRadialGradientExpr(value) {
16
+ return hasKind(value, "radial-gradient");
17
+ }
18
+ function isColorExpression(value) {
19
+ return isMixExpr(value) || isShadeExpr(value) || isLinearGradientExpr(value) || isRadialGradientExpr(value);
20
+ }
21
+ /**
22
+ * `color-mix(in <space>, <from> <amount>, <to>)` — blend `from` and
23
+ * `to` at the given percentage. Inputs can be CSS color literals,
24
+ * `token('ns/name')` markers, or other `mix()` outputs.
25
+ *
26
+ * mix(token('bg/primary'), 'transparent', '20%')
27
+ * mix('#000', token('bg/accent'), '40%', 'oklab')
28
+ */
29
+ function mix(from, to, amount, colorSpace) {
30
+ return {
31
+ __kind: "mix",
32
+ from,
33
+ to,
34
+ amount,
35
+ colorSpace
36
+ };
37
+ }
38
+ /**
39
+ * Opacity sugar — `alpha(color, 0.2)` resolves to
40
+ * `color-mix(in srgb, color 20%, transparent)`, which renders as
41
+ * `color` at 20% opacity. The numeric API matches `rgba()` and the
42
+ * CSS `opacity` property (both 0..1).
43
+ *
44
+ * Out-of-range values clamp to `[0, 1]`. The mix amount is the
45
+ * color's share of the blend (`color-mix(in srgb, A X%, B)` defines
46
+ * `X%` as A's proportion), so `opacity * 100` is exactly what goes on
47
+ * the wire.
48
+ */
49
+ function alpha(color, opacity) {
50
+ return {
51
+ __kind: "mix",
52
+ from: color,
53
+ to: "transparent",
54
+ amount: `${Math.round(Math.max(0, Math.min(1, opacity)) * 100)}%`,
55
+ colorSpace: "srgb"
56
+ };
57
+ }
58
+ /**
59
+ * `darken(color, 10)` → `color-mix(in oklch, color, light-dark(black, white) 10%)`
60
+ * — blends `color` toward black in light mode, white in dark mode. Pairs with
61
+ * `lighten`. `color` is usually a `token('bg/brand')` ref but accepts any
62
+ * `ColorValue`.
63
+ */
64
+ function darken(color, amount) {
65
+ return {
66
+ __kind: "darken",
67
+ color,
68
+ amount
69
+ };
70
+ }
71
+ /** Mirror of `darken()`; blends toward white in light mode, black in dark. */
72
+ function lighten(color, amount) {
73
+ return {
74
+ __kind: "lighten",
75
+ color,
76
+ amount
77
+ };
78
+ }
79
+ /**
80
+ * `linear-gradient(<angle>, <stop1>, <stop2>, …)` — directional
81
+ * gradient. `angle` accepts a CSS angle (`'135deg'`) or a `to <dir>`
82
+ * keyword. Stops carry a `color` and optional `at` position — bare
83
+ * stops let the engine space evenly.
84
+ */
85
+ function linearGradient(spec) {
86
+ return {
87
+ __kind: "linear-gradient",
88
+ ...spec
89
+ };
90
+ }
91
+ /**
92
+ * `radial-gradient(<shape> <size> at <position>, <stop1>, …)` —
93
+ * gradient radiating outward from `position`. Defaults match CSS
94
+ * (ellipse at center).
95
+ */
96
+ function radialGradient(spec) {
97
+ return {
98
+ __kind: "radial-gradient",
99
+ ...spec
100
+ };
101
+ }
102
+ function resolveColorValue(value, tokenRefToCss) {
103
+ if (typeof value === "string") return value;
104
+ if (isMixExpr(value)) return resolveMixExpr(value, tokenRefToCss);
105
+ if (isTokenRef(value)) return tokenRefToCss(value.ref);
106
+ return "";
107
+ }
108
+ function resolveMixExpr(expr, tokenRefToCss) {
109
+ const space = expr.colorSpace ?? "srgb";
110
+ const from = resolveColorValue(expr.from, tokenRefToCss);
111
+ const to = resolveColorValue(expr.to, tokenRefToCss);
112
+ return `color-mix(in ${space}, ${from} ${expr.amount}, ${to})`;
113
+ }
114
+ function resolveShadeExpr(expr, tokenRefToCss) {
115
+ return `color-mix(in oklch, ${resolveColorValue(expr.color, tokenRefToCss)}, ${expr.__kind === "darken" ? "light-dark(black, white)" : "light-dark(white, black)"} ${expr.amount}%)`;
116
+ }
117
+ function renderStops(stops, tokenRefToCss) {
118
+ const parts = [];
119
+ for (const stop of stops) {
120
+ const color = resolveColorValue(stop.color, tokenRefToCss);
121
+ parts.push(stop.at !== void 0 ? `${color} ${stop.at}` : color);
122
+ }
123
+ return parts.join(", ");
124
+ }
125
+ function resolveLinearGradientExpr(expr, tokenRefToCss) {
126
+ const fn = expr.repeating ? "repeating-linear-gradient" : "linear-gradient";
127
+ const prefix = expr.angle !== void 0 ? `${expr.angle}, ` : "";
128
+ return `${fn}(${expr.interpolation ? `in ${expr.interpolation}, ` : ""}${prefix}${renderStops(expr.stops, tokenRefToCss)})`;
129
+ }
130
+ function resolveRadialGradientExpr(expr, tokenRefToCss) {
131
+ const fn = expr.repeating ? "repeating-radial-gradient" : "radial-gradient";
132
+ const shapeAndSize = [expr.shape ?? "", expr.size ?? ""].filter(Boolean).join(" ");
133
+ const positionPart = expr.position ? ` at ${expr.position}` : "";
134
+ const head = shapeAndSize || positionPart ? `${shapeAndSize}${positionPart}, ` : "";
135
+ return `${fn}(${expr.interpolation ? `in ${expr.interpolation}, ` : ""}${head}${renderStops(expr.stops, tokenRefToCss)})`;
136
+ }
137
+ /**
138
+ * Resolve any structured color expression to its CSS string. The
139
+ * single entry point codegen calls after `isColorExpression` fires.
140
+ */
141
+ function resolveColorExpression(expr, tokenRefToCss) {
142
+ if (isMixExpr(expr)) return resolveMixExpr(expr, tokenRefToCss);
143
+ if (isShadeExpr(expr)) return resolveShadeExpr(expr, tokenRefToCss);
144
+ if (isLinearGradientExpr(expr)) return resolveLinearGradientExpr(expr, tokenRefToCss);
145
+ return resolveRadialGradientExpr(expr, tokenRefToCss);
146
+ }
147
+ //#endregion
148
+ export { alpha, darken, isColorExpression, isLinearGradientExpr, isMixExpr, isRadialGradientExpr, lighten, linearGradient, mix, radialGradient, resolveColorExpression };
@@ -0,0 +1,166 @@
1
+ import { ComponentRef } from "./refs.js";
2
+ import { FontAssetMember } from "./types.js";
3
+
4
+ //#region src/defineAssetGroup.d.ts
5
+ /**
6
+ * Static metadata an icon-class member may carry (the UDS v3 generated
7
+ * icons stamp this shape). All fields optional — metadata-less
8
+ * libraries (Phosphor) fall back to the documented harvest convention
9
+ * (PascalCase export key + component-shaped value).
10
+ */
11
+ interface IconAssetMetadata {
12
+ readonly name?: string;
13
+ readonly isSvgIcon?: boolean;
14
+ readonly variants?: readonly string[];
15
+ readonly category?: string;
16
+ readonly tags?: readonly string[];
17
+ }
18
+ /**
19
+ * One icon-class member — a React component (plain function or a
20
+ * forwardRef/memo exotic) optionally carrying static `.metadata`.
21
+ * Typed structurally so `@yahoo/uds-create-config` doesn't depend on React types
22
+ * here; the renderer casts at the registry boundary.
23
+ */
24
+ type IconAssetMember = ((props: never) => unknown) & {
25
+ readonly metadata?: IconAssetMetadata;
26
+ };
27
+ /**
28
+ * Icon branch — `type` is optional so icon authors never declare the
29
+ * class. `sizes` is required unless `props` is used (which normalizes
30
+ * into the flat fields). It's load-bearing render data (the `<svg>`
31
+ * shell reads px from it) and the picker's size-option list is derived
32
+ * from its keys.
33
+ */
34
+ interface IconAssetGroupConfig<P = Record<string, unknown>> {
35
+ type?: 'icon';
36
+ /** Named size → px (`{ sm: 16, md: 24 }`). Picker options = keys. */
37
+ sizes?: Readonly<Record<string, number>>;
38
+ /**
39
+ * Group-level variant superset the picker starts from. Omitted ⇒
40
+ * harvested union of members' `.metadata.variants` (first-seen
41
+ * order), which by construction can't drift behind the library.
42
+ * Required (in practice) for metadata-less libraries.
43
+ */
44
+ variants?: readonly string[];
45
+ /** Display label. Defaults to the title-cased registration key. */
46
+ label?: string;
47
+ /**
48
+ * Source-library version shown in the Assets UI (e.g. `2.1.1`). Authored,
49
+ * not derived — a set's published version rarely matches the npm package
50
+ * that ships its glyphs. Omitted ⇒ no version is shown.
51
+ */
52
+ version?: string;
53
+ description?: string;
54
+ /**
55
+ * Filter harvested members by their export key — return `false` to skip one.
56
+ * A large third-party package often ships more than its canonical glyph set
57
+ * (Phosphor exports both `HouseIcon` and a deprecated bare `House` alias, plus
58
+ * non-glyph `IconBase`/`IconContext`). Passing the package wildcard is required
59
+ * for codegen to bundle live members, so this predicate is how you narrow that
60
+ * wildcard to the real icons (e.g. `(n) => n.endsWith('Icon')`). Applied before
61
+ * the PascalCase / component-shape checks; runs over every export key.
62
+ */
63
+ include?: (name: string) => boolean;
64
+ /**
65
+ * Authoring sugar mirroring the member component's own prop axes. Each entry
66
+ * is a picker value-set, NOT a style map: keys are the member's
67
+ * prop names, values are the allowed choices. Exactly ONE entry must be a
68
+ * named→px MAP (the size axis); at most one entry may be an ARRAY (the variant
69
+ * axis). Normalized at config-eval into the flat `sizes`/`variants` fields.
70
+ * Cannot be combined with those flat fields. Type the members via
71
+ * `defineAssetGroup<IconProps>(...)` to constrain keys to the component's
72
+ * props (e.g. `variant` → its enum).
73
+ */
74
+ props?: { [K in keyof P]?: Readonly<Record<string, number>> | readonly NonNullable<P[K]>[] };
75
+ /**
76
+ * The component that authors this group's members in exported code —
77
+ * e.g. `'Icon'` so a placed asset node `yahoo-os:asset:icons/Trophy`
78
+ * round-trips through code views as `<Icon name="Trophy" … />`. There
79
+ * is no implicit link between a group and a component (a group's members
80
+ * and a component's `name` enum are decoupled even when built from the
81
+ * same package), so the authoring component is declared explicitly.
82
+ * It is also the component a placed member *renders through* on the canvas:
83
+ * the resolved `Icon` owns the set-specific size/variant→glyph mapping. Omit
84
+ * it for a component-less system: members render bare and exporters fall back
85
+ * to the bare member tag. Accepts a typed `ComponentRef` (from
86
+ * `component()`) or a bare string.
87
+ */
88
+ component?: string | ComponentRef;
89
+ }
90
+ /**
91
+ * Font branch — `type: 'font'` declares the class. The `never` fields
92
+ * make icon-class props a compile error inside a `{ type: 'font' }`
93
+ * literal regardless of property order (the union is ordering-free,
94
+ * unlike the chained-methods spelling it replaced).
95
+ */
96
+ interface FontAssetGroupConfig {
97
+ type: 'font';
98
+ label?: string;
99
+ /** Source-library version shown in the Assets UI (e.g. `2.1.1`). */
100
+ version?: string;
101
+ description?: string;
102
+ /** Icon-class prop — excluded on the font branch at the type level. */
103
+ sizes?: never;
104
+ /** Icon-class prop — excluded on the font branch at the type level. */
105
+ variants?: never;
106
+ /** Icon-class prop — excluded on the font branch at the type level. */
107
+ props?: never;
108
+ /** Icon-class prop — excluded on the font branch at the type level. */
109
+ component?: never;
110
+ }
111
+ type AssetGroupConfig = IconAssetGroupConfig<Record<string, unknown>> | FontAssetGroupConfig;
112
+ interface AssetGroupDefinitionBase {
113
+ /** Invariant ref tag — identical for every asset class. */
114
+ readonly __kind: 'assetGroup';
115
+ /**
116
+ * The group's slug — late-bound from the `registerAssetGroups`
117
+ * record key. Reading before registration throws.
118
+ */
119
+ readonly ref: string;
120
+ readonly label?: string;
121
+ readonly version?: string;
122
+ readonly description?: string;
123
+ }
124
+ interface IconAssetGroupDefinition extends AssetGroupDefinitionBase {
125
+ readonly assetKind: 'icon';
126
+ /** Harvested members, keyed by asset name (the `${assetName}` id segment). */
127
+ readonly members: Readonly<Record<string, IconAssetMember>>;
128
+ /** Per-member harvested `.metadata` (name/variants/category/tags). */
129
+ readonly memberMetadata: Readonly<Record<string, IconAssetMetadata>>;
130
+ readonly sizes: Readonly<Record<string, number>>;
131
+ /** Resolved variant superset — declared, or the harvested union. */
132
+ readonly variants: readonly string[];
133
+ /** Authoring component for code export (`'Icon'`), if declared. */
134
+ readonly component?: string;
135
+ }
136
+ interface FontAssetGroupDefinition extends AssetGroupDefinitionBase {
137
+ readonly assetKind: 'font';
138
+ /** Members keyed by `FontID` (kebab-case) — pure-JSON data records. */
139
+ readonly members: Readonly<Record<string, FontAssetMember>>;
140
+ }
141
+ type AssetGroupDefinition = IconAssetGroupDefinition | FontAssetGroupDefinition;
142
+ /**
143
+ * `defineAssetGroup(members)` return value — the only thing you can do
144
+ * with it is `.config({...})`, which completes the definition. The
145
+ * overloads branch the return type on the config union's discriminant.
146
+ * The phantom `P` generic flows from `defineAssetGroup<P>(...)` and
147
+ * constrains the `props` block keys/values to the member component's
148
+ * own props.
149
+ */
150
+ interface AssetGroupBuilder<P = Record<string, unknown>> {
151
+ config(config: IconAssetGroupConfig<P>): IconAssetGroupDefinition;
152
+ config(config: FontAssetGroupConfig): FontAssetGroupDefinition;
153
+ }
154
+ /**
155
+ * Attach icon metadata to a single one-off icon and hand it back
156
+ * unchanged. `isSvgIcon: true` is implied —
157
+ * the point of the call is to mark the component as an icon so the
158
+ * group harvest picks it up. Slots still point at the *group*, never
159
+ * at this.
160
+ */
161
+ declare function defineAssetIcon<T>(component: T, metadata: Omit<IconAssetMetadata, 'isSvgIcon'>): T & {
162
+ readonly metadata: IconAssetMetadata;
163
+ };
164
+ declare function defineAssetGroup<P = Record<string, unknown>>(members: Readonly<Record<string, unknown>>): AssetGroupBuilder<P>;
165
+ //#endregion
166
+ export { AssetGroupBuilder, AssetGroupConfig, AssetGroupDefinition, FontAssetGroupConfig, FontAssetGroupDefinition, IconAssetGroupConfig, IconAssetGroupDefinition, IconAssetMember, IconAssetMetadata, defineAssetGroup, defineAssetIcon };