@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.
- package/dist/AssetGroup.d.ts +77 -0
- package/dist/AssetGroup.js +125 -0
- package/dist/Component.d.ts +308 -0
- package/dist/Component.js +896 -0
- package/dist/ComponentGroup.d.ts +20 -0
- package/dist/ComponentGroup.js +46 -0
- package/dist/CompositeStyle.d.ts +27 -0
- package/dist/CompositeStyle.js +52 -0
- package/dist/Config.d.ts +423 -0
- package/dist/Config.js +1429 -0
- package/dist/Mode.d.ts +41 -0
- package/dist/Mode.js +81 -0
- package/dist/Modifier.d.ts +51 -0
- package/dist/Modifier.js +97 -0
- package/dist/MotionDef.d.ts +49 -0
- package/dist/MotionDef.js +97 -0
- package/dist/Props.d.ts +317 -0
- package/dist/Props.js +35 -0
- package/dist/Provider.d.ts +20 -0
- package/dist/Provider.js +14 -0
- package/dist/StyleProp.d.ts +112 -0
- package/dist/StyleProp.js +197 -0
- package/dist/Token.d.ts +55 -0
- package/dist/Token.js +112 -0
- package/dist/TokenGroup.d.ts +32 -0
- package/dist/TokenGroup.js +68 -0
- package/dist/asset-kind.d.ts +55 -0
- package/dist/asset-kind.js +29 -0
- package/dist/brands.d.ts +30 -0
- package/dist/brands.js +20 -0
- package/dist/captureCallerPath.d.ts +48 -0
- package/dist/captureCallerPath.js +95 -0
- package/dist/colorExpressions.d.ts +131 -0
- package/dist/colorExpressions.js +148 -0
- package/dist/defineAssetGroup.d.ts +166 -0
- package/dist/defineAssetGroup.js +264 -0
- package/dist/defineProvider.d.ts +29 -0
- package/dist/defineProvider.js +60 -0
- package/dist/element-marker.d.ts +54 -0
- package/dist/element-marker.js +113 -0
- package/dist/entity-utils.d.ts +56 -0
- package/dist/entity-utils.js +105 -0
- package/dist/factories.d.ts +707 -0
- package/dist/factories.js +393 -0
- package/dist/foreign-component-name.d.ts +21 -0
- package/dist/foreign-component-name.js +42 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +28 -0
- package/dist/interpolate.d.ts +20 -0
- package/dist/interpolate.js +10 -0
- package/dist/jsx/__fixtures__/cross-component-preview.d.ts +3 -0
- package/dist/jsx/__fixtures__/cross-component-preview.js +15 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +15 -0
- package/dist/jsx/jsx-dev-runtime.js +11 -0
- package/dist/jsx/jsx-runtime.d.ts +48 -0
- package/dist/jsx/jsx-runtime.js +305 -0
- package/dist/markers.d.ts +217 -0
- package/dist/markers.js +67 -0
- package/dist/refs.d.ts +158 -0
- package/dist/refs.js +104 -0
- package/dist/renderer/RendererErrorBoundary.d.ts +26 -0
- package/dist/renderer/RendererErrorBoundary.js +30 -0
- package/dist/renderer/UdsRenderer.d.ts +80 -0
- package/dist/renderer/UdsRenderer.js +33 -0
- package/dist/renderer/assetRenderable.d.ts +13 -0
- package/dist/renderer/assetRenderable.js +13 -0
- package/dist/renderer/index.d.ts +14 -0
- package/dist/renderer/index.js +14 -0
- package/dist/renderer/makeRegistry.d.ts +34 -0
- package/dist/renderer/makeRegistry.js +52 -0
- package/dist/renderer/makeUdsRenderer.d.ts +29 -0
- package/dist/renderer/makeUdsRenderer.js +35 -0
- package/dist/renderer/primitives/FragmentRenderer.d.ts +12 -0
- package/dist/renderer/primitives/FragmentRenderer.js +11 -0
- package/dist/renderer/primitives/SlotRenderer.d.ts +21 -0
- package/dist/renderer/primitives/SlotRenderer.js +20 -0
- package/dist/renderer/wrapRegistry.d.ts +64 -0
- package/dist/renderer/wrapRegistry.js +39 -0
- package/dist/renderer/wrappers/component-slots.d.ts +41 -0
- package/dist/renderer/wrappers/component-slots.js +66 -0
- package/dist/renderer/wrappers/event-bridge.d.ts +20 -0
- package/dist/renderer/wrappers/event-bridge.js +78 -0
- package/dist/renderer/wrappers/hex-normalize.d.ts +14 -0
- package/dist/renderer/wrappers/hex-normalize.js +35 -0
- package/dist/renderer/wrappers/html-aliases.d.ts +24 -0
- package/dist/renderer/wrappers/html-aliases.js +62 -0
- package/dist/renderer/wrappers/inline-styles.d.ts +16 -0
- package/dist/renderer/wrappers/inline-styles.js +104 -0
- package/dist/renderer/wrappers/slot-resolution.d.ts +25 -0
- package/dist/renderer/wrappers/slot-resolution.js +68 -0
- package/dist/renderer/wrappers/void-elements.d.ts +23 -0
- package/dist/renderer/wrappers/void-elements.js +28 -0
- package/dist/spec/apply-forced-modifiers.d.ts +19 -0
- package/dist/spec/apply-forced-modifiers.js +49 -0
- package/dist/spec/asset-jsx.d.ts +48 -0
- package/dist/spec/asset-jsx.js +48 -0
- package/dist/spec/collapse-text-labels.d.ts +44 -0
- package/dist/spec/collapse-text-labels.js +107 -0
- package/dist/spec/empty-node-slots.d.ts +51 -0
- package/dist/spec/empty-node-slots.js +141 -0
- package/dist/spec/index.d.ts +10 -0
- package/dist/spec/index.js +10 -0
- package/dist/spec/jsxToSpec.d.ts +48 -0
- package/dist/spec/jsxToSpec.js +506 -0
- package/dist/spec/layer-props.d.ts +52 -0
- package/dist/spec/layer-props.js +149 -0
- package/dist/spec/preview-controls.d.ts +44 -0
- package/dist/spec/preview-controls.js +139 -0
- package/dist/spec/slot-refs.d.ts +39 -0
- package/dist/spec/slot-refs.js +56 -0
- package/dist/spec/specToJsx.d.ts +35 -0
- package/dist/spec/specToJsx.js +127 -0
- package/dist/token-override-rows.d.ts +66 -0
- package/dist/token-override-rows.js +223 -0
- package/dist/tokenValueType.d.ts +34 -0
- package/dist/tokenValueType.js +138 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/css-properties.d.ts +232 -0
- package/dist/types/css-properties.js +14 -0
- package/dist/types/css-property-keywords.d.ts +156 -0
- package/dist/types/css-property-keywords.js +616 -0
- package/dist/types/css-values.d.ts +63 -0
- package/dist/types/css-values.js +16 -0
- package/dist/types.d.ts +708 -0
- package/dist/types.js +12 -0
- package/dist/units.d.ts +14 -0
- package/dist/units.js +16 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- 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 };
|