@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,11 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+ //#region src/renderer/primitives/FragmentRenderer.tsx
3
+ /**
4
+ * Renders `Fragment`-typed Spec elements transparently — children
5
+ * pass through untouched. The runtime emits `type: 'Fragment'` for
6
+ * both the JSX `<>...</>` shorthand and the explicit `<Fragment>`
7
+ * sentinel; this renderer handles both cases.
8
+ */
9
+ const FragmentRenderer = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children });
10
+ //#endregion
11
+ export { FragmentRenderer };
@@ -0,0 +1,21 @@
1
+ import { ComponentRenderer } from "@json-render/react";
2
+
3
+ //#region src/renderer/primitives/SlotRenderer.d.ts
4
+ /**
5
+ * Renders `Slot`-typed Spec elements as a passthrough for the
6
+ * parent-provided children. The spec extractor emits `Slot`
7
+ * placeholders inside captured `render` Specs to mark where the
8
+ * production render fn passes its `children` argument through. At
9
+ * actual render time, the canvas renderer hands parent-supplied
10
+ * children straight through — same semantics as `FragmentRenderer`,
11
+ * just under a distinct type name so consumers can recognise and
12
+ * highlight the slot boundary in anatomy views.
13
+ *
14
+ * Plain `Slot` (not `$Slot`) matches json-render's convention:
15
+ * `$prefix` names are reserved for prop-value expressions
16
+ * (`$state`, `$bindState`, `$slot`, `$template`, etc.). Element
17
+ * types are plain names, like `Fragment`.
18
+ */
19
+ declare const SlotRenderer: ComponentRenderer;
20
+ //#endregion
21
+ export { SlotRenderer };
@@ -0,0 +1,20 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+ //#region src/renderer/primitives/SlotRenderer.tsx
3
+ /**
4
+ * Renders `Slot`-typed Spec elements as a passthrough for the
5
+ * parent-provided children. The spec extractor emits `Slot`
6
+ * placeholders inside captured `render` Specs to mark where the
7
+ * production render fn passes its `children` argument through. At
8
+ * actual render time, the canvas renderer hands parent-supplied
9
+ * children straight through — same semantics as `FragmentRenderer`,
10
+ * just under a distinct type name so consumers can recognise and
11
+ * highlight the slot boundary in anatomy views.
12
+ *
13
+ * Plain `Slot` (not `$Slot`) matches json-render's convention:
14
+ * `$prefix` names are reserved for prop-value expressions
15
+ * (`$state`, `$bindState`, `$slot`, `$template`, etc.). Element
16
+ * types are plain names, like `Fragment`.
17
+ */
18
+ const SlotRenderer = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children });
19
+ //#endregion
20
+ export { SlotRenderer };
@@ -0,0 +1,64 @@
1
+ import React from "react";
2
+ import { ComponentRegistry } from "@json-render/react";
3
+
4
+ //#region src/renderer/wrapRegistry.d.ts
5
+ /**
6
+ * Config-derived facts the wrapper stack needs but can't read from a bare
7
+ * `ComponentRegistry` (which carries only render fns). Codegen derives this
8
+ * from the `Config` and emits it alongside the registry, so the shared
9
+ * wrappers stay config-agnostic — no hardcoded `'Box'`/`'Image'`/`'bg'`
10
+ * component or style-prop names. Every field is optional; an omitted/empty
11
+ * descriptor makes the dependent wrapper a no-op (e.g. a host registry that
12
+ * supplies its own components without a descriptor).
13
+ */
14
+ interface RegistryDescriptor {
15
+ /**
16
+ * Component names whose root renders a void HTML element (`img`, `input`,
17
+ * …). `wrapVoidElements` strips `children` from these — React throws if a
18
+ * void element gets children. Bare names; namespace prefixes are stripped
19
+ * at match time.
20
+ */
21
+ voidComponents?: readonly string[];
22
+ /**
23
+ * camelCase CSS property → style-prop name, inverted from each
24
+ * `StyleProp.cssProperty`. Lets `wrapInlineStyleProps` hoist a raw
25
+ * `style: {...}` (Figma / AI import) onto typed style props.
26
+ */
27
+ cssPropertyToStyleProp?: Readonly<Record<string, string>>;
28
+ /**
29
+ * Container primitives (root renders `div`): a fixed `height` from an
30
+ * imported `style` becomes `minHeight` so content can still grow.
31
+ */
32
+ layoutComponents?: readonly string[];
33
+ /**
34
+ * Text primitives (root renders a text tag): a fixed `width`/`height` from
35
+ * an imported `style` is dropped — text shouldn't carry a bounding box.
36
+ */
37
+ textComponents?: readonly string[];
38
+ /**
39
+ * Component-typed slots (the aliased `Icon` pattern): componentName →
40
+ * propName → accepted asset-group slug. A `slot({ type: 'component' })
41
+ * .accepts(<icon group>)` saves the picked asset as an inline name string
42
+ * and its render fn expects the icon component itself, so
43
+ * `wrapComponentTypedSlots` resolves the name to the member component (paired
44
+ * with the runtime `assetMembersBySlug` lookup). Absent for components
45
+ * without such slots.
46
+ */
47
+ componentSlots?: Readonly<Record<string, Readonly<Record<string, string>>>>;
48
+ }
49
+ /**
50
+ * Apply the standard wrapper stack + built-in spec primitives to an
51
+ * existing `ComponentRegistry`. Used by `makeRegistry` after it's
52
+ * built per-component renderers from the project's components, AND
53
+ * by `UdsRenderer` when a host provides a custom registry that needs
54
+ * the same wrappers applied on top.
55
+ *
56
+ * `descriptor` carries the config-derived facts the config-dependent
57
+ * wrappers (`void-elements`, `inline-styles`) need; omit it and those
58
+ * wrappers pass through. Composition order mirrors the legacy inline
59
+ * `wrapRegistry` — each wrapper assumes its outer wrappers haven't yet
60
+ * seen the element.
61
+ */
62
+ declare function wrapRegistry(reg: ComponentRegistry, descriptor?: RegistryDescriptor, assetMembersBySlug?: ReadonlyMap<string, ReadonlyMap<string, React.ComponentType>>): ComponentRegistry;
63
+ //#endregion
64
+ export { RegistryDescriptor, wrapRegistry };
@@ -0,0 +1,39 @@
1
+ import { FragmentRenderer } from "./primitives/FragmentRenderer.js";
2
+ import { SlotRenderer } from "./primitives/SlotRenderer.js";
3
+ import { wrapComponentTypedSlots } from "./wrappers/component-slots.js";
4
+ import { wrapEventBridge } from "./wrappers/event-bridge.js";
5
+ import { wrapNormalizeHex } from "./wrappers/hex-normalize.js";
6
+ import { aliasHtmlTypes } from "./wrappers/html-aliases.js";
7
+ import { wrapInlineStyleProps } from "./wrappers/inline-styles.js";
8
+ import { wrapSlotResolution } from "./wrappers/slot-resolution.js";
9
+ import { wrapVoidElements } from "./wrappers/void-elements.js";
10
+ //#region src/renderer/wrapRegistry.ts
11
+ /**
12
+ * Apply the standard wrapper stack + built-in spec primitives to an
13
+ * existing `ComponentRegistry`. Used by `makeRegistry` after it's
14
+ * built per-component renderers from the project's components, AND
15
+ * by `UdsRenderer` when a host provides a custom registry that needs
16
+ * the same wrappers applied on top.
17
+ *
18
+ * `descriptor` carries the config-derived facts the config-dependent
19
+ * wrappers (`void-elements`, `inline-styles`) need; omit it and those
20
+ * wrappers pass through. Composition order mirrors the legacy inline
21
+ * `wrapRegistry` — each wrapper assumes its outer wrappers haven't yet
22
+ * seen the element.
23
+ */
24
+ function wrapRegistry(reg, descriptor, assetMembersBySlug) {
25
+ return aliasHtmlTypes(wrapInlineStyleProps(wrapNormalizeHex(wrapEventBridge(wrapVoidElements(wrapComponentTypedSlots(wrapSlotResolution({
26
+ ...reg,
27
+ Fragment: reg.Fragment ?? FragmentRenderer,
28
+ Slot: reg.Slot ?? SlotRenderer
29
+ }), {
30
+ componentSlots: descriptor?.componentSlots,
31
+ assetMembersBySlug
32
+ }), { voidComponents: descriptor?.voidComponents }))), {
33
+ cssPropertyToStyleProp: descriptor?.cssPropertyToStyleProp,
34
+ layoutComponents: descriptor?.layoutComponents,
35
+ textComponents: descriptor?.textComponents
36
+ }));
37
+ }
38
+ //#endregion
39
+ export { wrapRegistry };
@@ -0,0 +1,41 @@
1
+ import type { ComponentRegistry } from '@json-render/react';
2
+ import type React from 'react';
3
+ /**
4
+ * Config-derived facts for the aliased `Icon` pattern. A component-typed slot
5
+ * (`slot({ type: 'component' }).accepts(<icon group>)`) saves the picked asset
6
+ * as an inline name string (`"Trophy"`) — not a `$slot` ref — and its render fn
7
+ * expects the icon *component* itself (`({ name: SvgIcon }) => <SvgIcon … />`).
8
+ *
9
+ * - `componentSlots`: componentName → propName → accepted asset-group slug,
10
+ * emitted by codegen's `deriveRegistryDescriptor` from each slot's
11
+ * `authoredType: 'component'` + `acceptsAssetGroup`.
12
+ * - `assetMembersBySlug`: slug → assetName → member component, built at runtime
13
+ * by `makeRegistry` from the same live asset groups it keys under their
14
+ * namespaced asset type. The stored component is the renderable form
15
+ * (the member rendered through the group's declared system component, e.g.
16
+ * `<Icon name=… />`, or the bare member when none is declared), so the
17
+ * author's `<SvgIcon variant size />` draws.
18
+ */
19
+ export interface ComponentTypedSlotsConfig {
20
+ componentSlots?: Readonly<Record<string, Readonly<Record<string, string>>>>;
21
+ assetMembersBySlug?: ReadonlyMap<string, ReadonlyMap<string, React.ComponentType>>;
22
+ }
23
+ /**
24
+ * Resolve component-typed slot props from their saved inline asset name to the
25
+ * member component, so the consuming component's render fn receives a callable
26
+ * component (not a rendered `$slot` child routed through `ElementRenderer`).
27
+ *
28
+ * A component-typed prop's only valid value is the inline asset-name string, so
29
+ * this wrapper guarantees the render fn receives a member component or
30
+ * `undefined` — never a rendered element:
31
+ * - a string resolves to its member component (an unresolvable name — not in
32
+ * the group — is left as the string so the render fn can guard);
33
+ * - any non-string, non-undefined value (e.g. a leftover `{ $slot }` ref from a
34
+ * spec authored before component-typed slots were distinguished) is stripped
35
+ * to `undefined`, so it can't reach `wrapSlotResolution` and render as an
36
+ * `ElementRenderer` child the render fn would choke on.
37
+ *
38
+ * It runs OUTSIDE `wrapSlotResolution`, so it sees the raw prop value before any
39
+ * `$slot` resolution. Both lookups absent ⇒ no-op.
40
+ */
41
+ export declare function wrapComponentTypedSlots(reg: ComponentRegistry, { componentSlots, assetMembersBySlug }?: ComponentTypedSlotsConfig): ComponentRegistry;
@@ -0,0 +1,66 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region src/renderer/wrappers/component-slots.tsx
3
+ /** Local component name of a registry key: `yahoo-os:IconSlotFixture` →
4
+ * `IconSlotFixture`. Registry keys are `<namespace>:<Name>`; component names
5
+ * never contain `:`, so split on the first one. Mirrors `wrapVoidElements`. */
6
+ function localName(key) {
7
+ const colon = key.indexOf(":");
8
+ return colon === -1 ? key : key.slice(colon + 1);
9
+ }
10
+ /**
11
+ * Resolve component-typed slot props from their saved inline asset name to the
12
+ * member component, so the consuming component's render fn receives a callable
13
+ * component (not a rendered `$slot` child routed through `ElementRenderer`).
14
+ *
15
+ * A component-typed prop's only valid value is the inline asset-name string, so
16
+ * this wrapper guarantees the render fn receives a member component or
17
+ * `undefined` — never a rendered element:
18
+ * - a string resolves to its member component (an unresolvable name — not in
19
+ * the group — is left as the string so the render fn can guard);
20
+ * - any non-string, non-undefined value (e.g. a leftover `{ $slot }` ref from a
21
+ * spec authored before component-typed slots were distinguished) is stripped
22
+ * to `undefined`, so it can't reach `wrapSlotResolution` and render as an
23
+ * `ElementRenderer` child the render fn would choke on.
24
+ *
25
+ * It runs OUTSIDE `wrapSlotResolution`, so it sees the raw prop value before any
26
+ * `$slot` resolution. Both lookups absent ⇒ no-op.
27
+ */
28
+ function wrapComponentTypedSlots(reg, { componentSlots, assetMembersBySlug } = {}) {
29
+ if (!componentSlots || !assetMembersBySlug) return reg;
30
+ const wrapped = { ...reg };
31
+ for (const key of Object.keys(reg)) {
32
+ const slotProps = componentSlots[localName(key)];
33
+ if (!slotProps) continue;
34
+ const Orig = wrapped[key];
35
+ if (!Orig) continue;
36
+ wrapped[key] = function ComponentTypedSlotWrapper(renderProps) {
37
+ const props = renderProps.element.props;
38
+ if (!props) return /* @__PURE__ */ jsx(Orig, { ...renderProps });
39
+ let resolved;
40
+ for (const [propName, slug] of Object.entries(slotProps)) {
41
+ const value = props[propName];
42
+ if (value === void 0) continue;
43
+ if (typeof value === "string") {
44
+ const member = assetMembersBySlug.get(slug)?.get(value);
45
+ if (!member) continue;
46
+ resolved ??= { ...props };
47
+ resolved[propName] = member;
48
+ } else {
49
+ resolved ??= { ...props };
50
+ resolved[propName] = void 0;
51
+ }
52
+ }
53
+ if (!resolved) return /* @__PURE__ */ jsx(Orig, { ...renderProps });
54
+ return /* @__PURE__ */ jsx(Orig, {
55
+ ...renderProps,
56
+ element: {
57
+ ...renderProps.element,
58
+ props: resolved
59
+ }
60
+ });
61
+ };
62
+ }
63
+ return wrapped;
64
+ }
65
+ //#endregion
66
+ export { wrapComponentTypedSlots };
@@ -0,0 +1,20 @@
1
+ import { ComponentRegistry } from "@json-render/react";
2
+
3
+ //#region src/renderer/wrappers/event-bridge.d.ts
4
+ /**
5
+ * Bridge json-render's `on.*` event bindings to React callback props.
6
+ *
7
+ * Wraps every component renderer so it can inspect the spec
8
+ * element's `on` field (e.g. `on.press: { action: 'setState', params:
9
+ * { statePath: '/x', value: 1 } }`) and inject the corresponding
10
+ * React callback (`onClick`) that performs the setState OR emits a
11
+ * named event for the host app's handler map to pick up.
12
+ *
13
+ * Runs at the `ComponentRenderer` layer — earlier than
14
+ * `defineRegistry`'s prop extraction — so it can read `element.on`
15
+ * and patch `element.props` with synthesized callback props before
16
+ * the per-component wrapper sees them.
17
+ */
18
+ declare function wrapEventBridge(reg: ComponentRegistry): ComponentRegistry;
19
+ //#endregion
20
+ export { wrapEventBridge };
@@ -0,0 +1,78 @@
1
+ import { useStateStore } from "@json-render/react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/renderer/wrappers/event-bridge.tsx
4
+ /**
5
+ * Map json-render `on.*` event bindings to React callback prop names.
6
+ * Spec authors and AI both lean on `on.press`, `on.change`, etc.; the
7
+ * UDS components surface those as `onClick`, `onChange`, etc. on the
8
+ * React side, so the renderer translates between the two surfaces.
9
+ */
10
+ const EVENT_TO_CALLBACKS = {
11
+ press: ["onClick"],
12
+ change: ["onChange"],
13
+ click: ["onClick"],
14
+ toggle: ["onToggle"],
15
+ submit: ["onSubmit"],
16
+ input: ["onInput"],
17
+ focus: ["onFocus"],
18
+ blur: ["onBlur"],
19
+ openChange: ["onOpenChange"],
20
+ valueChange: ["onValueChange"],
21
+ valueCommit: ["onValueCommit"],
22
+ dismiss: ["onDismiss"]
23
+ };
24
+ /**
25
+ * Bridge json-render's `on.*` event bindings to React callback props.
26
+ *
27
+ * Wraps every component renderer so it can inspect the spec
28
+ * element's `on` field (e.g. `on.press: { action: 'setState', params:
29
+ * { statePath: '/x', value: 1 } }`) and inject the corresponding
30
+ * React callback (`onClick`) that performs the setState OR emits a
31
+ * named event for the host app's handler map to pick up.
32
+ *
33
+ * Runs at the `ComponentRenderer` layer — earlier than
34
+ * `defineRegistry`'s prop extraction — so it can read `element.on`
35
+ * and patch `element.props` with synthesized callback props before
36
+ * the per-component wrapper sees them.
37
+ */
38
+ function wrapEventBridge(reg) {
39
+ const wrapped = { ...reg };
40
+ for (const [name, Comp] of Object.entries(reg)) wrapped[name] = function EventBridgeWrapper(renderProps) {
41
+ const stateStore = useStateStore();
42
+ const { element, emit } = renderProps;
43
+ const on = element.on;
44
+ if (!on) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
45
+ const callbackProps = {};
46
+ for (const [eventName, binding] of Object.entries(on)) {
47
+ const callbackNames = EVENT_TO_CALLBACKS[eventName];
48
+ if (!callbackNames) continue;
49
+ const bindings = Array.isArray(binding) ? binding : [binding];
50
+ const handler = (...args) => {
51
+ const callbackValue = args[0];
52
+ for (const b of bindings) {
53
+ const action = b;
54
+ if (action.action === "setState" && action.params?.statePath) {
55
+ const val = "value" in (action.params ?? {}) ? action.params.value : callbackValue;
56
+ stateStore.set(action.params.statePath, val);
57
+ } else emit(eventName);
58
+ }
59
+ };
60
+ for (const cbName of callbackNames) callbackProps[cbName] = handler;
61
+ }
62
+ if (Object.keys(callbackProps).length === 0) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
63
+ const patchedElement = {
64
+ ...element,
65
+ props: {
66
+ ...element.props,
67
+ ...callbackProps
68
+ }
69
+ };
70
+ return /* @__PURE__ */ jsx(Comp, {
71
+ ...renderProps,
72
+ element: patchedElement
73
+ });
74
+ };
75
+ return wrapped;
76
+ }
77
+ //#endregion
78
+ export { wrapEventBridge };
@@ -0,0 +1,14 @@
1
+ import { ComponentRegistry } from "@json-render/react";
2
+
3
+ //#region src/renderer/wrappers/hex-normalize.d.ts
4
+ /**
5
+ * Normalize raw hex prop values (e.g. from `$state` resolution at
6
+ * runtime) to UDS arbitrary-value syntax (`[#ef4444]`). `$state`
7
+ * resolves a hex string verbatim, but UDS's style-prop processor
8
+ * expects brackets around arbitrary literals — without normalisation
9
+ * the value falls through to the default token-lookup path and the
10
+ * styling silently fails.
11
+ */
12
+ declare function wrapNormalizeHex(reg: ComponentRegistry): ComponentRegistry;
13
+ //#endregion
14
+ export { wrapNormalizeHex };
@@ -0,0 +1,35 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region src/renderer/wrappers/hex-normalize.tsx
3
+ const RAW_HEX_RE = /^#[0-9a-fA-F]{3,8}$/;
4
+ /**
5
+ * Normalize raw hex prop values (e.g. from `$state` resolution at
6
+ * runtime) to UDS arbitrary-value syntax (`[#ef4444]`). `$state`
7
+ * resolves a hex string verbatim, but UDS's style-prop processor
8
+ * expects brackets around arbitrary literals — without normalisation
9
+ * the value falls through to the default token-lookup path and the
10
+ * styling silently fails.
11
+ */
12
+ function wrapNormalizeHex(reg) {
13
+ const wrapped = { ...reg };
14
+ for (const [name, Comp] of Object.entries(reg)) wrapped[name] = function HexNormalizeWrapper(renderProps) {
15
+ const props = renderProps.element.props;
16
+ if (!props) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
17
+ let patched = false;
18
+ const newProps = { ...props };
19
+ for (const [propName, value] of Object.entries(newProps)) if (typeof value === "string" && RAW_HEX_RE.test(value)) {
20
+ newProps[propName] = `[${value}]`;
21
+ patched = true;
22
+ }
23
+ if (!patched) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
24
+ return /* @__PURE__ */ jsx(Comp, {
25
+ ...renderProps,
26
+ element: {
27
+ ...renderProps.element,
28
+ props: newProps
29
+ }
30
+ });
31
+ };
32
+ return wrapped;
33
+ }
34
+ //#endregion
35
+ export { wrapNormalizeHex };
@@ -0,0 +1,24 @@
1
+ import { ComponentRegistry } from "@json-render/react";
2
+
3
+ //#region src/renderer/wrappers/html-aliases.d.ts
4
+ /**
5
+ * Install a Proxy fallback so a bare intrinsic tag used as a spec type
6
+ * (stray SVG internals like `path`, `rect`, `circle`, `g`, or a raw HTML
7
+ * tag a non-conforming spec slips in) renders as a native React intrinsic
8
+ * element instead of triggering json-render's "no renderer for component
9
+ * type" warning.
10
+ *
11
+ * There is deliberately NO HTML-tag → UDS-component aliasing here: which
12
+ * component backs which tag is config-specific, and the generated prompt
13
+ * already steers specs to real components (`img` → the image component) and
14
+ * the polymorphic `as` prop (`<Box as="section">`) for semantic HTML. So a
15
+ * conforming spec never reaches this Proxy for layout tags; it's a pure
16
+ * native-rendering safety net.
17
+ *
18
+ * Returns a Proxy — successive `wrapRegistry` callers see the proxy
19
+ * shape, which lazily caches intrinsic renderers on `target` as they're
20
+ * accessed so repeated lookups return the same function reference.
21
+ */
22
+ declare function aliasHtmlTypes(reg: ComponentRegistry): ComponentRegistry;
23
+ //#endregion
24
+ export { aliasHtmlTypes };
@@ -0,0 +1,62 @@
1
+ import React from "react";
2
+ //#region src/renderer/wrappers/html-aliases.tsx
3
+ const INTRINSIC_TAG_RE = /^[a-z][a-zA-Z0-9-]*$/;
4
+ const FORBIDDEN_INTRINSIC_TAGS = new Set([
5
+ "script",
6
+ "iframe",
7
+ "object",
8
+ "embed",
9
+ "base",
10
+ "link",
11
+ "meta"
12
+ ]);
13
+ const FORBIDDEN_INTRINSIC_PROPS = new Set(["dangerouslySetInnerHTML"]);
14
+ const NullEl = () => null;
15
+ NullEl.displayName = "ForbiddenIntrinsic";
16
+ /**
17
+ * Install a Proxy fallback so a bare intrinsic tag used as a spec type
18
+ * (stray SVG internals like `path`, `rect`, `circle`, `g`, or a raw HTML
19
+ * tag a non-conforming spec slips in) renders as a native React intrinsic
20
+ * element instead of triggering json-render's "no renderer for component
21
+ * type" warning.
22
+ *
23
+ * There is deliberately NO HTML-tag → UDS-component aliasing here: which
24
+ * component backs which tag is config-specific, and the generated prompt
25
+ * already steers specs to real components (`img` → the image component) and
26
+ * the polymorphic `as` prop (`<Box as="section">`) for semantic HTML. So a
27
+ * conforming spec never reaches this Proxy for layout tags; it's a pure
28
+ * native-rendering safety net.
29
+ *
30
+ * Returns a Proxy — successive `wrapRegistry` callers see the proxy
31
+ * shape, which lazily caches intrinsic renderers on `target` as they're
32
+ * accessed so repeated lookups return the same function reference.
33
+ */
34
+ function aliasHtmlTypes(reg) {
35
+ const wrapped = { ...reg };
36
+ return new Proxy(wrapped, {
37
+ get(target, prop, receiver) {
38
+ if (typeof prop === "string" && prop in target) return Reflect.get(target, prop, receiver);
39
+ if (typeof prop === "string" && FORBIDDEN_INTRINSIC_TAGS.has(prop)) return NullEl;
40
+ if (typeof prop === "string" && INTRINSIC_TAG_RE.test(prop)) {
41
+ const IntrinsicEl = ({ element, children }) => {
42
+ const intrinsicProps = {};
43
+ for (const [key, value] of Object.entries(element.props ?? {})) {
44
+ if (FORBIDDEN_INTRINSIC_PROPS.has(key)) continue;
45
+ intrinsicProps[key] = value;
46
+ }
47
+ return React.createElement(prop, intrinsicProps, children);
48
+ };
49
+ IntrinsicEl.displayName = prop;
50
+ target[prop] = IntrinsicEl;
51
+ return IntrinsicEl;
52
+ }
53
+ return Reflect.get(target, prop, receiver);
54
+ },
55
+ has(target, prop) {
56
+ if (typeof prop === "string" && INTRINSIC_TAG_RE.test(prop)) return true;
57
+ return Reflect.has(target, prop);
58
+ }
59
+ });
60
+ }
61
+ //#endregion
62
+ export { aliasHtmlTypes };
@@ -0,0 +1,16 @@
1
+ import { ComponentRegistry } from "@json-render/react";
2
+
3
+ //#region src/renderer/wrappers/inline-styles.d.ts
4
+ /** Config-derived facts this wrapper needs. Omitted ⇒ the relevant branch
5
+ * no-ops (a raw `style` then passes through to the DOM untouched). */
6
+ interface InlineStyleConfig {
7
+ /** camelCase CSS property → style-prop name (inverted from cssProperty). */
8
+ cssPropertyToStyleProp?: Readonly<Record<string, string>>;
9
+ /** Container primitives: a fixed `height` becomes `minHeight`. */
10
+ layoutComponents?: readonly string[];
11
+ /** Text primitives: a fixed `width`/`height` is dropped. */
12
+ textComponents?: readonly string[];
13
+ }
14
+ declare function wrapInlineStyleProps(reg: ComponentRegistry, config?: InlineStyleConfig): ComponentRegistry;
15
+ //#endregion
16
+ export { wrapInlineStyleProps };
@@ -0,0 +1,104 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region src/renderer/wrappers/inline-styles.tsx
3
+ const HEX_RE = /^#[0-9a-fA-F]{3,8}$/;
4
+ const UNIT_RE = /^-?\d+(\.\d+)?(px|rem|em|%|vh|vw)$/;
5
+ const FUNCTION_CALL_RE = /\w\(.*\)/;
6
+ /** Local component name of a spec type: `yahoo-os:Text` → `Text`. */
7
+ function localName(type) {
8
+ const colon = type.indexOf(":");
9
+ return colon === -1 ? type : type.slice(colon + 1);
10
+ }
11
+ function cssKeyToUdsProp(cssKey, elementType, cssMap, layoutSet, textSet) {
12
+ const type = elementType ? localName(elementType) : void 0;
13
+ if ((cssKey === "width" || cssKey === "height") && type && textSet.has(type)) return;
14
+ if (cssKey === "height" && type && layoutSet.has(type)) return cssMap.minHeight;
15
+ return cssMap[cssKey];
16
+ }
17
+ function shouldDropCssStyle(cssKey, elementType, textSet) {
18
+ const type = elementType ? localName(elementType) : void 0;
19
+ return !!type && textSet.has(type) && (cssKey === "width" || cssKey === "height");
20
+ }
21
+ function cssValueToUdsValue(value) {
22
+ if (typeof value === "number") return `[${value}px]`;
23
+ if (typeof value !== "string") return value;
24
+ if (value.startsWith("[") && value.endsWith("]")) return value;
25
+ if (HEX_RE.test(value) || UNIT_RE.test(value)) return `[${value}]`;
26
+ return value;
27
+ }
28
+ /**
29
+ * Function-call CSS values (`linear-gradient(...)`, `rgb(...)`,
30
+ * `url(...)`, `calc(...)`, `color-mix(...)`, ...) can't become a
31
+ * Tailwind utility class without a corresponding pre-extracted CSS
32
+ * rule, and the canvas loads specs at runtime — Tailwind never sees
33
+ * the value at build time. Leave these in inline `style` so the
34
+ * browser applies them natively.
35
+ */
36
+ function isFunctionCallCssValue(value) {
37
+ return typeof value === "string" && FUNCTION_CALL_RE.test(value);
38
+ }
39
+ /**
40
+ * Parse a raw CSS declaration string (`"background: red; padding: 4px;"`)
41
+ * into a `React.CSSProperties`-shaped object with camelCase keys.
42
+ * Survives `url(...)` and gradient values that contain colons inside
43
+ * their argument lists by splitting only on the FIRST colon per
44
+ * declaration.
45
+ */
46
+ function parseCssDeclarationString(css) {
47
+ const out = {};
48
+ for (const decl of css.split(";")) {
49
+ const trimmed = decl.trim();
50
+ if (!trimmed) continue;
51
+ const colon = trimmed.indexOf(":");
52
+ if (colon === -1) continue;
53
+ const rawKey = trimmed.slice(0, colon).trim();
54
+ const value = trimmed.slice(colon + 1).trim();
55
+ if (!rawKey || !value) continue;
56
+ const camelKey = rawKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
57
+ out[camelKey] = value;
58
+ }
59
+ return out;
60
+ }
61
+ function wrapInlineStyleProps(reg, config = {}) {
62
+ const cssMap = config.cssPropertyToStyleProp ?? {};
63
+ const layoutSet = new Set(config.layoutComponents ?? []);
64
+ const textSet = new Set(config.textComponents ?? []);
65
+ const wrapped = { ...reg };
66
+ for (const [name, Comp] of Object.entries(reg)) wrapped[name] = function InlineStylePropsWrapper(renderProps) {
67
+ const props = renderProps.element.props;
68
+ const elementType = renderProps.element.type;
69
+ const rawStyle = props?.style;
70
+ if (!props || rawStyle == null) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
71
+ let style;
72
+ if (typeof rawStyle === "string") style = parseCssDeclarationString(rawStyle);
73
+ else if (typeof rawStyle === "object" && !Array.isArray(rawStyle)) style = rawStyle;
74
+ else return /* @__PURE__ */ jsx(Comp, { ...renderProps });
75
+ let patched = typeof rawStyle === "string";
76
+ const newProps = { ...props };
77
+ const remainingStyle = {};
78
+ for (const [cssKey, cssValue] of Object.entries(style)) {
79
+ if (isFunctionCallCssValue(cssValue)) {
80
+ remainingStyle[cssKey] = cssValue;
81
+ continue;
82
+ }
83
+ const propName = cssKeyToUdsProp(cssKey, elementType, cssMap, layoutSet, textSet);
84
+ if (propName && newProps[propName] == null) {
85
+ newProps[propName] = cssValueToUdsValue(cssValue);
86
+ patched = true;
87
+ } else if (shouldDropCssStyle(cssKey, elementType, textSet)) patched = true;
88
+ else remainingStyle[cssKey] = cssValue;
89
+ }
90
+ if (!patched) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
91
+ if (Object.keys(remainingStyle).length > 0) newProps.style = remainingStyle;
92
+ else delete newProps.style;
93
+ return /* @__PURE__ */ jsx(Comp, {
94
+ ...renderProps,
95
+ element: {
96
+ ...renderProps.element,
97
+ props: newProps
98
+ }
99
+ });
100
+ };
101
+ return wrapped;
102
+ }
103
+ //#endregion
104
+ export { wrapInlineStyleProps };
@@ -0,0 +1,25 @@
1
+ import { ComponentRegistry } from "@json-render/react";
2
+
3
+ //#region src/renderer/wrappers/slot-resolution.d.ts
4
+ /**
5
+ * Resolve `$slot` prop references to rendered React children.
6
+ *
7
+ * Components like `Card` declare named slots in their authoring spec:
8
+ *
9
+ * props: {
10
+ * title: slot('header/text'),
11
+ * footer: slot('footer'),
12
+ * }
13
+ *
14
+ * Codegen lowers each `slot(...)` to a `{ $slot: 'key' }` marker that
15
+ * surfaces in `element.props`. At render time this wrapper pairs each
16
+ * slot key against the keyed React children passed in by `Renderer`
17
+ * (json-render assigns each rendered child a key derived from its
18
+ * spec element id), pulls the matching child out of the regular
19
+ * children stream, and feeds it through as the resolved prop value.
20
+ * Children whose keys don't match any slot pass through to the
21
+ * component as regular `children`.
22
+ */
23
+ declare function wrapSlotResolution(reg: ComponentRegistry): ComponentRegistry;
24
+ //#endregion
25
+ export { wrapSlotResolution };