@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,68 @@
|
|
|
1
|
+
import { isSlotRef } from "../../spec/slot-refs.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/renderer/wrappers/slot-resolution.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Resolve `$slot` prop references to rendered React children.
|
|
7
|
+
*
|
|
8
|
+
* Components like `Card` declare named slots in their authoring spec:
|
|
9
|
+
*
|
|
10
|
+
* props: {
|
|
11
|
+
* title: slot('header/text'),
|
|
12
|
+
* footer: slot('footer'),
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Codegen lowers each `slot(...)` to a `{ $slot: 'key' }` marker that
|
|
16
|
+
* surfaces in `element.props`. At render time this wrapper pairs each
|
|
17
|
+
* slot key against the keyed React children passed in by `Renderer`
|
|
18
|
+
* (json-render assigns each rendered child a key derived from its
|
|
19
|
+
* spec element id), pulls the matching child out of the regular
|
|
20
|
+
* children stream, and feeds it through as the resolved prop value.
|
|
21
|
+
* Children whose keys don't match any slot pass through to the
|
|
22
|
+
* component as regular `children`.
|
|
23
|
+
*/
|
|
24
|
+
function wrapSlotResolution(reg) {
|
|
25
|
+
const wrapped = {};
|
|
26
|
+
for (const [name, Comp] of Object.entries(reg)) wrapped[name] = function SlotWrapper(renderProps) {
|
|
27
|
+
const { element, children } = renderProps;
|
|
28
|
+
const props = element.props;
|
|
29
|
+
if (!props) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
|
|
30
|
+
const slotEntries = [];
|
|
31
|
+
for (const [propName, value] of Object.entries(props)) if (isSlotRef(value)) slotEntries.push([propName, value.$slot]);
|
|
32
|
+
if (slotEntries.length === 0) return /* @__PURE__ */ jsx(Comp, { ...renderProps });
|
|
33
|
+
const slotKeySet = /* @__PURE__ */ new Set();
|
|
34
|
+
for (const [, ref] of slotEntries) {
|
|
35
|
+
const refs = Array.isArray(ref) ? ref : [ref];
|
|
36
|
+
for (const r of refs) slotKeySet.add(r);
|
|
37
|
+
}
|
|
38
|
+
const childArray = React.Children.toArray(children);
|
|
39
|
+
const slotChildMap = /* @__PURE__ */ new Map();
|
|
40
|
+
const regularChildren = [];
|
|
41
|
+
for (const child of childArray) {
|
|
42
|
+
if (React.isValidElement(child) && typeof child.key === "string") {
|
|
43
|
+
const elementKey = child.key.startsWith(".$") ? child.key.slice(2) : child.key;
|
|
44
|
+
if (slotKeySet.has(elementKey)) {
|
|
45
|
+
slotChildMap.set(elementKey, child);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
regularChildren.push(child);
|
|
50
|
+
}
|
|
51
|
+
const resolvedProps = { ...props };
|
|
52
|
+
for (const [propName, ref] of slotEntries) if (Array.isArray(ref)) {
|
|
53
|
+
const resolved = ref.map((key) => slotChildMap.get(key)).filter(Boolean);
|
|
54
|
+
resolvedProps[propName] = resolved.length > 0 ? resolved : void 0;
|
|
55
|
+
} else resolvedProps[propName] = slotChildMap.get(ref) ?? void 0;
|
|
56
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
57
|
+
...renderProps,
|
|
58
|
+
element: {
|
|
59
|
+
...element,
|
|
60
|
+
props: resolvedProps
|
|
61
|
+
},
|
|
62
|
+
children: regularChildren.length > 0 ? regularChildren : void 0
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
return wrapped;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { wrapSlotResolution };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentRegistry } from "@json-render/react";
|
|
2
|
+
|
|
3
|
+
//#region src/renderer/wrappers/void-elements.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Strip `children` from void HTML elements (e.g. `<img>`-backed UDS
|
|
6
|
+
* components) that React refuses to render with children. Source
|
|
7
|
+
* Specs sometimes include a `children` prop on these — silently drop
|
|
8
|
+
* it rather than letting React throw.
|
|
9
|
+
*
|
|
10
|
+
* `voidComponents` is config-derived (component names whose root renders a
|
|
11
|
+
* void HTML tag), so this stays config-agnostic. Matches on the
|
|
12
|
+
* namespace-stripped local name, so a namespaced registry (`yahoo-os:Image`)
|
|
13
|
+
* is recognized, not just the bare `Image` key. No void set ⇒ no-op.
|
|
14
|
+
*/
|
|
15
|
+
interface VoidElementsConfig {
|
|
16
|
+
/** Component names whose root renders a void HTML tag (`img`, `input`, …). */
|
|
17
|
+
voidComponents?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
declare function wrapVoidElements(reg: ComponentRegistry, {
|
|
20
|
+
voidComponents
|
|
21
|
+
}?: VoidElementsConfig): ComponentRegistry;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { wrapVoidElements };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
//#region src/renderer/wrappers/void-elements.tsx
|
|
3
|
+
/** Local component name of a registry key: `yahoo-os:Image` → `Image`,
|
|
4
|
+
* `Image` → `Image`. Registry keys are `<namespace>:<Name>`; component names
|
|
5
|
+
* never contain `:`, so split on the first one. */
|
|
6
|
+
function localName(key) {
|
|
7
|
+
const colon = key.indexOf(":");
|
|
8
|
+
return colon === -1 ? key : key.slice(colon + 1);
|
|
9
|
+
}
|
|
10
|
+
function wrapVoidElements(reg, { voidComponents } = {}) {
|
|
11
|
+
if (!voidComponents || voidComponents.length === 0) return reg;
|
|
12
|
+
const voidSet = new Set(voidComponents);
|
|
13
|
+
const wrapped = { ...reg };
|
|
14
|
+
for (const key of Object.keys(reg)) {
|
|
15
|
+
if (!voidSet.has(localName(key))) continue;
|
|
16
|
+
const Orig = wrapped[key];
|
|
17
|
+
if (!Orig) continue;
|
|
18
|
+
wrapped[key] = function VoidElementWrapper(p) {
|
|
19
|
+
return /* @__PURE__ */ jsx(Orig, {
|
|
20
|
+
...p,
|
|
21
|
+
children: void 0
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return wrapped;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { wrapVoidElements };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/spec/apply-forced-modifiers.d.ts
|
|
2
|
+
type Props = Record<string, unknown>;
|
|
3
|
+
interface SpecShape {
|
|
4
|
+
root: string;
|
|
5
|
+
elements: Record<string, {
|
|
6
|
+
props?: Props;
|
|
7
|
+
}>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Return a copy of `spec` with each active state modifier folded into concrete
|
|
11
|
+
* style props on every element that declares it. `activeModifiers` are the
|
|
12
|
+
* forced states for this cell (e.g. `['_hover']`); `state` is the seeded
|
|
13
|
+
* discriminator model (`{ variant, size, __previewSeedRow, … }`) the modifier
|
|
14
|
+
* blocks' `$cond`s key off. Non-mutating: only changed elements are rebuilt,
|
|
15
|
+
* and an empty `activeModifiers` returns the input spec unchanged.
|
|
16
|
+
*/
|
|
17
|
+
declare function applyForcedModifiers<S extends SpecShape>(spec: S, activeModifiers: readonly string[], state: Props): S;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { applyForcedModifiers };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { evaluateVisibility } from "@json-render/core";
|
|
2
|
+
//#region src/spec/apply-forced-modifiers.ts
|
|
3
|
+
function isCondValue(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && "$cond" in value;
|
|
5
|
+
}
|
|
6
|
+
function resolveBlock(value, state) {
|
|
7
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
8
|
+
if (isCondValue(value)) return resolveBlock(evaluateVisibility(value.$cond, { stateModel: state }) ? value.$then : value.$else, state);
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Return a copy of `spec` with each active state modifier folded into concrete
|
|
13
|
+
* style props on every element that declares it. `activeModifiers` are the
|
|
14
|
+
* forced states for this cell (e.g. `['_hover']`); `state` is the seeded
|
|
15
|
+
* discriminator model (`{ variant, size, __previewSeedRow, … }`) the modifier
|
|
16
|
+
* blocks' `$cond`s key off. Non-mutating: only changed elements are rebuilt,
|
|
17
|
+
* and an empty `activeModifiers` returns the input spec unchanged.
|
|
18
|
+
*/
|
|
19
|
+
function applyForcedModifiers(spec, activeModifiers, state) {
|
|
20
|
+
if (activeModifiers.length === 0) return spec;
|
|
21
|
+
let changed = false;
|
|
22
|
+
const nextElements = {};
|
|
23
|
+
for (const [key, element] of Object.entries(spec.elements)) {
|
|
24
|
+
const props = element.props;
|
|
25
|
+
const present = props ? activeModifiers.filter((mod) => mod in props) : [];
|
|
26
|
+
if (!props || present.length === 0) {
|
|
27
|
+
nextElements[key] = element;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const nextProps = { ...props };
|
|
31
|
+
for (const mod of present) {
|
|
32
|
+
const block = resolveBlock(nextProps[mod], state);
|
|
33
|
+
if (block) Object.assign(nextProps, block);
|
|
34
|
+
delete nextProps[mod];
|
|
35
|
+
}
|
|
36
|
+
nextElements[key] = {
|
|
37
|
+
...element,
|
|
38
|
+
props: nextProps
|
|
39
|
+
};
|
|
40
|
+
changed = true;
|
|
41
|
+
}
|
|
42
|
+
if (!changed) return spec;
|
|
43
|
+
return {
|
|
44
|
+
...spec,
|
|
45
|
+
elements: nextElements
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { applyForcedModifiers };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/spec/asset-jsx.d.ts
|
|
2
|
+
/** Pull the slug + member out of an asset id, or `null` for a normal type. */
|
|
3
|
+
declare function parseAssetType(type: string): {
|
|
4
|
+
slug: string;
|
|
5
|
+
member: string;
|
|
6
|
+
} | null;
|
|
7
|
+
/**
|
|
8
|
+
* `slug → authoring-component name` (e.g. `{ icons: 'Icon' }`). Derived from
|
|
9
|
+
* the asset groups that declare a `component`; a slug missing from the map has
|
|
10
|
+
* no authoring component and falls back to the bare member tag.
|
|
11
|
+
*/
|
|
12
|
+
type AssetComponentMap = Readonly<Record<string, string>>;
|
|
13
|
+
/** How a placed asset node should appear in exported JSX. */
|
|
14
|
+
interface AssetJsxForm {
|
|
15
|
+
/** The JSX tag — the authoring component (`Icon`) or the bare member. */
|
|
16
|
+
tag: string;
|
|
17
|
+
/**
|
|
18
|
+
* The `name` attribute value when the authoring component carries the
|
|
19
|
+
* member identity (`name="Trophy"`). Absent on the bare-member fallback,
|
|
20
|
+
* which IS the member.
|
|
21
|
+
*/
|
|
22
|
+
nameAttr?: string;
|
|
23
|
+
/** Identifier to import — the component when mapped, else the member. */
|
|
24
|
+
importName: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a spec element `type` to its exported-JSX form, or `null` when the
|
|
28
|
+
* type is not an asset node (a normal component — caller serializes as usual).
|
|
29
|
+
*
|
|
30
|
+
* - mapped slug → `<Icon name="Member" … />` (component-typed export);
|
|
31
|
+
* - unmapped slug → `<Member … />` (component-less fallback — a self-contained
|
|
32
|
+
* member renders itself; a bare-path glyph would need raw `<svg>`, which the
|
|
33
|
+
* string-only serializers can't synthesize, so the member tag is the best
|
|
34
|
+
* they can emit).
|
|
35
|
+
*/
|
|
36
|
+
declare function assetJsxForm(type: string, assetComponents?: AssetComponentMap): AssetJsxForm | null;
|
|
37
|
+
/**
|
|
38
|
+
* Inverse of `assetJsxForm` for the editor round-trip: given a parsed JSX tag
|
|
39
|
+
* and its props, reconstruct the asset-node `type` string — or `null` if the
|
|
40
|
+
* tag is a genuine component, not an authoring component placing a known member.
|
|
41
|
+
* The caller closes over its live config to find the group whose `component`
|
|
42
|
+
* matches `tag` and whose members include the `name` value, then returns
|
|
43
|
+
* `group.assetType(name)`. When it resolves, the parser drops the `name` prop
|
|
44
|
+
* (the member identity lives in the type) and keeps the rest (variant, size).
|
|
45
|
+
*/
|
|
46
|
+
type AssetNodeResolver = (tag: string, props: Readonly<Record<string, unknown>>) => string | null;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { AssetComponentMap, AssetJsxForm, AssetNodeResolver, assetJsxForm, parseAssetType };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/spec/asset-jsx.ts
|
|
2
|
+
const ASSET_MARKER = "asset:";
|
|
3
|
+
const NAMESPACED_ASSET_MARKER = ":asset:";
|
|
4
|
+
/** Pull the slug + member out of an asset id, or `null` for a normal type. */
|
|
5
|
+
function parseAssetType(type) {
|
|
6
|
+
let bodyStart;
|
|
7
|
+
if (type.startsWith(ASSET_MARKER)) bodyStart = 6;
|
|
8
|
+
else {
|
|
9
|
+
const markerIndex = type.indexOf(NAMESPACED_ASSET_MARKER);
|
|
10
|
+
if (markerIndex === -1) return null;
|
|
11
|
+
bodyStart = markerIndex + 7;
|
|
12
|
+
}
|
|
13
|
+
const slashIndex = type.indexOf("/", bodyStart);
|
|
14
|
+
if (slashIndex === -1) return null;
|
|
15
|
+
const slug = type.slice(bodyStart, slashIndex);
|
|
16
|
+
const member = type.slice(slashIndex + 1);
|
|
17
|
+
if (!slug || !member) return null;
|
|
18
|
+
return {
|
|
19
|
+
slug,
|
|
20
|
+
member
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a spec element `type` to its exported-JSX form, or `null` when the
|
|
25
|
+
* type is not an asset node (a normal component — caller serializes as usual).
|
|
26
|
+
*
|
|
27
|
+
* - mapped slug → `<Icon name="Member" … />` (component-typed export);
|
|
28
|
+
* - unmapped slug → `<Member … />` (component-less fallback — a self-contained
|
|
29
|
+
* member renders itself; a bare-path glyph would need raw `<svg>`, which the
|
|
30
|
+
* string-only serializers can't synthesize, so the member tag is the best
|
|
31
|
+
* they can emit).
|
|
32
|
+
*/
|
|
33
|
+
function assetJsxForm(type, assetComponents) {
|
|
34
|
+
const parsed = parseAssetType(type);
|
|
35
|
+
if (!parsed) return null;
|
|
36
|
+
const component = assetComponents?.[parsed.slug];
|
|
37
|
+
if (component) return {
|
|
38
|
+
tag: component,
|
|
39
|
+
nameAttr: parsed.member,
|
|
40
|
+
importName: component
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
tag: parsed.member,
|
|
44
|
+
importName: parsed.member
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { assetJsxForm, parseAssetType };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/spec/collapse-text-labels.d.ts
|
|
2
|
+
type Props = Record<string, unknown>;
|
|
3
|
+
interface ElementShape {
|
|
4
|
+
type: string;
|
|
5
|
+
props?: Props;
|
|
6
|
+
children?: unknown;
|
|
7
|
+
}
|
|
8
|
+
interface SpecShape {
|
|
9
|
+
root: string;
|
|
10
|
+
elements: Record<string, ElementShape>;
|
|
11
|
+
}
|
|
12
|
+
interface ComponentClassification {
|
|
13
|
+
derived: {
|
|
14
|
+
acceptsChildren: boolean;
|
|
15
|
+
acceptsChildNodes: boolean;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
interface ConfigLike {
|
|
19
|
+
getComponent(type: string): ComponentClassification | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** One collapse the transform performed — surfaced for lint/reporting. */
|
|
22
|
+
interface CollapsedTextLabel {
|
|
23
|
+
/** The string-label component whose label was inlined. */
|
|
24
|
+
parentKey: string;
|
|
25
|
+
/** The string-label component's spec `type` (e.g. `yahoo-os:Badge`). */
|
|
26
|
+
parentType: string;
|
|
27
|
+
/** The wrapped Text element that was removed (when it wasn't shared). */
|
|
28
|
+
childKey: string;
|
|
29
|
+
/** The label text hoisted onto the parent's `props.children`. */
|
|
30
|
+
text: string;
|
|
31
|
+
}
|
|
32
|
+
interface CollapseTextLabelsResult<S extends SpecShape> {
|
|
33
|
+
spec: S;
|
|
34
|
+
collapsed: CollapsedTextLabel[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Return a copy of `spec` with every redundant Text-wrapped label folded into a
|
|
38
|
+
* string `children` on the string-label component that wraps it (see file
|
|
39
|
+
* header). Non-mutating: unchanged elements are reused, and a spec with no such
|
|
40
|
+
* wrappers is returned as-is with an empty `collapsed` report.
|
|
41
|
+
*/
|
|
42
|
+
declare function collapseWrappedTextLabels<S extends SpecShape>(spec: S, config: ConfigLike): CollapseTextLabelsResult<S>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { CollapseTextLabelsResult, CollapsedTextLabel, collapseWrappedTextLabels };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region src/spec/collapse-text-labels.ts
|
|
2
|
+
/** Child element keys an element references through its `children` array. */
|
|
3
|
+
function childKeysOf(element) {
|
|
4
|
+
if (!Array.isArray(element.children)) return [];
|
|
5
|
+
return element.children.filter((c) => typeof c === "string");
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Count every parent→child edge in the spec so a wrapped Text node is only
|
|
9
|
+
* deleted when nothing *else* still points at it. Covers `children` arrays and
|
|
10
|
+
* top-level `$slot` prop refs (the two ways the renderer reaches an element).
|
|
11
|
+
*/
|
|
12
|
+
function countReferences(elements) {
|
|
13
|
+
const counts = /* @__PURE__ */ new Map();
|
|
14
|
+
const bump = (key) => counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
15
|
+
for (const element of Object.values(elements)) {
|
|
16
|
+
for (const child of childKeysOf(element)) bump(child);
|
|
17
|
+
if (!element.props) continue;
|
|
18
|
+
for (const value of Object.values(element.props)) {
|
|
19
|
+
if (typeof value !== "object" || value === null || !("$slot" in value)) continue;
|
|
20
|
+
const slot = value.$slot;
|
|
21
|
+
const refs = Array.isArray(slot) ? slot : [slot];
|
|
22
|
+
for (const ref of refs) if (typeof ref === "string") bump(ref);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return counts;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A *bare string leaf* is an element whose only rendered content is a string
|
|
29
|
+
* `children` prop: no element children, and no prop other than `children`. Such
|
|
30
|
+
* a node contributes exactly its text, so flattening it onto a string-label
|
|
31
|
+
* parent is lossless. Returns the string, or `undefined` if the element carries
|
|
32
|
+
* anything more (own styling, icons, nested children) and must be preserved.
|
|
33
|
+
*/
|
|
34
|
+
function bareLabelText(element) {
|
|
35
|
+
if (childKeysOf(element).length > 0) return void 0;
|
|
36
|
+
const props = element.props;
|
|
37
|
+
if (!props) return void 0;
|
|
38
|
+
const text = props.children;
|
|
39
|
+
if (typeof text !== "string") return void 0;
|
|
40
|
+
if (Object.keys(props).filter((k) => k !== "children").length > 0) return void 0;
|
|
41
|
+
return text;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return a copy of `spec` with every redundant Text-wrapped label folded into a
|
|
45
|
+
* string `children` on the string-label component that wraps it (see file
|
|
46
|
+
* header). Non-mutating: unchanged elements are reused, and a spec with no such
|
|
47
|
+
* wrappers is returned as-is with an empty `collapsed` report.
|
|
48
|
+
*/
|
|
49
|
+
function collapseWrappedTextLabels(spec, config) {
|
|
50
|
+
const collapsed = [];
|
|
51
|
+
const refCounts = countReferences(spec.elements);
|
|
52
|
+
const rewrites = /* @__PURE__ */ new Map();
|
|
53
|
+
const toDelete = /* @__PURE__ */ new Set();
|
|
54
|
+
for (const [key, element] of Object.entries(spec.elements)) {
|
|
55
|
+
const component = config.getComponent(element.type);
|
|
56
|
+
if (!component) continue;
|
|
57
|
+
const { acceptsChildren, acceptsChildNodes } = component.derived;
|
|
58
|
+
if (!acceptsChildren || acceptsChildNodes) continue;
|
|
59
|
+
const childKeys = childKeysOf(element);
|
|
60
|
+
if (childKeys.length !== 1) continue;
|
|
61
|
+
const existingLabel = element.props?.children;
|
|
62
|
+
if (typeof existingLabel === "string" && existingLabel !== "") continue;
|
|
63
|
+
const childKey = childKeys[0];
|
|
64
|
+
const child = spec.elements[childKey];
|
|
65
|
+
if (!child) continue;
|
|
66
|
+
const text = bareLabelText(child);
|
|
67
|
+
if (text === void 0) continue;
|
|
68
|
+
rewrites.set(key, text);
|
|
69
|
+
if ((refCounts.get(childKey) ?? 0) <= 1) toDelete.add(childKey);
|
|
70
|
+
collapsed.push({
|
|
71
|
+
parentKey: key,
|
|
72
|
+
parentType: element.type,
|
|
73
|
+
childKey,
|
|
74
|
+
text
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (collapsed.length === 0) return {
|
|
78
|
+
spec,
|
|
79
|
+
collapsed
|
|
80
|
+
};
|
|
81
|
+
const nextElements = {};
|
|
82
|
+
for (const [key, element] of Object.entries(spec.elements)) {
|
|
83
|
+
if (toDelete.has(key)) continue;
|
|
84
|
+
const label = rewrites.get(key);
|
|
85
|
+
if (label === void 0) {
|
|
86
|
+
nextElements[key] = element;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const { children: _dropped, ...rest } = element;
|
|
90
|
+
nextElements[key] = {
|
|
91
|
+
...rest,
|
|
92
|
+
props: {
|
|
93
|
+
...element.props,
|
|
94
|
+
children: label
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
spec: {
|
|
100
|
+
...spec,
|
|
101
|
+
elements: nextElements
|
|
102
|
+
},
|
|
103
|
+
collapsed
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { collapseWrappedTextLabels };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Component } from "../Component.js";
|
|
2
|
+
import { Spec } from "@json-render/core";
|
|
3
|
+
|
|
4
|
+
//#region src/spec/empty-node-slots.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Materialize every EMPTY layer-bound node slot of `spec`'s root as a `Slot`
|
|
7
|
+
* element wired through a `$slot` ref, so an unfilled slot is a stable element
|
|
8
|
+
* in the spec rather than an absent prop — the studio canvas needs a drop
|
|
9
|
+
* target, the layers panel a row, and the inspector an "Empty" state. Slots the
|
|
10
|
+
* spec already fills are left as-is. Returns `spec` unchanged when there's
|
|
11
|
+
* nothing to inject (no node slots, or all of them filled).
|
|
12
|
+
*/
|
|
13
|
+
declare function withEmptyNodeSlots(spec: Spec, component: Pick<Component, 'derived'>): Spec;
|
|
14
|
+
/**
|
|
15
|
+
* Pin a persistent trailing `Slot` as the last child of every container element
|
|
16
|
+
* in `spec` (tree-wide), so a container always exposes an insertion drop target
|
|
17
|
+
* at the bottom of its children — the same `Slot` model used for node slots,
|
|
18
|
+
* but appended to `children` rather than replacing the element when filled.
|
|
19
|
+
* Idempotent: a container whose children already end in a `Slot` is left as-is,
|
|
20
|
+
* so re-running (and filling, which inserts *before* the trailing slot) never
|
|
21
|
+
* stacks duplicates. Returns `spec` unchanged when there's nothing to add.
|
|
22
|
+
*/
|
|
23
|
+
declare function withContainerChildSlots(spec: Spec): Spec;
|
|
24
|
+
/**
|
|
25
|
+
* Compose both slot injections into the canvas's render view: layer-bound node
|
|
26
|
+
* slots on a component instance's root (`withEmptyNodeSlots`, needs the
|
|
27
|
+
* component definition) plus a trailing insertion `Slot` in every container,
|
|
28
|
+
* tree-wide (`withContainerChildSlots`). This is the spec the studio canvas
|
|
29
|
+
* renders so empty slots show as drop targets — it is NEVER persisted. Stored
|
|
30
|
+
* specs stay slot-free; `stripInjectedSlots` is the inverse, applied at every
|
|
31
|
+
* serialization boundary (DB, clipboard, AI prompt). Both helpers return the
|
|
32
|
+
* same reference when there's nothing to add, so this is cheap and idempotent —
|
|
33
|
+
* re-running on an already-slotted spec adds nothing.
|
|
34
|
+
*/
|
|
35
|
+
declare function withRenderSlots(spec: Spec, component: Pick<Component, 'derived'> | null | undefined): Spec;
|
|
36
|
+
/**
|
|
37
|
+
* Inverse of `withEmptyNodeSlots` + `withContainerChildSlots`: drop every
|
|
38
|
+
* injected `Slot` element and scrub its references, so a spec carries no
|
|
39
|
+
* editing scaffolding. A `Slot`-typed element is ALWAYS an injected content
|
|
40
|
+
* hole (json-render's placeholder), never authored content — both injectors
|
|
41
|
+
* emit `type: 'Slot'` — so removing all of them and their references is the
|
|
42
|
+
* exact reversal: a trailing `children` Slot drops out of its parent's
|
|
43
|
+
* `children`, and an empty node slot drops both its `Slot` element and the
|
|
44
|
+
* `{ $slot }` prop that pointed at it (a FILLED slot points at a real element,
|
|
45
|
+
* which is not `Slot`-typed, so it survives). Use at export/serialization
|
|
46
|
+
* boundaries (e.g. clipboard); the canvas re-injects fresh drop targets on
|
|
47
|
+
* load. Idempotent: returns `spec` unchanged when there are no `Slot` elements.
|
|
48
|
+
*/
|
|
49
|
+
declare function stripInjectedSlots(spec: Spec): Spec;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { stripInjectedSlots, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
//#region src/spec/empty-node-slots.ts
|
|
2
|
+
const SLOT_TYPE = "Slot";
|
|
3
|
+
/**
|
|
4
|
+
* Layer-bound single-node slots — Button `startIcon`/`endIcon`, Item `media`:
|
|
5
|
+
* a `slot()` bound to a named layer whose value is a renderable node. Open
|
|
6
|
+
* `children` slots (no layer) are authored as child layers, and text/scalar
|
|
7
|
+
* slots as inputs, so neither is materialized here.
|
|
8
|
+
*/
|
|
9
|
+
function nodeSlotNames(component) {
|
|
10
|
+
return component.derived.props.filter((p) => p.kind === "slot" && p.layer !== void 0 && p.valueType === "ReactNode" && p.authoredType !== "string").map((p) => p.name);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Materialize every EMPTY layer-bound node slot of `spec`'s root as a `Slot`
|
|
14
|
+
* element wired through a `$slot` ref, so an unfilled slot is a stable element
|
|
15
|
+
* in the spec rather than an absent prop — the studio canvas needs a drop
|
|
16
|
+
* target, the layers panel a row, and the inspector an "Empty" state. Slots the
|
|
17
|
+
* spec already fills are left as-is. Returns `spec` unchanged when there's
|
|
18
|
+
* nothing to inject (no node slots, or all of them filled).
|
|
19
|
+
*/
|
|
20
|
+
function withEmptyNodeSlots(spec, component) {
|
|
21
|
+
const names = nodeSlotNames(component);
|
|
22
|
+
if (names.length === 0) return spec;
|
|
23
|
+
const rootKey = spec.root;
|
|
24
|
+
const next = structuredClone(spec);
|
|
25
|
+
const elements = next.elements;
|
|
26
|
+
const root = elements[rootKey];
|
|
27
|
+
if (!root) return spec;
|
|
28
|
+
root.props = root.props ?? {};
|
|
29
|
+
let injected = false;
|
|
30
|
+
for (const name of names) {
|
|
31
|
+
if (root.props[name] !== void 0) continue;
|
|
32
|
+
const key = `${rootKey}__${name}__slot`;
|
|
33
|
+
elements[key] = {
|
|
34
|
+
type: SLOT_TYPE,
|
|
35
|
+
props: { name }
|
|
36
|
+
};
|
|
37
|
+
root.props[name] = { $slot: key };
|
|
38
|
+
injected = true;
|
|
39
|
+
}
|
|
40
|
+
return injected ? next : spec;
|
|
41
|
+
}
|
|
42
|
+
const CONTAINER_TYPES = new Set([
|
|
43
|
+
"VStack",
|
|
44
|
+
"HStack",
|
|
45
|
+
"Box",
|
|
46
|
+
"ZStack",
|
|
47
|
+
"Flex",
|
|
48
|
+
"Grid",
|
|
49
|
+
"ScrollView"
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Pin a persistent trailing `Slot` as the last child of every container element
|
|
53
|
+
* in `spec` (tree-wide), so a container always exposes an insertion drop target
|
|
54
|
+
* at the bottom of its children — the same `Slot` model used for node slots,
|
|
55
|
+
* but appended to `children` rather than replacing the element when filled.
|
|
56
|
+
* Idempotent: a container whose children already end in a `Slot` is left as-is,
|
|
57
|
+
* so re-running (and filling, which inserts *before* the trailing slot) never
|
|
58
|
+
* stacks duplicates. Returns `spec` unchanged when there's nothing to add.
|
|
59
|
+
*/
|
|
60
|
+
function withContainerChildSlots(spec) {
|
|
61
|
+
const elements = spec.elements;
|
|
62
|
+
const targets = Object.keys(elements).filter((key) => {
|
|
63
|
+
const el = elements[key];
|
|
64
|
+
if (!el || !CONTAINER_TYPES.has(el.type ?? "")) return false;
|
|
65
|
+
const children = el.children ?? [];
|
|
66
|
+
return elements[children[children.length - 1] ?? ""]?.type !== SLOT_TYPE;
|
|
67
|
+
});
|
|
68
|
+
if (targets.length === 0) return spec;
|
|
69
|
+
const next = structuredClone(spec);
|
|
70
|
+
const nextEls = next.elements;
|
|
71
|
+
const used = new Set(Object.keys(nextEls));
|
|
72
|
+
for (const key of targets) {
|
|
73
|
+
let slotKey = `${key}__children__slot`;
|
|
74
|
+
let n = 0;
|
|
75
|
+
while (used.has(slotKey)) slotKey = `${key}__children__slot__${++n}`;
|
|
76
|
+
used.add(slotKey);
|
|
77
|
+
nextEls[slotKey] = {
|
|
78
|
+
type: SLOT_TYPE,
|
|
79
|
+
props: { name: "children" }
|
|
80
|
+
};
|
|
81
|
+
const el = nextEls[key];
|
|
82
|
+
el.children = [...el.children ?? [], slotKey];
|
|
83
|
+
}
|
|
84
|
+
return next;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Compose both slot injections into the canvas's render view: layer-bound node
|
|
88
|
+
* slots on a component instance's root (`withEmptyNodeSlots`, needs the
|
|
89
|
+
* component definition) plus a trailing insertion `Slot` in every container,
|
|
90
|
+
* tree-wide (`withContainerChildSlots`). This is the spec the studio canvas
|
|
91
|
+
* renders so empty slots show as drop targets — it is NEVER persisted. Stored
|
|
92
|
+
* specs stay slot-free; `stripInjectedSlots` is the inverse, applied at every
|
|
93
|
+
* serialization boundary (DB, clipboard, AI prompt). Both helpers return the
|
|
94
|
+
* same reference when there's nothing to add, so this is cheap and idempotent —
|
|
95
|
+
* re-running on an already-slotted spec adds nothing.
|
|
96
|
+
*/
|
|
97
|
+
function withRenderSlots(spec, component) {
|
|
98
|
+
return withContainerChildSlots(component ? withEmptyNodeSlots(spec, component) : spec);
|
|
99
|
+
}
|
|
100
|
+
function slotRefKeys(value) {
|
|
101
|
+
if (typeof value !== "object" || value === null || !("$slot" in value)) return;
|
|
102
|
+
const ref = value.$slot;
|
|
103
|
+
if (typeof ref === "string") return [ref];
|
|
104
|
+
return Array.isArray(ref) ? ref : void 0;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Inverse of `withEmptyNodeSlots` + `withContainerChildSlots`: drop every
|
|
108
|
+
* injected `Slot` element and scrub its references, so a spec carries no
|
|
109
|
+
* editing scaffolding. A `Slot`-typed element is ALWAYS an injected content
|
|
110
|
+
* hole (json-render's placeholder), never authored content — both injectors
|
|
111
|
+
* emit `type: 'Slot'` — so removing all of them and their references is the
|
|
112
|
+
* exact reversal: a trailing `children` Slot drops out of its parent's
|
|
113
|
+
* `children`, and an empty node slot drops both its `Slot` element and the
|
|
114
|
+
* `{ $slot }` prop that pointed at it (a FILLED slot points at a real element,
|
|
115
|
+
* which is not `Slot`-typed, so it survives). Use at export/serialization
|
|
116
|
+
* boundaries (e.g. clipboard); the canvas re-injects fresh drop targets on
|
|
117
|
+
* load. Idempotent: returns `spec` unchanged when there are no `Slot` elements.
|
|
118
|
+
*/
|
|
119
|
+
function stripInjectedSlots(spec) {
|
|
120
|
+
const elements = spec.elements;
|
|
121
|
+
const slotKeys = new Set(Object.keys(elements).filter((k) => elements[k]?.type === SLOT_TYPE));
|
|
122
|
+
if (slotKeys.size === 0) return spec;
|
|
123
|
+
const next = structuredClone(spec);
|
|
124
|
+
const nextEls = next.elements;
|
|
125
|
+
for (const key of slotKeys) delete nextEls[key];
|
|
126
|
+
for (const el of Object.values(nextEls)) {
|
|
127
|
+
if (!el) continue;
|
|
128
|
+
if (Array.isArray(el.children)) el.children = el.children.filter((c) => !slotKeys.has(c));
|
|
129
|
+
if (!el.props) continue;
|
|
130
|
+
for (const [propName, value] of Object.entries(el.props)) {
|
|
131
|
+
const refs = slotRefKeys(value);
|
|
132
|
+
if (!refs) continue;
|
|
133
|
+
const remaining = refs.filter((r) => !slotKeys.has(r));
|
|
134
|
+
if (remaining.length === 0) delete el.props[propName];
|
|
135
|
+
else if (remaining.length !== refs.length) el.props[propName] = { $slot: remaining };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return next;
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { stripInjectedSlots, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { applyForcedModifiers } from "./apply-forced-modifiers.js";
|
|
2
|
+
import { AssetComponentMap, AssetJsxForm, AssetNodeResolver, assetJsxForm, parseAssetType } from "./asset-jsx.js";
|
|
3
|
+
import { CollapseTextLabelsResult, CollapsedTextLabel, collapseWrappedTextLabels } from "./collapse-text-labels.js";
|
|
4
|
+
import { stripInjectedSlots, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots } from "./empty-node-slots.js";
|
|
5
|
+
import { JsxToSpecOptions, UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps } from "./jsxToSpec.js";
|
|
6
|
+
import { ResolvableComponent, resolveAuthoredLayerProps, resolveRenderedLayerProps } from "./layer-props.js";
|
|
7
|
+
import { PreviewControl, PreviewControlKind, derivePreviewControls, propOptions } from "./preview-controls.js";
|
|
8
|
+
import { collectSlotRefs, isSlotRef } from "./slot-refs.js";
|
|
9
|
+
import { SpecToJsxOptions, SpecToJsxResult, specToJsx } from "./specToJsx.js";
|
|
10
|
+
export { type AssetComponentMap, type AssetJsxForm, type AssetNodeResolver, type CollapseTextLabelsResult, type CollapsedTextLabel, type JsxToSpecOptions, type PreviewControl, type PreviewControlKind, type ResolvableComponent, type SpecToJsxOptions, type SpecToJsxResult, UNRESOLVED, applyForcedModifiers, assetJsxForm, collapseWrappedTextLabels, collectSlotRefs, derivePreviewControls, hasUnresolvedProps, isSlotRef, jsxToSpec, parseAssetType, propOptions, resolveAuthoredLayerProps, resolveRenderedLayerProps, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { collectSlotRefs, isSlotRef } from "./slot-refs.js";
|
|
2
|
+
import { applyForcedModifiers } from "./apply-forced-modifiers.js";
|
|
3
|
+
import { assetJsxForm, parseAssetType } from "./asset-jsx.js";
|
|
4
|
+
import { collapseWrappedTextLabels } from "./collapse-text-labels.js";
|
|
5
|
+
import { stripInjectedSlots, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots } from "./empty-node-slots.js";
|
|
6
|
+
import { UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps } from "./jsxToSpec.js";
|
|
7
|
+
import { resolveAuthoredLayerProps, resolveRenderedLayerProps } from "./layer-props.js";
|
|
8
|
+
import { derivePreviewControls, propOptions } from "./preview-controls.js";
|
|
9
|
+
import { specToJsx } from "./specToJsx.js";
|
|
10
|
+
export { UNRESOLVED, applyForcedModifiers, assetJsxForm, collapseWrappedTextLabels, collectSlotRefs, derivePreviewControls, hasUnresolvedProps, isSlotRef, jsxToSpec, parseAssetType, propOptions, resolveAuthoredLayerProps, resolveRenderedLayerProps, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
|