@yahoo/uds-create-config 2.44.0 → 3.0.0
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/README.md +129 -0
- package/dist/ai-lanes.d.ts +23 -0
- package/dist/ai-lanes.js +34 -0
- package/dist/authoring/define-component.d.ts +85 -0
- package/dist/configs/CanvasConfig.d.ts +3237 -0
- package/dist/configs/CanvasConfig.js +332 -0
- package/dist/configs/build-options.d.ts +10 -0
- package/dist/configs/build-options.js +68 -0
- package/dist/configs/platform.d.ts +15 -0
- package/dist/configs/platform.js +17 -0
- package/dist/configs/react-native-system.d.ts +3026 -0
- package/dist/configs/react-native-system.js +64 -0
- package/dist/configs/system.d.ts +2771 -0
- package/dist/configs/system.js +74 -0
- package/dist/css/properties.generated.d.ts +14 -0
- package/dist/css/properties.generated.js +6260 -0
- package/dist/css/value-type.d.ts +48 -0
- package/dist/css/value-type.js +131 -0
- package/dist/css/values.d.ts +33 -0
- package/dist/css/values.js +116 -0
- package/dist/entities/native/NativeModifier.d.ts +25 -0
- package/dist/entities/native/NativeModifier.js +41 -0
- package/dist/entities/native/NativeSettings.d.ts +44 -0
- package/dist/entities/native/NativeSettings.js +39 -0
- package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
- package/dist/entities/native/NativeStyleProperty.js +28 -0
- package/dist/entities/native/NativeToken.d.ts +31 -0
- package/dist/entities/native/NativeToken.js +49 -0
- package/dist/entities/system/CanvasRole.d.ts +34 -0
- package/dist/entities/system/CanvasRole.js +45 -0
- package/dist/entities/system/Component.d.ts +1287 -0
- package/dist/entities/system/Component.js +1840 -0
- package/dist/entities/system/Composite.d.ts +12 -0
- package/dist/entities/system/Composite.js +26 -0
- package/dist/entities/system/Device.d.ts +11 -0
- package/dist/entities/system/Device.js +18 -0
- package/dist/entities/system/File.d.ts +72 -0
- package/dist/entities/system/File.js +136 -0
- package/dist/entities/system/Font.d.ts +48 -0
- package/dist/entities/system/Font.js +56 -0
- package/dist/entities/system/GlobalStyle.d.ts +26 -0
- package/dist/entities/system/GlobalStyle.js +54 -0
- package/dist/entities/system/Guidance.d.ts +85 -0
- package/dist/entities/system/Guidance.js +59 -0
- package/dist/entities/system/GuidanceStyle.d.ts +14 -0
- package/dist/entities/system/GuidanceStyle.js +8 -0
- package/dist/entities/system/Icon.d.ts +46 -0
- package/dist/entities/system/Icon.js +46 -0
- package/dist/entities/system/LinkedSystem.d.ts +504 -0
- package/dist/entities/system/LinkedSystem.js +814 -0
- package/dist/entities/system/Modifier.d.ts +92 -0
- package/dist/entities/system/Modifier.js +120 -0
- package/dist/entities/system/Motion.d.ts +28 -0
- package/dist/entities/system/Motion.js +48 -0
- package/dist/entities/system/Operation.d.ts +100 -0
- package/dist/entities/system/Operation.js +236 -0
- package/dist/entities/system/Package.d.ts +42 -0
- package/dist/entities/system/Package.js +75 -0
- package/dist/entities/system/Settings.d.ts +94 -0
- package/dist/entities/system/Settings.js +166 -0
- package/dist/entities/system/StyleProperty.d.ts +135 -0
- package/dist/entities/system/StyleProperty.js +438 -0
- package/dist/entities/system/Token.d.ts +67 -0
- package/dist/entities/system/Token.js +129 -0
- package/dist/entities/system/Tool.d.ts +134 -0
- package/dist/entities/system/Tool.js +124 -0
- package/dist/entities/system/color.d.ts +64 -0
- package/dist/entities/system/color.js +123 -0
- package/dist/entities/system/component-module.d.ts +63 -0
- package/dist/entities/system/component-module.js +258 -0
- package/dist/entities/system/copy-plan.d.ts +98 -0
- package/dist/entities/system/copy-plan.js +451 -0
- package/dist/entities/system/defineComponent.d.ts +428 -0
- package/dist/entities/system/defineComponent.js +337 -0
- package/dist/entities/system/element.d.ts +101 -0
- package/dist/entities/system/element.js +171 -0
- package/dist/entities/system/icon-library.d.ts +64 -0
- package/dist/entities/system/icon-library.js +112 -0
- package/dist/entities/system/icon-metadata.d.ts +72 -0
- package/dist/entities/system/icon-metadata.js +111 -0
- package/dist/entities/system/link-declaration.d.ts +27 -0
- package/dist/entities/system/link-declaration.js +64 -0
- package/dist/entities/system/link-plan.d.ts +160 -0
- package/dist/entities/system/link-plan.js +770 -0
- package/dist/entities/system/runtime-modules.d.ts +25 -0
- package/dist/entities/system/runtime-modules.js +38 -0
- package/dist/entities/system/style-bag.d.ts +20 -0
- package/dist/entities/system/style-bag.js +246 -0
- package/dist/entities/system/token-index.d.ts +89 -0
- package/dist/entities/system/token-index.js +112 -0
- package/dist/framework/Config.d.ts +2472 -0
- package/dist/framework/Config.js +5023 -0
- package/dist/framework/Entity.d.ts +127 -0
- package/dist/framework/Entity.js +125 -0
- package/dist/framework/authoring.d.ts +24 -0
- package/dist/framework/authoring.js +7 -0
- package/dist/framework/change-hooks.d.ts +119 -0
- package/dist/framework/change-hooks.js +131 -0
- package/dist/framework/changes.d.ts +88 -0
- package/dist/framework/changes.js +246 -0
- package/dist/framework/class-names.d.ts +260 -0
- package/dist/framework/class-names.js +630 -0
- package/dist/framework/coalesce.d.ts +25 -0
- package/dist/framework/coalesce.js +60 -0
- package/dist/framework/config-op.d.ts +76 -0
- package/dist/framework/config-op.js +43 -0
- package/dist/framework/config-operation-kind.d.ts +14 -0
- package/dist/framework/config-operation-kind.js +14 -0
- package/dist/framework/config-ops.d.ts +34 -0
- package/dist/framework/config-ops.js +187 -0
- package/dist/framework/defineConfig.d.ts +196 -0
- package/dist/framework/defineConfig.js +100 -0
- package/dist/framework/defineDerivedEntity.d.ts +74 -0
- package/dist/framework/defineDerivedEntity.js +83 -0
- package/dist/framework/defineEntity.d.ts +318 -0
- package/dist/framework/defineEntity.js +183 -0
- package/dist/framework/defineSubEntity.d.ts +148 -0
- package/dist/framework/defineSubEntity.js +121 -0
- package/dist/framework/derived-mutations.d.ts +20 -0
- package/dist/framework/derived-mutations.js +38 -0
- package/dist/framework/entity-search.d.ts +29 -0
- package/dist/framework/entity-search.js +117 -0
- package/dist/framework/inline-sources.d.ts +49 -0
- package/dist/framework/inline-sources.js +388 -0
- package/dist/framework/layer-styles.d.ts +25 -0
- package/dist/framework/layer-styles.js +49 -0
- package/dist/framework/memo.d.ts +48 -0
- package/dist/framework/memo.js +84 -0
- package/dist/framework/overlay.d.ts +49 -0
- package/dist/framework/overlay.js +17 -0
- package/dist/framework/plan.d.ts +49 -0
- package/dist/framework/plan.js +73 -0
- package/dist/framework/projections.d.ts +480 -0
- package/dist/framework/projections.js +974 -0
- package/dist/framework/prop-surface.d.ts +132 -0
- package/dist/framework/prop-surface.js +278 -0
- package/dist/framework/ref-graph.d.ts +71 -0
- package/dist/framework/ref-graph.js +158 -0
- package/dist/framework/ref-integrity.d.ts +55 -0
- package/dist/framework/ref-integrity.js +171 -0
- package/dist/framework/registered.d.ts +95 -0
- package/dist/framework/registry-dir.d.ts +42 -0
- package/dist/framework/registry-dir.js +48 -0
- package/dist/framework/registry.d.ts +300 -0
- package/dist/framework/registry.js +104 -0
- package/dist/framework/rejection.d.ts +58 -0
- package/dist/framework/rejection.js +111 -0
- package/dist/framework/rename-inference.d.ts +26 -0
- package/dist/framework/rename-inference.js +50 -0
- package/dist/framework/render-spec.d.ts +296 -0
- package/dist/framework/render-spec.js +809 -0
- package/dist/framework/schema-version.d.ts +140 -0
- package/dist/framework/schema-version.js +214 -0
- package/dist/framework/schemas.d.ts +109 -0
- package/dist/framework/schemas.js +615 -0
- package/dist/framework/session.d.ts +196 -0
- package/dist/framework/session.js +367 -0
- package/dist/framework/signature.d.ts +15 -0
- package/dist/framework/signature.js +83 -0
- package/dist/framework/snapshot.d.ts +115 -0
- package/dist/framework/snapshot.js +277 -0
- package/dist/framework/source-integrity.d.ts +226 -0
- package/dist/framework/source-integrity.js +478 -0
- package/dist/framework/sources.d.ts +211 -0
- package/dist/framework/sources.js +89 -0
- package/dist/framework/utils/compiled-schema.d.ts +23 -0
- package/dist/framework/utils/compiled-schema.js +46 -0
- package/dist/framework/utils/content-key.d.ts +15 -0
- package/dist/framework/utils/content-key.js +33 -0
- package/dist/framework/utils/enumerated.d.ts +13 -0
- package/dist/framework/utils/enumerated.js +19 -0
- package/dist/framework/utils/field-path.d.ts +95 -0
- package/dist/framework/utils/field-path.js +136 -0
- package/dist/framework/utils/field-schema.d.ts +55 -0
- package/dist/framework/utils/field-schema.js +183 -0
- package/dist/framework/utils/group.d.ts +37 -0
- package/dist/framework/utils/group.js +13 -0
- package/dist/framework/utils/package-path.d.ts +37 -0
- package/dist/framework/utils/package-path.js +61 -0
- package/dist/framework/utils/refs.d.ts +194 -0
- package/dist/framework/utils/refs.js +403 -0
- package/dist/framework/validate-spec.d.ts +27 -0
- package/dist/framework/validate-spec.js +45 -0
- package/dist/framework/value-domain.d.ts +26 -0
- package/dist/framework/value-domain.js +202 -0
- package/dist/framework/views-facade.d.ts +15 -0
- package/dist/framework/views-facade.js +19 -0
- package/dist/index.d.ts +90 -42
- package/dist/index.js +86 -37
- package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
- package/dist/migrations/2.0.0/raw-css.js +72 -0
- package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
- package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
- package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
- package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
- package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
- package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.js +2 -0
- package/dist/react-native/style-keys.generated.d.ts +10 -0
- package/dist/react-native/style-keys.generated.js +167 -0
- package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
- package/dist/renderer/RendererErrorBoundary.js +59 -10
- package/dist/renderer/UdsRenderer.d.ts +11 -10
- package/dist/renderer/UdsRenderer.js +1 -1
- package/dist/renderer/assetEntries.d.ts +37 -0
- package/dist/renderer/assetEntries.js +39 -0
- package/dist/renderer/assetRenderable.d.ts +14 -6
- package/dist/renderer/assetRenderable.js +8 -2
- package/dist/renderer/componentEntry.d.ts +58 -0
- package/dist/renderer/componentEntry.js +71 -0
- package/dist/renderer/icon-library.d.ts +20 -0
- package/dist/renderer/index.d.ts +7 -7
- package/dist/renderer/index.js +5 -5
- package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
- package/dist/renderer/primitives/SlotRenderer.js +1 -1
- package/dist/renderer/runtimeComponent.d.ts +33 -0
- package/dist/renderer/runtimeComponent.js +113 -0
- package/dist/renderer/spec-content.d.ts +43 -0
- package/dist/renderer/spec-content.js +95 -0
- package/dist/renderer/wrapRegistry.d.ts +22 -37
- package/dist/renderer/wrapRegistry.js +10 -20
- package/dist/renderer/wrappers/event-bridge.js +6 -5
- package/dist/renderer/wrappers/hex-normalize.js +6 -5
- package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
- package/dist/renderer/wrappers/html-aliases.js +36 -19
- package/dist/renderer/wrappers/inline-styles.js +7 -6
- package/dist/spec/asset-jsx.d.ts +18 -5
- package/dist/spec/asset-jsx.js +27 -16
- package/dist/spec/collapse-text-labels.d.ts +5 -15
- package/dist/spec/collapse-text-labels.js +26 -19
- package/dist/spec/empty-node-slots.d.ts +56 -34
- package/dist/spec/empty-node-slots.js +87 -47
- package/dist/spec/index.d.ts +21 -10
- package/dist/spec/index.js +21 -10
- package/dist/spec/jsxToSpec.d.ts +14 -9
- package/dist/spec/jsxToSpec.js +20 -3
- package/dist/spec/preview-elements.d.ts +63 -0
- package/dist/spec/preview-elements.js +89 -0
- package/dist/spec/rewrite-refs.d.ts +58 -0
- package/dist/spec/rewrite-refs.js +250 -0
- package/dist/spec/specToJsx.js +18 -29
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -52
- package/dist/AssetGroup.d.ts +0 -77
- package/dist/AssetGroup.js +0 -125
- package/dist/Component.d.ts +0 -333
- package/dist/Component.js +0 -1061
- package/dist/ComponentGroup.d.ts +0 -22
- package/dist/ComponentGroup.js +0 -51
- package/dist/CompositeStyle.d.ts +0 -30
- package/dist/CompositeStyle.js +0 -59
- package/dist/Config.d.ts +0 -528
- package/dist/Config.js +0 -1712
- package/dist/Mode.d.ts +0 -41
- package/dist/Mode.js +0 -81
- package/dist/Modifier.d.ts +0 -51
- package/dist/Modifier.js +0 -97
- package/dist/MotionDef.d.ts +0 -81
- package/dist/MotionDef.js +0 -212
- package/dist/Props.d.ts +0 -332
- package/dist/Props.js +0 -35
- package/dist/Provider.d.ts +0 -20
- package/dist/Provider.js +0 -14
- package/dist/StyleProp.d.ts +0 -145
- package/dist/StyleProp.js +0 -239
- package/dist/Token.d.ts +0 -76
- package/dist/Token.js +0 -133
- package/dist/TokenGroup.d.ts +0 -33
- package/dist/TokenGroup.js +0 -69
- package/dist/asset-kind.d.ts +0 -55
- package/dist/asset-kind.js +0 -29
- package/dist/asset-value.d.ts +0 -23
- package/dist/asset-value.js +0 -40
- package/dist/brands.d.ts +0 -30
- package/dist/brands.js +0 -20
- package/dist/captureCallerPath.d.ts +0 -48
- package/dist/captureCallerPath.js +0 -95
- package/dist/colorExpressions.d.ts +0 -131
- package/dist/colorExpressions.js +0 -148
- package/dist/component-referrers.d.ts +0 -30
- package/dist/component-referrers.js +0 -40
- package/dist/config-diagnostics.d.ts +0 -21
- package/dist/config-diagnostics.js +0 -12
- package/dist/defineAssetGroup.d.ts +0 -200
- package/dist/defineAssetGroup.js +0 -323
- package/dist/defineProvider.d.ts +0 -29
- package/dist/defineProvider.js +0 -60
- package/dist/element-marker.d.ts +0 -63
- package/dist/element-marker.js +0 -113
- package/dist/entity-utils.d.ts +0 -56
- package/dist/entity-utils.js +0 -105
- package/dist/extension.d.ts +0 -55
- package/dist/extension.js +0 -214
- package/dist/factories.d.ts +0 -863
- package/dist/factories.js +0 -475
- package/dist/font-face.d.ts +0 -25
- package/dist/font-face.js +0 -72
- package/dist/foreign-component-name.d.ts +0 -21
- package/dist/foreign-component-name.js +0 -42
- package/dist/interpolate.d.ts +0 -20
- package/dist/interpolate.js +0 -10
- package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
- package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
- package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
- package/dist/jsx/jsx-dev-runtime.js +0 -11
- package/dist/jsx/jsx-runtime.d.ts +0 -48
- package/dist/jsx/jsx-runtime.js +0 -305
- package/dist/linked-system-pins.d.ts +0 -30
- package/dist/linked-system-pins.js +0 -45
- package/dist/linkedNodePrefixes.d.ts +0 -73
- package/dist/linkedNodePrefixes.js +0 -99
- package/dist/markers.d.ts +0 -235
- package/dist/markers.js +0 -70
- package/dist/motion-constants.d.ts +0 -37
- package/dist/motion-constants.js +0 -61
- package/dist/native/NativeConfig.d.ts +0 -56
- package/dist/native/NativeConfig.js +0 -162
- package/dist/native/assets.d.ts +0 -20
- package/dist/native/assets.js +0 -17
- package/dist/native/components.d.ts +0 -139
- package/dist/native/components.js +0 -67
- package/dist/native/index.d.ts +0 -18
- package/dist/native/index.js +0 -17
- package/dist/native/modes.d.ts +0 -10
- package/dist/native/modes.js +0 -11
- package/dist/native/types.d.ts +0 -95
- package/dist/native/types.js +0 -0
- package/dist/native/validation.d.ts +0 -8
- package/dist/native/validation.js +0 -885
- package/dist/native/values.d.ts +0 -7
- package/dist/native/values.js +0 -15
- package/dist/native.d.ts +0 -12
- package/dist/native.js +0 -10
- package/dist/refs.d.ts +0 -204
- package/dist/refs.js +0 -129
- package/dist/registry-aliases.d.ts +0 -33
- package/dist/registry-aliases.js +0 -35
- package/dist/registry-dir.d.ts +0 -22
- package/dist/registry-dir.js +0 -10
- package/dist/renderer/makeRegistry.d.ts +0 -34
- package/dist/renderer/makeRegistry.js +0 -52
- package/dist/renderer/makeUdsRenderer.d.ts +0 -13
- package/dist/renderer/makeUdsRenderer.js +0 -51
- package/dist/renderer/wrappers/component-slots.d.ts +0 -41
- package/dist/renderer/wrappers/component-slots.js +0 -66
- package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
- package/dist/renderer/wrappers/slot-resolution.js +0 -68
- package/dist/renderer/wrappers/void-elements.d.ts +0 -37
- package/dist/renderer/wrappers/void-elements.js +0 -40
- package/dist/spec/layer-props.d.ts +0 -52
- package/dist/spec/layer-props.js +0 -149
- package/dist/spec/preview-controls.d.ts +0 -44
- package/dist/spec/preview-controls.js +0 -139
- package/dist/spec/slot-refs.d.ts +0 -39
- package/dist/spec/slot-refs.js +0 -56
- package/dist/token-override-rows.d.ts +0 -68
- package/dist/token-override-rows.js +0 -233
- package/dist/tokenValueType.d.ts +0 -34
- package/dist/tokenValueType.js +0 -138
- package/dist/types/css-properties.d.ts +0 -233
- package/dist/types/css-properties.js +0 -14
- package/dist/types/css-property-keywords.d.ts +0 -156
- package/dist/types/css-property-keywords.js +0 -616
- package/dist/types/css-values.d.ts +0 -63
- package/dist/types/css-values.js +0 -16
- package/dist/types.d.ts +0 -1138
- package/dist/types.js +0 -12
- package/dist/units.d.ts +0 -14
- package/dist/units.js +0 -16
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.js +0 -4
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { isRef, kindOf, memberRef, pathOf } from "../../framework/utils/refs.js";
|
|
2
|
+
import { Component, canonicalWhen, layerRef } from "./Component.js";
|
|
3
|
+
//#region src/entities/system/defineComponent.ts
|
|
4
|
+
function build(body) {
|
|
5
|
+
const handle = (() => null);
|
|
6
|
+
const next = (patch) => build({
|
|
7
|
+
...body,
|
|
8
|
+
...patch
|
|
9
|
+
});
|
|
10
|
+
Object.assign(handle, {
|
|
11
|
+
kind: "component",
|
|
12
|
+
body,
|
|
13
|
+
path: void 0,
|
|
14
|
+
layers: (layers) => next({ layers }),
|
|
15
|
+
props: (props) => next({ props }),
|
|
16
|
+
styles: (rules) => next({ styles: rules }),
|
|
17
|
+
defaultProps: (defaults) => next({ defaultProps: defaults }),
|
|
18
|
+
forwards: (forwards) => next({ forwards }),
|
|
19
|
+
metadata: (meta) => next(meta),
|
|
20
|
+
render: () => handle,
|
|
21
|
+
renderCanvas: () => handle,
|
|
22
|
+
preview: (spec) => spec?.defaultProps === void 0 ? handle : next({ previewProps: spec.defaultProps }),
|
|
23
|
+
toStored: () => toStored(body),
|
|
24
|
+
assignPath(path) {
|
|
25
|
+
handle.path = path;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return handle;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The preview props a CONFIG can hold.
|
|
32
|
+
*
|
|
33
|
+
* A preview default is often authored as JSX (`icon: <PlusIcon/>`, `children: <><Box>Item 1</Box>…</>`),
|
|
34
|
+
* and a React element is not data: `$$typeof` is a symbol and `type` is a function, both of which
|
|
35
|
+
* `JSON.stringify` drops, so storing one yields `{ key, props, _owner, _store }` — React internals that
|
|
36
|
+
* will never revive and that no reader can tell from a real value.
|
|
37
|
+
*
|
|
38
|
+
* So an element is CONVERTED to the same `PreviewElement` shape the build stores — a thing to render
|
|
39
|
+
* and what to render it with — rather than dropped. Both producers then agree, which matters because
|
|
40
|
+
* only one of them runs for any given config: the build reads `.preview()` from source with ts-morph,
|
|
41
|
+
* this runs when a config is registered, and a reader can't tell which made the config it holds.
|
|
42
|
+
*
|
|
43
|
+
* What this path CANNOT do is name an element the source could. A tag is its own name and a component
|
|
44
|
+
* handle carries its adopted path, but a foreign function (a Phosphor glyph, say) is just a function
|
|
45
|
+
* at runtime — its `displayName` is a label, not an identity, and two libraries may both export
|
|
46
|
+
* `StarIcon`. Such a prop is DROPPED: an absent default renders nothing, while a guessed ref renders
|
|
47
|
+
* the wrong glyph and reads as authored. The build resolves those from the import specifier, which is
|
|
48
|
+
* why ~a third of the element-valued preview props in a real system only survive a build.
|
|
49
|
+
*/
|
|
50
|
+
function storableProps(props) {
|
|
51
|
+
if (props === void 0) return void 0;
|
|
52
|
+
const out = {};
|
|
53
|
+
for (const [key, value] of Object.entries(props)) {
|
|
54
|
+
const stored = storableValue(value);
|
|
55
|
+
if (stored !== void 0) out[key] = stored;
|
|
56
|
+
}
|
|
57
|
+
return Object.keys(out).length === 0 ? void 0 : out;
|
|
58
|
+
}
|
|
59
|
+
/** A live React element, by the marker anything pretending to be one also carries. */
|
|
60
|
+
function isReactElement(value) {
|
|
61
|
+
return typeof value === "object" && value !== null && "$$typeof" in value;
|
|
62
|
+
}
|
|
63
|
+
const FRAGMENT = Symbol.for("react.fragment");
|
|
64
|
+
/**
|
|
65
|
+
* What a runtime element renders, named the way a stored one names it — or `undefined` when this path
|
|
66
|
+
* can't say faithfully. See {@link storableProps}.
|
|
67
|
+
*/
|
|
68
|
+
function storableElementName(type) {
|
|
69
|
+
if (typeof type === "string") return type;
|
|
70
|
+
if (isComponentElement(type) && type.path) return Component.ref(type.path);
|
|
71
|
+
}
|
|
72
|
+
/** The scalar half of an element's props — what `PreviewElement.props` may hold. */
|
|
73
|
+
function storableAttributes(props) {
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const [key, value] of Object.entries(props)) {
|
|
76
|
+
if (key === "children") continue;
|
|
77
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out[key] = value;
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/** Children as a list, however one was written — a lone child isn't wrapped in an array. */
|
|
82
|
+
function childList(children) {
|
|
83
|
+
if (children === void 0 || children === null) return [];
|
|
84
|
+
return Array.isArray(children) ? children.flat(Number.POSITIVE_INFINITY) : [children];
|
|
85
|
+
}
|
|
86
|
+
/** One React element as the stored shape, or `undefined` when it can't be named. */
|
|
87
|
+
function storableElement(value) {
|
|
88
|
+
const element = storableElementName(value.type);
|
|
89
|
+
if (element === void 0) return void 0;
|
|
90
|
+
const props = {
|
|
91
|
+
...value.key !== null && value.key !== void 0 ? { key: String(value.key) } : {},
|
|
92
|
+
...storableAttributes(value.props ?? {})
|
|
93
|
+
};
|
|
94
|
+
const children = [];
|
|
95
|
+
let text;
|
|
96
|
+
for (const child of childList(value.props?.children)) {
|
|
97
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
98
|
+
const literal = String(child).trim();
|
|
99
|
+
if (literal) text = literal;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!isReactElement(child)) continue;
|
|
103
|
+
const nested = storableElement(child);
|
|
104
|
+
if (nested) children.push(nested);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
element,
|
|
108
|
+
...Object.keys(props).length > 0 ? { props } : {},
|
|
109
|
+
...children.length > 0 ? { children } : {},
|
|
110
|
+
...text !== void 0 ? { text } : {}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* One preview-prop value as the config stores it, or `undefined` to drop the prop.
|
|
115
|
+
*
|
|
116
|
+
* Mirrors the arms the build reads from source: a literal, an element, a fragment (several elements
|
|
117
|
+
* under one prop), an array, and a nested record.
|
|
118
|
+
*/
|
|
119
|
+
function storableValue(value) {
|
|
120
|
+
if (value === null) return null;
|
|
121
|
+
const type = typeof value;
|
|
122
|
+
if (type === "string" || type === "number" || type === "boolean") return value;
|
|
123
|
+
if (type !== "object") return void 0;
|
|
124
|
+
if (isReactElement(value)) {
|
|
125
|
+
if (value.type === FRAGMENT) {
|
|
126
|
+
const items = childList(value.props?.children).filter(isReactElement).map(storableElement).filter((item) => item !== void 0);
|
|
127
|
+
return items.length > 0 ? items : void 0;
|
|
128
|
+
}
|
|
129
|
+
return storableElement(value);
|
|
130
|
+
}
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
const items = value.map(storableValue).filter((item) => item !== void 0);
|
|
133
|
+
return items.length > 0 ? items : void 0;
|
|
134
|
+
}
|
|
135
|
+
const out = {};
|
|
136
|
+
for (const [key, member] of Object.entries(value)) {
|
|
137
|
+
const stored = storableValue(member);
|
|
138
|
+
if (stored !== void 0) out[key] = stored;
|
|
139
|
+
}
|
|
140
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* One prop declaration as the config stores it — the tagged union, with the tag DERIVED from what a
|
|
144
|
+
* bare form already says.
|
|
145
|
+
*
|
|
146
|
+
* Two kinds mean something particular as a prop: a style property writes CSS through it, and a
|
|
147
|
+
* composite applies a whole bag. Anything else a ref can name is a set of VALUES, which is what a
|
|
148
|
+
* variant is — an icon library, most often, so `name: Icon.ref('phosphor')` is a variant over its
|
|
149
|
+
* glyphs without copying 1,530 names into the component that renders them.
|
|
150
|
+
*/
|
|
151
|
+
function storedProp(decl, layers) {
|
|
152
|
+
if (Array.isArray(decl)) return {
|
|
153
|
+
type: "variant",
|
|
154
|
+
value: decl
|
|
155
|
+
};
|
|
156
|
+
if (isAuthoredForward(decl)) return storedForward(decl, layers);
|
|
157
|
+
if (!isRef(decl)) return decl;
|
|
158
|
+
const kind = kindOf(decl);
|
|
159
|
+
if (kind === "style-property") return {
|
|
160
|
+
type: "styleProperty",
|
|
161
|
+
value: decl
|
|
162
|
+
};
|
|
163
|
+
if (kind === "composite") return {
|
|
164
|
+
type: "composite",
|
|
165
|
+
value: decl
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
type: "variant",
|
|
169
|
+
value: decl
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A route whose far end is still a NAME — either half of the authored form.
|
|
174
|
+
*
|
|
175
|
+
* `target: 'input/disabled'` is what a config file writes; `into: 'disabled'` beside a layer ref is
|
|
176
|
+
* what the schema's split leaves. Both are the same declaration one step from storage, and both need
|
|
177
|
+
* the member ref this builder is about to mint. A body read back from the config already spells it and
|
|
178
|
+
* is left alone.
|
|
179
|
+
*
|
|
180
|
+
* `toStored` runs BEFORE the schema, so the path form is what actually arrives here — testing only for
|
|
181
|
+
* a string `into` meant nothing matched and the ref was never minted.
|
|
182
|
+
*/
|
|
183
|
+
function isAuthoredForward(decl) {
|
|
184
|
+
if (typeof decl !== "object" || decl === null || decl.type !== "forward") return false;
|
|
185
|
+
const { target, into } = decl;
|
|
186
|
+
return typeof target === "string" || typeof into === "string";
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* A `bind()` declaration with its `into` resolved to a member ref at the target layer's element.
|
|
190
|
+
*
|
|
191
|
+
* Left as authored when the layer's element is a tag or an unadopted handle: a tag's props are the
|
|
192
|
+
* DOM's and have no entity to point into, and minting a ref against an empty path would produce
|
|
193
|
+
* `component:#props/x`, which resolves to nothing and reads as authored. The schema refuses a
|
|
194
|
+
* non-ref `into`, so the failure is loud at registration rather than silent in the data.
|
|
195
|
+
*/
|
|
196
|
+
function storedForward(decl, layers) {
|
|
197
|
+
return storedRoutedForward(typeof decl.target === "string" ? {
|
|
198
|
+
...decl,
|
|
199
|
+
target: layerRef(decl.target.slice(0, decl.target.indexOf("/"))),
|
|
200
|
+
into: decl.target.slice(decl.target.indexOf("/") + 1)
|
|
201
|
+
} : {
|
|
202
|
+
...decl,
|
|
203
|
+
target: decl.target,
|
|
204
|
+
into: decl.into ?? "children"
|
|
205
|
+
}, layers);
|
|
206
|
+
}
|
|
207
|
+
function storedRoutedForward(decl, layers) {
|
|
208
|
+
const layer = pathOf(decl.target);
|
|
209
|
+
const element = layers?.[layer];
|
|
210
|
+
const path = isComponentElement(element) ? element.path : isRef(element) ? pathOf(element) : void 0;
|
|
211
|
+
if (!path) return decl;
|
|
212
|
+
const declaring = declaringPath(element, decl.into) ?? path;
|
|
213
|
+
return {
|
|
214
|
+
...decl,
|
|
215
|
+
into: memberRef("component", declaring, "props", decl.into)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/** The prop name a forwarding entry identifies, whichever spelling it is in — authored names have not
|
|
219
|
+
* become member refs yet at this point, and a re-authored body may hold either. */
|
|
220
|
+
function forwardedName(entry) {
|
|
221
|
+
if (typeof entry === "string") return entry;
|
|
222
|
+
if (isRef(entry)) return pathOf(entry).split("/").pop();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Which component in the layer chain actually DECLARES `prop` — the one a member ref can point into.
|
|
226
|
+
*
|
|
227
|
+
* A forwarded prop has no declaration on the component that exposes it, so the walk follows
|
|
228
|
+
* `forwards` into the layer that supplies it and asks the same question there. `seen` guards a cycle:
|
|
229
|
+
* the chain is authored data, so nothing stops a config from describing one.
|
|
230
|
+
*/
|
|
231
|
+
function declaringPath(element, prop, seen = /* @__PURE__ */ new Set()) {
|
|
232
|
+
if (!isComponentElement(element) || seen.has(element)) return void 0;
|
|
233
|
+
const body = element.body;
|
|
234
|
+
if (!body) return void 0;
|
|
235
|
+
const props = body.props;
|
|
236
|
+
if (props && prop in props) return props[prop] === null ? void 0 : element.path;
|
|
237
|
+
const forwards = body.forwards;
|
|
238
|
+
if (!forwards) return void 0;
|
|
239
|
+
const next = new Set(seen).add(element);
|
|
240
|
+
const layers = body.layers;
|
|
241
|
+
for (const [layer, entry] of Object.entries(forwards)) {
|
|
242
|
+
if (!(entry === "*" || Array.isArray(entry) && entry.some((one) => forwardedName(one) === prop))) continue;
|
|
243
|
+
const found = declaringPath(layers?.[layer], prop, next);
|
|
244
|
+
if (found) return found;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** Whether a layer's element is another component's handle rather than a tag or a ref. */
|
|
248
|
+
function isComponentElement(value) {
|
|
249
|
+
return typeof value === "function" && value.kind === "component";
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A `forwards` record with each narrowing list's prop NAMES resolved to member refs — the same step
|
|
253
|
+
* {@link storedForward} performs, for the same reason and at the same moment.
|
|
254
|
+
*
|
|
255
|
+
* Each ref names the component that DECLARES the prop, which is not always the layer's own element:
|
|
256
|
+
* `Button` forwarding `width` from a `Pressable` root names `Box`, since `Pressable` only forwards it
|
|
257
|
+
* on from there. A ref at `Pressable` would resolve to nothing, and the build refuses a config that
|
|
258
|
+
* spells one. The element's own path is the fallback when nothing in the chain declares the name.
|
|
259
|
+
*
|
|
260
|
+
* `'*'` passes through: it names nothing, so it has no ref to mint and cannot rot on a rename. A list
|
|
261
|
+
* against a tag or an unadopted handle is left as authored, so the schema's refusal is loud at
|
|
262
|
+
* registration rather than silent in the data.
|
|
263
|
+
*/
|
|
264
|
+
function storedForwards(forwards, layers) {
|
|
265
|
+
const out = {};
|
|
266
|
+
for (const [layer, entry] of Object.entries(forwards)) {
|
|
267
|
+
if (!Array.isArray(entry)) {
|
|
268
|
+
out[layer] = entry;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const element = layers?.[layer];
|
|
272
|
+
const path = isComponentElement(element) ? element.path : isRef(element) ? pathOf(element) : void 0;
|
|
273
|
+
out[layer] = path ? entry.map((name) => typeof name === "string" ? memberRef("component", declaringPath(element, name) ?? path, "props", name) : name) : entry;
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
/** The authored body as the entity's stored shape — which differs in exactly four places. */
|
|
278
|
+
function toStored(body) {
|
|
279
|
+
const stored = { ...body };
|
|
280
|
+
if (body.previewProps !== void 0) {
|
|
281
|
+
const previewProps = storableProps(body.previewProps);
|
|
282
|
+
if (previewProps === void 0) delete stored.previewProps;
|
|
283
|
+
else stored.previewProps = previewProps;
|
|
284
|
+
}
|
|
285
|
+
if (body.props && typeof body.props === "object") {
|
|
286
|
+
const props = {};
|
|
287
|
+
for (const [name, decl] of Object.entries(body.props)) props[name] = storedProp(decl, body.layers);
|
|
288
|
+
stored.props = props;
|
|
289
|
+
}
|
|
290
|
+
if (body.layers && typeof body.layers === "object") {
|
|
291
|
+
const layers = {};
|
|
292
|
+
for (const [name, element] of Object.entries(body.layers)) layers[name] = isComponentElement(element) ? Component.ref(element.path ?? "") : element;
|
|
293
|
+
stored.layers = layers;
|
|
294
|
+
}
|
|
295
|
+
if (body.forwards && typeof body.forwards === "object") stored.forwards = storedForwards(body.forwards, body.layers);
|
|
296
|
+
const rules = body.styles;
|
|
297
|
+
if (!Array.isArray(rules)) return stored;
|
|
298
|
+
const styles = {};
|
|
299
|
+
for (const rule of rules) styles[canonicalWhen(rule.when)] = {
|
|
300
|
+
when: rule.when ?? null,
|
|
301
|
+
layers: rule.layers
|
|
302
|
+
};
|
|
303
|
+
return {
|
|
304
|
+
...stored,
|
|
305
|
+
styles
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Author a component.
|
|
310
|
+
*
|
|
311
|
+
* Callable for the case with nothing to narrow — `defineComponent({ layers: { root: 'div' } })` — and
|
|
312
|
+
* chainable for every other, since a chain is what lets each step's types come from the last.
|
|
313
|
+
*/
|
|
314
|
+
/**
|
|
315
|
+
* Author a component.
|
|
316
|
+
*
|
|
317
|
+
* Called with an ELEMENT — `defineComponent('input')`, `defineComponent(Component.ref('Box'))` — that
|
|
318
|
+
* element becomes the root layer, because a component with one layer IS that element and saying so
|
|
319
|
+
* twice adds nothing. It's also what makes the element's props type correctly: v1 expressed this as a
|
|
320
|
+
* `defaultProps: { as: 'input' }` on a `div`-rooted component, which left the config claiming the
|
|
321
|
+
* element was a `div` while every call site treated it as an input.
|
|
322
|
+
*
|
|
323
|
+
* The render follows from it too — one layer needs no anatomy, so the build generates the element
|
|
324
|
+
* rather than reading a `.render()` that would only restate the layer.
|
|
325
|
+
*/
|
|
326
|
+
function defineComponentImpl(bodyOrElement) {
|
|
327
|
+
if (isComponentElement(bodyOrElement)) return build({ layers: { root: bodyOrElement } });
|
|
328
|
+
if (typeof bodyOrElement === "function" || isRef(bodyOrElement) && kindOf(bodyOrElement) === "package") throw new Error("[uds] defineComponent(<package export>): a package export cannot be a component's only layer yet — the generated one-layer render emits web elements. Declare `layers` and a `.render()` instead.");
|
|
329
|
+
if (typeof bodyOrElement === "string" || isRef(bodyOrElement)) return build({ layers: { root: bodyOrElement } });
|
|
330
|
+
return build(bodyOrElement ?? {});
|
|
331
|
+
}
|
|
332
|
+
const defineComponent = Object.assign(defineComponentImpl, {
|
|
333
|
+
layers: (layers) => build({}).layers(layers),
|
|
334
|
+
props: (props) => build({}).props(props)
|
|
335
|
+
});
|
|
336
|
+
//#endregion
|
|
337
|
+
export { defineComponent };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Config } from "../../framework/Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/entities/system/element.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A component's forwarded layers, as `{ [layer]: '*' | Ref[] }` — the ONE reader of the field.
|
|
6
|
+
*
|
|
7
|
+
* A field read directly is a field that has to be found again when its shape changes; there were six
|
|
8
|
+
* such callers once, and three read it raw.
|
|
9
|
+
*
|
|
10
|
+
* It used to fall back to `inherits`, the pre-migration spelling, read as `{ [layer]: '*' }`. That
|
|
11
|
+
* reader is gone: `v1-artifact` folds a v1 config straight to `forwards`, so nothing mints the old
|
|
12
|
+
* field, and a stored config still carrying it now forwards nothing rather than being quietly
|
|
13
|
+
* translated. Deliberate — one name for one concept beats two where the second is invisible.
|
|
14
|
+
*/
|
|
15
|
+
declare function forwardsOf(body: {
|
|
16
|
+
forwards?: Record<string, unknown> | undefined;
|
|
17
|
+
}): Record<string, unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* A component's root layer — where every prop the config doesn't model is sent.
|
|
20
|
+
*
|
|
21
|
+
* The schema REQUIRES a layer called `root` (see `Component`'s `layers`), so the fallback below is for
|
|
22
|
+
* malformed data only: a per-member `sub-delete` doesn't re-validate its owner, so this answers
|
|
23
|
+
* defensively rather than assuming. It is not a way to have a differently-named root.
|
|
24
|
+
*/
|
|
25
|
+
declare function rootLayerOf(layers: Record<string, unknown>): [name: string, element: unknown];
|
|
26
|
+
/**
|
|
27
|
+
* What a component renders, as the two things React's element type can be.
|
|
28
|
+
*
|
|
29
|
+
* A `tag` is already an element type — `'div'`, `'input'` — and needs no lookup. A `ref` is a
|
|
30
|
+
* package export (`package:reactNative/Pressable`), which is what a native layer always is, and
|
|
31
|
+
* reaching it means generating its import. Only the emitter that generates imports can do that, so
|
|
32
|
+
* this hands back the ref rather than resolving it.
|
|
33
|
+
*/
|
|
34
|
+
type RenderedTarget = {
|
|
35
|
+
readonly kind: 'tag';
|
|
36
|
+
readonly tag: string;
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: 'ref';
|
|
39
|
+
readonly ref: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The element `path` renders, following component roots until something concrete turns up.
|
|
43
|
+
*
|
|
44
|
+
* `div` when nothing resolves — a component whose root is a dangling ref still has to render as
|
|
45
|
+
* something, and the neutral container is the answer that breaks the least.
|
|
46
|
+
*/
|
|
47
|
+
declare function renderedTarget(config: Config, path: string, seen?: Set<string>): RenderedTarget;
|
|
48
|
+
/**
|
|
49
|
+
* The TAG `path` renders — the web half of {@link renderedTarget}, where a package export has no
|
|
50
|
+
* tag to be and the neutral container stands in.
|
|
51
|
+
*
|
|
52
|
+
* Expressed over the same walk rather than repeating it: two walks that answer "what does this
|
|
53
|
+
* render" can disagree about a pinned `as` or a component root, and only one of them is consulted
|
|
54
|
+
* by the module that ships.
|
|
55
|
+
*/
|
|
56
|
+
declare function renderedElement(config: Config, path: string, seen?: Set<string>): string;
|
|
57
|
+
/**
|
|
58
|
+
* Elements that may not be given children — React throws when one is.
|
|
59
|
+
*
|
|
60
|
+
* The list is HTML's, not the config's: whether `<input>` takes children is a fact about the DOM, and
|
|
61
|
+
* a design system has no say in it.
|
|
62
|
+
*/
|
|
63
|
+
declare const VOID_ELEMENTS: ReadonlySet<string>;
|
|
64
|
+
/**
|
|
65
|
+
* What a component may be given as children — the ONE answer to a question v1 asks as two
|
|
66
|
+
* complementary name lists, and gets subtly wrong at the edges.
|
|
67
|
+
*
|
|
68
|
+
* Two facts decide it, and neither implies the other:
|
|
69
|
+
*
|
|
70
|
+
* - the ELEMENT it renders. A void one takes no children; React throws if it's given any. `as` is
|
|
71
|
+
* part of this, which is what v1's `voidComponents` misses — `Input` is `div`-layered and an
|
|
72
|
+
* `<input>`, so a leaked child forwards onto a void element and throws (UDS-2907).
|
|
73
|
+
* - what the COMPONENT declares. One with no `children` slot has nowhere to put them, whatever its
|
|
74
|
+
* element would allow — a `div`-rooted form control is the case that lands here and nowhere else.
|
|
75
|
+
*
|
|
76
|
+
* `text` is the third answer, not a special case of `nodes`: a slot marked `text` takes a string,
|
|
77
|
+
* so a picker offers a text field rather than a node well.
|
|
78
|
+
*/
|
|
79
|
+
type ChildrenPolicy = 'none' | 'text' | 'nodes';
|
|
80
|
+
declare function childrenPolicy(config: Config, path: string): ChildrenPolicy;
|
|
81
|
+
/**
|
|
82
|
+
* The component one is a PART of — `Card/Header` is part of `Card`.
|
|
83
|
+
*
|
|
84
|
+
* A part is not a new relationship needing a new field: in this model identity IS the path, so a
|
|
85
|
+
* component nested under another is nested by being named that way, exactly as `color/brand` is a
|
|
86
|
+
* token in `color` and `phosphor/StarIcon` is a glyph in `phosphor`. Storing the edge as well would
|
|
87
|
+
* be the same fact in two places, and the two could disagree the moment either moved.
|
|
88
|
+
*
|
|
89
|
+
* `undefined` when the path names no owner (a component in a plain group, or a top-level one) — which
|
|
90
|
+
* is also the test for "offer this in a palette", since a part is reached through the thing it belongs
|
|
91
|
+
* to rather than listed beside it.
|
|
92
|
+
*/
|
|
93
|
+
declare function ownerOf(config: Config, path: string): string | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* The components that are parts of this one, in registration order.
|
|
96
|
+
*
|
|
97
|
+
* Direct parts only: `Card/Header/Title` is a part of `Card/Header`, which is what the path says.
|
|
98
|
+
*/
|
|
99
|
+
declare function partsOf(config: Config, path: string): string[];
|
|
100
|
+
//#endregion
|
|
101
|
+
export { ChildrenPolicy, RenderedTarget, VOID_ELEMENTS, childrenPolicy, forwardsOf, ownerOf, partsOf, renderedElement, renderedTarget, rootLayerOf };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { memberOf, splitRef } from "../../framework/utils/refs.js";
|
|
2
|
+
//#region src/entities/system/element.ts
|
|
3
|
+
/** The path a value points at when it's a ref to a component, else `undefined`. */
|
|
4
|
+
function componentPathOf(value) {
|
|
5
|
+
const marker = value?.__ref;
|
|
6
|
+
if (typeof marker !== "string") return void 0;
|
|
7
|
+
const { kind, qualifiedPath } = splitRef(marker);
|
|
8
|
+
return kind === "component" && qualifiedPath !== marker ? qualifiedPath : void 0;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A component's forwarded layers, as `{ [layer]: '*' | Ref[] }` — the ONE reader of the field.
|
|
12
|
+
*
|
|
13
|
+
* A field read directly is a field that has to be found again when its shape changes; there were six
|
|
14
|
+
* such callers once, and three read it raw.
|
|
15
|
+
*
|
|
16
|
+
* It used to fall back to `inherits`, the pre-migration spelling, read as `{ [layer]: '*' }`. That
|
|
17
|
+
* reader is gone: `v1-artifact` folds a v1 config straight to `forwards`, so nothing mints the old
|
|
18
|
+
* field, and a stored config still carrying it now forwards nothing rather than being quietly
|
|
19
|
+
* translated. Deliberate — one name for one concept beats two where the second is invisible.
|
|
20
|
+
*/
|
|
21
|
+
function forwardsOf(body) {
|
|
22
|
+
return body.forwards ?? {};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A component's root layer — where every prop the config doesn't model is sent.
|
|
26
|
+
*
|
|
27
|
+
* The schema REQUIRES a layer called `root` (see `Component`'s `layers`), so the fallback below is for
|
|
28
|
+
* malformed data only: a per-member `sub-delete` doesn't re-validate its owner, so this answers
|
|
29
|
+
* defensively rather than assuming. It is not a way to have a differently-named root.
|
|
30
|
+
*/
|
|
31
|
+
function rootLayerOf(layers) {
|
|
32
|
+
if ("root" in layers) return ["root", layers.root];
|
|
33
|
+
const [name = "root", element] = Object.entries(layers)[0] ?? [];
|
|
34
|
+
return [name, element];
|
|
35
|
+
}
|
|
36
|
+
/** The ref a value points at when it's a package export used as an element, else `undefined`. */
|
|
37
|
+
function packageRefOf(value) {
|
|
38
|
+
const marker = value?.__ref;
|
|
39
|
+
if (typeof marker !== "string") return void 0;
|
|
40
|
+
const { kind, qualifiedPath } = splitRef(marker);
|
|
41
|
+
return kind === "package" && qualifiedPath !== marker ? marker : void 0;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The element `path` renders, following component roots until something concrete turns up.
|
|
45
|
+
*
|
|
46
|
+
* `div` when nothing resolves — a component whose root is a dangling ref still has to render as
|
|
47
|
+
* something, and the neutral container is the answer that breaks the least.
|
|
48
|
+
*/
|
|
49
|
+
function renderedTarget(config, path, seen = /* @__PURE__ */ new Set()) {
|
|
50
|
+
const fallback = {
|
|
51
|
+
kind: "tag",
|
|
52
|
+
tag: "div"
|
|
53
|
+
};
|
|
54
|
+
if (seen.has(path)) return fallback;
|
|
55
|
+
seen.add(path);
|
|
56
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
57
|
+
if (!body) return fallback;
|
|
58
|
+
const pinned = body.defaultProps?.as;
|
|
59
|
+
if (typeof pinned === "string") return {
|
|
60
|
+
kind: "tag",
|
|
61
|
+
tag: pinned
|
|
62
|
+
};
|
|
63
|
+
const [, element] = rootLayerOf(body.layers ?? {});
|
|
64
|
+
if (typeof element === "string") return {
|
|
65
|
+
kind: "tag",
|
|
66
|
+
tag: element
|
|
67
|
+
};
|
|
68
|
+
const packageRef = packageRefOf(element);
|
|
69
|
+
if (packageRef) return {
|
|
70
|
+
kind: "ref",
|
|
71
|
+
ref: packageRef
|
|
72
|
+
};
|
|
73
|
+
const target = componentPathOf(element);
|
|
74
|
+
return target ? renderedTarget(config, target, seen) : fallback;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The TAG `path` renders — the web half of {@link renderedTarget}, where a package export has no
|
|
78
|
+
* tag to be and the neutral container stands in.
|
|
79
|
+
*
|
|
80
|
+
* Expressed over the same walk rather than repeating it: two walks that answer "what does this
|
|
81
|
+
* render" can disagree about a pinned `as` or a component root, and only one of them is consulted
|
|
82
|
+
* by the module that ships.
|
|
83
|
+
*/
|
|
84
|
+
function renderedElement(config, path, seen = /* @__PURE__ */ new Set()) {
|
|
85
|
+
const target = renderedTarget(config, path, seen);
|
|
86
|
+
return target.kind === "tag" ? target.tag : "div";
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Elements that may not be given children — React throws when one is.
|
|
90
|
+
*
|
|
91
|
+
* The list is HTML's, not the config's: whether `<input>` takes children is a fact about the DOM, and
|
|
92
|
+
* a design system has no say in it.
|
|
93
|
+
*/
|
|
94
|
+
const VOID_ELEMENTS = new Set([
|
|
95
|
+
"area",
|
|
96
|
+
"base",
|
|
97
|
+
"br",
|
|
98
|
+
"col",
|
|
99
|
+
"embed",
|
|
100
|
+
"hr",
|
|
101
|
+
"img",
|
|
102
|
+
"input",
|
|
103
|
+
"link",
|
|
104
|
+
"meta",
|
|
105
|
+
"param",
|
|
106
|
+
"source",
|
|
107
|
+
"track",
|
|
108
|
+
"wbr"
|
|
109
|
+
]);
|
|
110
|
+
function childrenPolicy(config, path) {
|
|
111
|
+
if (VOID_ELEMENTS.has(renderedElement(config, path))) return "none";
|
|
112
|
+
const slot = childrenSlot(config, path);
|
|
113
|
+
if (slot === void 0) return "none";
|
|
114
|
+
return slot?.text ? "text" : "nodes";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The `children` slot a component exposes — its own, or the one it inherits from the layer it's
|
|
118
|
+
* built on. `undefined` when it has none.
|
|
119
|
+
*
|
|
120
|
+
* A DECLARED `null` is the omit tombstone: a component drops an inherited slot that way, so a
|
|
121
|
+
* present key is not the same as an accepted slot.
|
|
122
|
+
*/
|
|
123
|
+
function childrenSlot(config, path, seen = /* @__PURE__ */ new Set()) {
|
|
124
|
+
if (seen.has(path)) return void 0;
|
|
125
|
+
seen.add(path);
|
|
126
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
127
|
+
if (!body) return void 0;
|
|
128
|
+
const declared = body.props?.children;
|
|
129
|
+
if (declared !== void 0) return declared === null ? void 0 : declared;
|
|
130
|
+
for (const [layer, entry] of Object.entries(forwardsOf(body))) {
|
|
131
|
+
if (Array.isArray(entry) && !entry.some((r) => namesChildren(r))) continue;
|
|
132
|
+
const target = componentPathOf(body.layers?.[layer]);
|
|
133
|
+
if (!target) continue;
|
|
134
|
+
const slot = childrenSlot(config, target, seen);
|
|
135
|
+
if (slot !== void 0) return slot;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Whether a forwarded member ref names a `children` prop. */
|
|
139
|
+
function namesChildren(entry) {
|
|
140
|
+
const marker = entry?.__ref;
|
|
141
|
+
if (typeof marker !== "string") return false;
|
|
142
|
+
return memberOf(marker)?.endsWith("/children") ?? false;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The component one is a PART of — `Card/Header` is part of `Card`.
|
|
146
|
+
*
|
|
147
|
+
* A part is not a new relationship needing a new field: in this model identity IS the path, so a
|
|
148
|
+
* component nested under another is nested by being named that way, exactly as `color/brand` is a
|
|
149
|
+
* token in `color` and `phosphor/StarIcon` is a glyph in `phosphor`. Storing the edge as well would
|
|
150
|
+
* be the same fact in two places, and the two could disagree the moment either moved.
|
|
151
|
+
*
|
|
152
|
+
* `undefined` when the path names no owner (a component in a plain group, or a top-level one) — which
|
|
153
|
+
* is also the test for "offer this in a palette", since a part is reached through the thing it belongs
|
|
154
|
+
* to rather than listed beside it.
|
|
155
|
+
*/
|
|
156
|
+
function ownerOf(config, path) {
|
|
157
|
+
const slash = path.lastIndexOf("/");
|
|
158
|
+
if (slash === -1) return void 0;
|
|
159
|
+
const owner = path.slice(0, slash);
|
|
160
|
+
return config.resolve("component", owner) ? owner : void 0;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The components that are parts of this one, in registration order.
|
|
164
|
+
*
|
|
165
|
+
* Direct parts only: `Card/Header/Title` is a part of `Card/Header`, which is what the path says.
|
|
166
|
+
*/
|
|
167
|
+
function partsOf(config, path) {
|
|
168
|
+
return config.list("component").filter((item) => ownerOf(config, item.path) === path).map((item) => item.path);
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
export { VOID_ELEMENTS, childrenPolicy, forwardsOf, ownerOf, partsOf, renderedElement, renderedTarget, rootLayerOf };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Config } from "../../framework/Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/entities/system/icon-library.d.ts
|
|
4
|
+
/** An icon library, as its group node describes it. */
|
|
5
|
+
interface IconLibrary {
|
|
6
|
+
/** The group path — the `slug` half of a placed glyph's type. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
/** The glyphs it ships, by leaf name. */
|
|
9
|
+
readonly members: readonly string[];
|
|
10
|
+
/** Named sizes (`sm: 16`). */
|
|
11
|
+
readonly sizes: Readonly<Record<string, number>>;
|
|
12
|
+
/** Weights/styles the set ships. */
|
|
13
|
+
readonly variants: readonly string[];
|
|
14
|
+
/** The component a placed glyph renders through, if the set declares one. */
|
|
15
|
+
readonly component?: string;
|
|
16
|
+
/** The npm module that supplies the library's glyph implementations. */
|
|
17
|
+
readonly module?: string;
|
|
18
|
+
/** The version of the package the glyphs come from, when the set pins one —
|
|
19
|
+
* what an assets index shows beside the library's name. */
|
|
20
|
+
readonly version?: string;
|
|
21
|
+
/** The variant the bound component declares in its `defaultProps` — what a
|
|
22
|
+
* picker seeds when nothing is stored. Passed through as DECLARED; a policy
|
|
23
|
+
* read validates against {@link variants} before trusting it. */
|
|
24
|
+
readonly defaultVariant?: string;
|
|
25
|
+
/** The size bucket the bound component declares in its `defaultProps`.
|
|
26
|
+
* Same contract as {@link defaultVariant}: declared, not validated. */
|
|
27
|
+
readonly defaultSizeKey?: string;
|
|
28
|
+
}
|
|
29
|
+
/** The spec `type` a placed glyph of this library carries — its own ref. */
|
|
30
|
+
declare function assetType(library: IconLibrary, member: string): string;
|
|
31
|
+
/** One library by its group path — `undefined` when the config has no such set. */
|
|
32
|
+
declare function iconLibrary(config: Config | null | undefined, path: string): IconLibrary | undefined;
|
|
33
|
+
/** Every icon library the config declares. */
|
|
34
|
+
declare function iconLibraries(config: Config | null | undefined): IconLibrary[];
|
|
35
|
+
/**
|
|
36
|
+
* The library a surface should show: the hinted one when a caller carries a slug (a slot's
|
|
37
|
+
* `accepts` ref, a stored fill), else the first library that actually has members. One home for
|
|
38
|
+
* that policy — the toolbar, placement, and the panel all resolve through here, so no surface
|
|
39
|
+
* carries its own idea of a default set. A hint that names no library resolves to `undefined`
|
|
40
|
+
* rather than falling back: the caller knows whether a stale slug should show empty or pick anew.
|
|
41
|
+
*/
|
|
42
|
+
declare function resolveIconLibrary(config: Config | null | undefined, hint?: string): IconLibrary | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Every category the library's members carry, RAW as stored (lowercase, unsorted within a member,
|
|
45
|
+
* plural per member), deduplicated and sorted for a filter menu. Casing is display policy — a
|
|
46
|
+
* surface title-cases for headings; values compare and filter by the stored form.
|
|
47
|
+
*/
|
|
48
|
+
declare function iconCategories(config: Config | null | undefined, libraryPath: string): readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* The variants a placed glyph may take.
|
|
51
|
+
*
|
|
52
|
+
* The whole library's variants: nothing in the model describes one glyph's own set yet
|
|
53
|
+
* (config-v2 model gap 8 — per-item `variants` narrowing). So a set that ships a variant only
|
|
54
|
+
* some of its glyphs support will offer it for all of them until that closes.
|
|
55
|
+
*/
|
|
56
|
+
declare function memberVariantOptions(library: IconLibrary, _member: string): readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* Whether an element type declares a prop that may survive layer-style projection. A placed
|
|
59
|
+
* glyph's type isn't a component, so its prop surface comes from its library instead: the
|
|
60
|
+
* component the set renders through, plus the size and variant axes the set ships.
|
|
61
|
+
*/
|
|
62
|
+
declare function isDeclaredElementProp(config: Config | null | undefined, elementType: string, propName: string): boolean;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { IconLibrary, assetType, iconCategories, iconLibraries, iconLibrary, isDeclaredElementProp, memberVariantOptions, resolveIconLibrary };
|