@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,305 @@
1
+ import { foreignComponentName } from "../foreign-component-name.js";
2
+ //#region src/jsx/jsx-runtime.ts
3
+ const Fragment = Symbol.for("react.fragment");
4
+ let configContext = null;
5
+ function setConfigContext(config) {
6
+ configContext = config;
7
+ }
8
+ function getConfigContext() {
9
+ return configContext;
10
+ }
11
+ let counter = 0;
12
+ function nextKey() {
13
+ return `el${counter++}`;
14
+ }
15
+ const pendingRefs = /* @__PURE__ */ new Map();
16
+ let refCounter = 0;
17
+ function nextRefId() {
18
+ return `__udsRef_${refCounter++}`;
19
+ }
20
+ let renderScope = null;
21
+ let wrapperCounter = 0;
22
+ const TRANSPARENT_WRAPPERS = new Set([
23
+ "AnimatePresence",
24
+ "MotionConfig",
25
+ "LazyMotion"
26
+ ]);
27
+ /**
28
+ * Scope subsequent wrapper-type resolution to `componentName` (or clear it
29
+ * with `null`). Resets the per-component wrapper index so stamped names are
30
+ * stable across runs regardless of global element-key state.
31
+ */
32
+ function setRenderExtractionContext(componentName) {
33
+ renderScope = componentName;
34
+ wrapperCounter = 0;
35
+ }
36
+ /**
37
+ * Reset all module-level state — element key counter, pending-ref
38
+ * registry, ref counter, and render-extraction scope. Called by tests
39
+ * asserting specific keys and by the extractor before each top-level
40
+ * evaluation.
41
+ */
42
+ function __resetKeyCounterForTesting() {
43
+ counter = 0;
44
+ pendingRefs.clear();
45
+ refCounter = 0;
46
+ renderScope = null;
47
+ wrapperCounter = 0;
48
+ }
49
+ /**
50
+ * Drain and return the pending-ref registry. Called by the extractor
51
+ * after `import()`-ing a bundle to rewrite `__udsRef_N` placeholders to
52
+ * the component names that `registerComponents` has now stamped onto
53
+ * each builder.
54
+ */
55
+ function __drainPendingRefs() {
56
+ const drained = new Map(pendingRefs);
57
+ pendingRefs.clear();
58
+ refCounter = 0;
59
+ return drained;
60
+ }
61
+ /**
62
+ * JSX automatic-runtime entry for a single static child. Compilers pick
63
+ * this signature when the JSX expression has zero or one child.
64
+ */
65
+ function jsx(type, props) {
66
+ return buildSpec(type, props);
67
+ }
68
+ /**
69
+ * JSX automatic-runtime entry for static children — same semantics as
70
+ * `jsx`, the distinction is purely a compiler hint that `props.children`
71
+ * is an array literal.
72
+ */
73
+ function jsxs(type, props) {
74
+ return buildSpec(type, props);
75
+ }
76
+ function collectChildren(childList, parentTypeName) {
77
+ const mergedElements = {};
78
+ const childKeys = [];
79
+ let textBuffer = "";
80
+ let hasText = false;
81
+ let hasElementChildren = false;
82
+ for (const child of childList) {
83
+ if (child === null || child === void 0 || typeof child === "boolean") continue;
84
+ if (typeof child === "string") {
85
+ textBuffer += child;
86
+ hasText = true;
87
+ } else if (typeof child === "number") {
88
+ textBuffer += String(child);
89
+ hasText = true;
90
+ } else if (isSpec(child)) {
91
+ const inlineText = parentTypeName === "Text" ? plainTextContent(child) : null;
92
+ if (inlineText !== null) {
93
+ textBuffer += inlineText;
94
+ hasText = true;
95
+ } else {
96
+ for (const [k, el] of Object.entries(child.elements)) mergedElements[k] = el;
97
+ childKeys.push(child.root);
98
+ hasElementChildren = true;
99
+ }
100
+ }
101
+ }
102
+ return {
103
+ mergedElements,
104
+ childKeys,
105
+ textBuffer,
106
+ hasText,
107
+ hasElementChildren
108
+ };
109
+ }
110
+ /**
111
+ * True when `type` is a third-party composition wrapper to elide from a
112
+ * captured render spec. A UDS component (carries `__componentName`), a
113
+ * `Fragment`, and an intrinsic tag (passed as a string) are real anatomy and
114
+ * never elided. Among the rest, a node with a `render` target (the
115
+ * ariakit/Radix `asChild` pattern) or with meaningful children is plumbing
116
+ * that wraps real content; a node with neither is a genuine visual leaf (an
117
+ * icon) and stays. Caller gates this on render-extraction scope.
118
+ */
119
+ function isElidableWrapper(type, restProps, childList) {
120
+ if (type === Fragment) return false;
121
+ if (typeof type !== "object" && typeof type !== "function") return false;
122
+ if (typeof type.__componentName === "string") return false;
123
+ const hasRenderTarget = isSpec(restProps.render);
124
+ const hasMeaningfulChildren = childList.some((c) => c !== null && c !== void 0 && typeof c !== "boolean");
125
+ return hasRenderTarget || hasMeaningfulChildren;
126
+ }
127
+ /**
128
+ * Collapse an elided wrapper into its real content. With a `render` target
129
+ * (ariakit/Radix `asChild`), the wrapper renders *as* that UDS element, so we
130
+ * surface the target as the node and fold the wrapper's own children into it —
131
+ * faithful to how those libraries compose. Without one (a pure context
132
+ * provider like ariakit's `MenuProvider`), it collapses to a `Fragment` so its
133
+ * children render through. Either way no foreign type reaches the spec.
134
+ */
135
+ function elideWrapper(renderValue, childList) {
136
+ const { mergedElements, childKeys, textBuffer, hasText, hasElementChildren } = collectChildren(childList, "");
137
+ if (isSpec(renderValue)) {
138
+ const elements = {
139
+ ...renderValue.elements,
140
+ ...mergedElements
141
+ };
142
+ const target = elements[renderValue.root];
143
+ const foldedChildren = [...target.children ?? [], ...childKeys];
144
+ const updated = { ...target };
145
+ if (foldedChildren.length > 0) updated.children = foldedChildren;
146
+ if (hasText && !hasElementChildren) updated.props = {
147
+ ...target.props,
148
+ children: textBuffer
149
+ };
150
+ elements[renderValue.root] = updated;
151
+ return {
152
+ root: renderValue.root,
153
+ elements
154
+ };
155
+ }
156
+ const element = {
157
+ type: "Fragment",
158
+ props: {}
159
+ };
160
+ if (hasElementChildren) element.children = childKeys;
161
+ if (hasText && !hasElementChildren) element.props = { children: textBuffer };
162
+ const key = nextKey();
163
+ mergedElements[key] = element;
164
+ return {
165
+ root: key,
166
+ elements: mergedElements
167
+ };
168
+ }
169
+ /**
170
+ * Inline a dynamically-resolved leaf component into a captured render spec.
171
+ * Icon's `.render()` picks a glyph by name (`const Glyph = UdsIcons[name]`) and
172
+ * mounts `<Glyph .../>`; the glyph is a plain function component, so it would
173
+ * otherwise be stamped a synthetic `<scope>:<base>:<n>` type nothing resolves —
174
+ * it isn't registered, and a dynamic namespace lookup can't be traced to a
175
+ * `foreign:` import. Invoking it here (it returns a `Spec` through this same
176
+ * runtime, since the captured module is compiled against it) splices its real
177
+ * output — the `<path>` subtree — into the spec, so the Internals view paints
178
+ * the actual glyph instead of a blank node.
179
+ *
180
+ * Render-extraction only (gated by the caller on `renderScope`), and
181
+ * best-effort: a function that throws when invoked outside React (hooks,
182
+ * context) or returns a non-`Spec` (a context provider returning `null`, a
183
+ * glyph with no matching variant) yields `null`, and the caller falls back to
184
+ * the synthetic type — no worse than today.
185
+ */
186
+ function tryInlineDynamicLeaf(type, props) {
187
+ if (typeof type !== "function") return null;
188
+ const named = type;
189
+ if (typeof named.__componentName === "string") return null;
190
+ let base = "";
191
+ if (typeof named.displayName === "string" && named.displayName.length > 0) base = named.displayName;
192
+ else if (typeof named.name === "string" && named.name.length > 0) base = named.name;
193
+ if (TRANSPARENT_WRAPPERS.has(base)) return null;
194
+ try {
195
+ const result = type(props);
196
+ return isSpec(result) ? result : null;
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+ function buildSpec(type, props) {
202
+ const { children, ...restProps } = props;
203
+ const childList = normalizeChildren(children);
204
+ if (renderScope !== null && isElidableWrapper(type, restProps, childList)) return elideWrapper(restProps.render, childList);
205
+ if (renderScope !== null) {
206
+ const inlined = tryInlineDynamicLeaf(type, props);
207
+ if (inlined) return inlined;
208
+ }
209
+ const typeName = resolveTypeName(type);
210
+ const collected = collectChildren(childList, typeName);
211
+ const { mergedElements } = collected;
212
+ const { childKeys, textBuffer, hasText } = collected;
213
+ let { hasElementChildren } = collected;
214
+ const elementProps = { ...restProps };
215
+ if (hasText && !hasElementChildren) elementProps.children = textBuffer;
216
+ for (const [propName, value] of Object.entries(elementProps)) {
217
+ if (isSpec(value)) {
218
+ for (const [k, el] of Object.entries(value.elements)) mergedElements[k] = el;
219
+ childKeys.push(value.root);
220
+ hasElementChildren = true;
221
+ elementProps[propName] = { $slot: value.root };
222
+ continue;
223
+ }
224
+ if (Array.isArray(value) && value.length > 0 && value.every(isSpec)) {
225
+ const refs = [];
226
+ for (const spec of value) {
227
+ for (const [k, el] of Object.entries(spec.elements)) mergedElements[k] = el;
228
+ childKeys.push(spec.root);
229
+ refs.push(spec.root);
230
+ }
231
+ hasElementChildren = true;
232
+ elementProps[propName] = { $slot: refs };
233
+ }
234
+ }
235
+ if (childKeys.length === 1 && mergedElements[childKeys[0]]?.type === "Slot") elementProps.children = { $slot: childKeys[0] };
236
+ const element = {
237
+ type: typeName,
238
+ props: elementProps
239
+ };
240
+ if (hasElementChildren) element.children = childKeys;
241
+ const key = nextKey();
242
+ mergedElements[key] = element;
243
+ return {
244
+ root: key,
245
+ elements: mergedElements
246
+ };
247
+ }
248
+ function normalizeChildren(children) {
249
+ if (children === void 0 || children === null) return [];
250
+ if (Array.isArray(children)) return children.flat(Number.POSITIVE_INFINITY);
251
+ return [children];
252
+ }
253
+ function resolveTypeName(type) {
254
+ if (type === Fragment) return "Fragment";
255
+ if (typeof type === "string") return type;
256
+ const isObjectOrFn = type !== null && (typeof type === "object" || typeof type === "function");
257
+ if (isObjectOrFn) {
258
+ const named = type;
259
+ if (typeof named.__componentName === "string") return named.__componentName;
260
+ }
261
+ const foreign = foreignComponentName(type);
262
+ if (foreign !== null) return `foreign:${foreign}`;
263
+ if (typeof type === "function") {
264
+ const fn = type;
265
+ let base = null;
266
+ if (typeof fn.displayName === "string" && fn.displayName.length > 0) base = fn.displayName;
267
+ else if (typeof fn.name === "string" && fn.name.length > 0) base = fn.name;
268
+ if (base !== null) {
269
+ if (TRANSPARENT_WRAPPERS.has(base)) return "Fragment";
270
+ if (renderScope === null) return base;
271
+ return `${renderScope}:${base}:${wrapperCounter++}`;
272
+ }
273
+ }
274
+ if (isObjectOrFn) {
275
+ const id = nextRefId();
276
+ pendingRefs.set(id, type);
277
+ return id;
278
+ }
279
+ return "Unknown";
280
+ }
281
+ function isSpec(value) {
282
+ if (typeof value !== "object" || value === null) return false;
283
+ const candidate = value;
284
+ return typeof candidate.root === "string" && typeof candidate.elements === "object" && candidate.elements !== null;
285
+ }
286
+ /**
287
+ * If `spec` is a self-contained `Text` node carrying only string content,
288
+ * return that string; otherwise `null`. This is the shape the extractor
289
+ * synthesises for a string/number slot default. A real authored text layer
290
+ * carries `data-uds-layer` (and is never collapsed); the synthetic slot node
291
+ * never does, so absence of that marker — plus a single element whose only
292
+ * prop is the string `children` — identifies it precisely.
293
+ */
294
+ function plainTextContent(spec) {
295
+ if (Object.keys(spec.elements).length !== 1) return null;
296
+ const el = spec.elements[spec.root];
297
+ if (!el || el.type !== "Text") return null;
298
+ if (el.children && el.children.length > 0) return null;
299
+ const props = el.props ?? {};
300
+ if (typeof props.children !== "string") return null;
301
+ if (Object.keys(props).some((k) => k !== "children")) return null;
302
+ return props.children;
303
+ }
304
+ //#endregion
305
+ export { Fragment, __drainPendingRefs, __resetKeyCounterForTesting, getConfigContext, jsx, jsxs, setConfigContext, setRenderExtractionContext };
@@ -0,0 +1,217 @@
1
+ import { AssetGroupRef } from "./refs.js";
2
+ import { ComponentDefinition } from "./types.js";
3
+
4
+ //#region src/markers.d.ts
5
+ /**
6
+ * A slot's `.accepts(...)` argument: a registered component definition, or a
7
+ * placeable asset group returned by `defineAssetGroup(...).config(...)` (it
8
+ * carries the `AssetGroupRef` tag). The two are kept distinct downstream —
9
+ * component names land on `SlotInfo.accepts`, the asset-group slug on
10
+ * `SlotInfo.acceptsAssetGroup` — so the designer panel can pick the right
11
+ * picker. Non-placeable groups (fonts) are admitted by the type but rejected
12
+ * at config load.
13
+ */
14
+ type SlotAccepts = ComponentDefinition | AssetGroupRef;
15
+ /**
16
+ * Brand applied to a marker by `.required()`. Lives alongside the
17
+ * marker interfaces so the slot factories (whose `.required()`
18
+ * implementation is co-located with `.accepts()` rather than going
19
+ * through `attachRequired`) can return the brand-narrowed type via
20
+ * the interface signature.
21
+ *
22
+ * `RenderPropsFromConfig` reads this brand to decide whether a render-
23
+ * fn destructure entry is optional (`T | undefined`) or non-optional
24
+ * (`T`). Distinct from `__required?: boolean` on the marker bodies —
25
+ * that field is the runtime flag codegen reads; the brand is the
26
+ * compile-time signal the render-arg type-flow keys on.
27
+ */
28
+ type RequiredBrand = {
29
+ __required: true;
30
+ };
31
+ /**
32
+ * Author-declared slot value kind. A slot holds renderable content; the only
33
+ * explicit kind is text:
34
+ *
35
+ * - `'string'` — plain text content (e.g. Button's `children` label).
36
+ *
37
+ * An open `slot()` is a node container (`ReactNode`) by default — it accepts
38
+ * dropped layers and is narrowed to specific components via `.accepts(...)`;
39
+ * `'string'` instead marks a text surface, so tools like the Studio canvas
40
+ * inline-edit it rather than treat it as a reparent target. Scalars like
41
+ * boolean and number are *not* slots — use the dedicated `bool()` / `number()`
42
+ * markers. (A `'string'` slot still *resolves* to `SlotValueKind: 'ReactNode'`,
43
+ * since a string is a valid `ReactNode`; `authoredType` records the intent.)
44
+ *
45
+ * - `'component'` — the slot resolves to a `FunctionComponent`, not rendered
46
+ * content. Used by the aliased `Icon` pattern (`name: slot({ type:
47
+ * 'component' }).accepts(icons)`), where the render fn receives the icon
48
+ * component itself (`({ name: SvgIcon }) => <SvgIcon … />`) and the saved
49
+ * value is the inline asset-name string (`"Trophy"`), not a `$slot` ref.
50
+ * A `'component'` slot *requires* an asset-group `.accepts(...)` — config
51
+ * load throws otherwise.
52
+ */
53
+ type SlotValueType = 'string' | 'component';
54
+ /**
55
+ * Open-slot marker — `slot()` with no arguments. Codegen treats it as
56
+ * `ReactNode` accepted at the component's own children. Carries no
57
+ * cross-reference; `__accepts` / `__required` may still be set via the
58
+ * chain methods to constrain the slot's children or mark it required.
59
+ * `__valueType` records an explicit `slot({ type })` override (absent ⇒
60
+ * the default `ReactNode`).
61
+ */
62
+ interface SlotMarker {
63
+ readonly __kind: 'slot';
64
+ readonly __required?: boolean;
65
+ readonly __accepts?: readonly SlotAccepts[];
66
+ readonly __valueType?: SlotValueType;
67
+ /**
68
+ * Stamp `__required: true` on the marker. Codegen reads this per-prop
69
+ * and emits the JSX prop without a trailing `?`, so the slot becomes
70
+ * mandatory at call sites. The return type also intersects
71
+ * `RequiredBrand` so `RenderPropsFromConfig` narrows the render-fn
72
+ * destructure entry to non-optional.
73
+ */
74
+ required(): SlotMarker & RequiredBrand;
75
+ /**
76
+ * Constrain the slot's accepted children to one or more registered
77
+ * components, or to a placeable asset group (`slot().accepts(icons)`).
78
+ */
79
+ accepts(component: SlotAccepts | readonly SlotAccepts[]): SlotMarker;
80
+ }
81
+ /**
82
+ * A `slot({ type: 'component' })` marker — the aliased `Icon` pattern. Carries
83
+ * the literal `__valueType: 'component'` so `ResolveMarker` resolves the prop
84
+ * to a `ComponentType` (the render fn receives the icon component itself), and
85
+ * narrows `.accepts(...)` to asset groups only (a component-typed slot must
86
+ * accept an asset group). The chained `.accepts(...)` preserves this type so
87
+ * the literal survives to the render-fn inference.
88
+ */
89
+ interface ComponentSlotMarker extends SlotMarker {
90
+ readonly __valueType: 'component';
91
+ accepts(group: AssetGroupRef | readonly AssetGroupRef[]): ComponentSlotMarker;
92
+ }
93
+ /**
94
+ * Layer-targeting slot ref — `slot('layer')`, `slot('layer/prop')`, or
95
+ * `slot('layer', { prop })`. Routes a JSX prop into the named layer's
96
+ * `layerProp` (defaults to `'children'` when only a layer is given).
97
+ * The `layer` field is the cross-reference — that's what makes this a
98
+ * Ref rather than a Marker.
99
+ */
100
+ interface SlotRef<TLayer extends string = string, TAs extends string = string> {
101
+ readonly __kind: 'slot';
102
+ readonly layer: TLayer;
103
+ readonly layerProp: TAs;
104
+ readonly __required?: boolean;
105
+ readonly __accepts?: readonly SlotAccepts[];
106
+ /** Output adapter set via `.transform(fn)` — codegen wraps the
107
+ * layer's prop so the consumer-facing handler receives `fn(arg)`
108
+ * instead of the raw layer value (e.g. an input event → its
109
+ * string value). Must be self-contained (no closure over outer
110
+ * scope) since codegen lifts it into the generated module. */
111
+ readonly __transform?: (arg: never) => unknown;
112
+ readonly __valueType?: SlotValueType;
113
+ required(): SlotRef<TLayer, TAs> & RequiredBrand;
114
+ accepts(component: SlotAccepts | readonly SlotAccepts[]): SlotRef<TLayer, TAs>;
115
+ transform<Out>(fn: (arg: unknown) => Out): SlotRef<TLayer, TAs> & {
116
+ readonly __transformOut: Out;
117
+ };
118
+ }
119
+ /**
120
+ * Runtime guard for any slot binding (open marker or layered ref).
121
+ * Callers that need to distinguish the two forms narrow further by
122
+ * checking for the `layer` field — `'layer' in value`.
123
+ */
124
+ declare function isSlotMarker(value: unknown): value is SlotMarker | SlotRef;
125
+ interface BooleanMarker {
126
+ readonly __kind: 'boolean';
127
+ readonly __required?: boolean;
128
+ readonly values?: {
129
+ true?: Record<string, Record<string, unknown>>;
130
+ false?: Record<string, Record<string, unknown>>;
131
+ };
132
+ }
133
+ declare function isBoolMarker(value: unknown): value is BooleanMarker;
134
+ interface VariantMarkerObject<V extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>> {
135
+ readonly __kind: 'variant';
136
+ readonly __required?: boolean;
137
+ readonly values: V;
138
+ readonly default?: keyof V & string;
139
+ }
140
+ interface VariantMarkerArray<V extends readonly (string | number)[] = readonly (string | number)[]> {
141
+ readonly __kind: 'variant';
142
+ readonly __required?: boolean;
143
+ readonly values: V;
144
+ readonly default?: V[number];
145
+ }
146
+ type VariantMarker<V = unknown> = V extends readonly (string | number)[] ? VariantMarkerArray<V> : V extends Record<string, Record<string, unknown>> ? VariantMarkerObject<V> : VariantMarkerObject | VariantMarkerArray;
147
+ declare function isVariantMarker(value: unknown): value is VariantMarker;
148
+ /**
149
+ * Distinguish the two variant forms. `Array.isArray(marker.values)` is the
150
+ * single source of truth — every downstream consumer that branches on
151
+ * the form goes through this helper rather than duplicating the check.
152
+ */
153
+ declare function isVariantArrayMarker(value: VariantMarker): value is VariantMarkerArray;
154
+ interface StringMarker {
155
+ readonly __kind: 'string';
156
+ readonly __required?: boolean;
157
+ }
158
+ interface NumberMarker {
159
+ readonly __kind: 'number';
160
+ readonly __required?: boolean;
161
+ }
162
+ declare function isStringMarker(value: unknown): value is StringMarker;
163
+ declare function isNumberMarker(value: unknown): value is NumberMarker;
164
+ interface LayerMarker {
165
+ readonly __kind: 'layer';
166
+ readonly layer: string;
167
+ readonly styles: Record<string, unknown>;
168
+ }
169
+ declare function isLayerMarker(value: unknown): value is LayerMarker;
170
+ /**
171
+ * One conditional override for a `props` axis: apply `props` to the cell
172
+ * when every key in `when` matches the cell's other-axis values. A rule
173
+ * with no `when` always applies (the base). Later matching rules win.
174
+ */
175
+ interface PreviewPropsRule {
176
+ readonly when?: Readonly<Record<string, unknown>>;
177
+ readonly props: Readonly<Record<string, unknown>>;
178
+ }
179
+ /**
180
+ * Synthetic discriminator state a `props` axis compiles to, per axis side.
181
+ * The entry's label is the value. Codegen keys the merged spec's `$cond`
182
+ * on this, and the studio seeds it per cell — both derive it here so they
183
+ * never drift. (`columns`/`rows` entries are concatenated as sibling
184
+ * values of one dimension, so one key per side suffices.)
185
+ */
186
+ declare const PREVIEW_SEED_KEY: {
187
+ readonly row: "__previewSeedRow";
188
+ readonly column: "__previewSeedCol";
189
+ };
190
+ /** True when every key in `when` equals the cell coordinate's value. */
191
+ declare function matchesPreviewWhen(when: Readonly<Record<string, unknown>> | undefined, coord: Readonly<Record<string, unknown>>): boolean;
192
+ /**
193
+ * Merge the `props` of every rule whose `when` matches `coord` (in order,
194
+ * so later matching rules win). Shared by codegen's combo enumeration and
195
+ * the studio's cell assembly so a `props` axis resolves identically.
196
+ */
197
+ declare function resolvePreviewRules(rules: readonly PreviewPropsRule[], coord: Readonly<Record<string, unknown>>): Record<string, unknown>;
198
+ interface PreviewAxisMarker {
199
+ readonly __kind: 'previewAxis';
200
+ /** Axis name — either a prop name or a `_${string}` modifier. */
201
+ readonly prop?: string;
202
+ readonly modifier?: string;
203
+ /**
204
+ * `props` axis rules — per-cell prop-override bags, optionally guarded
205
+ * by `when` against the other axes' values. Lets a preview vary
206
+ * render-extra data per cell (e.g. sample `value`) without declaring a
207
+ * config prop. Resolved against the cell coordinate by the studio and
208
+ * by codegen's combo enumeration.
209
+ */
210
+ readonly rules?: readonly PreviewPropsRule[];
211
+ readonly kind: 'prop' | 'modifier' | 'props';
212
+ readonly nested?: PreviewAxisMarker;
213
+ nest(child: PreviewAxisMarker): PreviewAxisMarker;
214
+ }
215
+ declare function isPreviewAxisMarker(value: unknown): value is PreviewAxisMarker;
216
+ //#endregion
217
+ export { BooleanMarker, ComponentSlotMarker, LayerMarker, NumberMarker, PREVIEW_SEED_KEY, PreviewAxisMarker, PreviewPropsRule, RequiredBrand, SlotMarker, SlotRef, SlotValueType, StringMarker, VariantMarker, VariantMarkerArray, VariantMarkerObject, isBoolMarker, isLayerMarker, isNumberMarker, isPreviewAxisMarker, isSlotMarker, isStringMarker, isVariantArrayMarker, isVariantMarker, matchesPreviewWhen, resolvePreviewRules };
@@ -0,0 +1,67 @@
1
+ //#region src/markers.ts
2
+ /**
3
+ * Runtime guard for any slot binding (open marker or layered ref).
4
+ * Callers that need to distinguish the two forms narrow further by
5
+ * checking for the `layer` field — `'layer' in value`.
6
+ */
7
+ function isSlotMarker(value) {
8
+ return typeof value === "object" && value !== null && value.__kind === "slot";
9
+ }
10
+ function isBoolMarker(value) {
11
+ return typeof value === "object" && value !== null && value.__kind === "boolean";
12
+ }
13
+ function isVariantMarker(value) {
14
+ if (typeof value !== "object" || value === null) return false;
15
+ const v = value;
16
+ if (v.__kind !== "variant") return false;
17
+ return Array.isArray(v.values) || typeof v.values === "object";
18
+ }
19
+ /**
20
+ * Distinguish the two variant forms. `Array.isArray(marker.values)` is the
21
+ * single source of truth — every downstream consumer that branches on
22
+ * the form goes through this helper rather than duplicating the check.
23
+ */
24
+ function isVariantArrayMarker(value) {
25
+ return Array.isArray(value.values);
26
+ }
27
+ function isStringMarker(value) {
28
+ return typeof value === "object" && value !== null && value.__kind === "string";
29
+ }
30
+ function isNumberMarker(value) {
31
+ return typeof value === "object" && value !== null && value.__kind === "number";
32
+ }
33
+ function isLayerMarker(value) {
34
+ return typeof value === "object" && value !== null && value.__kind === "layer";
35
+ }
36
+ /**
37
+ * Synthetic discriminator state a `props` axis compiles to, per axis side.
38
+ * The entry's label is the value. Codegen keys the merged spec's `$cond`
39
+ * on this, and the studio seeds it per cell — both derive it here so they
40
+ * never drift. (`columns`/`rows` entries are concatenated as sibling
41
+ * values of one dimension, so one key per side suffices.)
42
+ */
43
+ const PREVIEW_SEED_KEY = {
44
+ row: "__previewSeedRow",
45
+ column: "__previewSeedCol"
46
+ };
47
+ /** True when every key in `when` equals the cell coordinate's value. */
48
+ function matchesPreviewWhen(when, coord) {
49
+ if (!when) return true;
50
+ for (const key of Object.keys(when)) if (coord[key] !== when[key]) return false;
51
+ return true;
52
+ }
53
+ /**
54
+ * Merge the `props` of every rule whose `when` matches `coord` (in order,
55
+ * so later matching rules win). Shared by codegen's combo enumeration and
56
+ * the studio's cell assembly so a `props` axis resolves identically.
57
+ */
58
+ function resolvePreviewRules(rules, coord) {
59
+ const out = {};
60
+ for (const rule of rules) if (matchesPreviewWhen(rule.when, coord)) Object.assign(out, rule.props);
61
+ return out;
62
+ }
63
+ function isPreviewAxisMarker(value) {
64
+ return typeof value === "object" && value !== null && value.__kind === "previewAxis";
65
+ }
66
+ //#endregion
67
+ export { PREVIEW_SEED_KEY, isBoolMarker, isLayerMarker, isNumberMarker, isPreviewAxisMarker, isSlotMarker, isStringMarker, isVariantArrayMarker, isVariantMarker, matchesPreviewWhen, resolvePreviewRules };