@yahoo/uds-create-config 2.45.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,630 @@
|
|
|
1
|
+
import { isRef, kindOf, pathOf, refLeaf } from "./utils/refs.js";
|
|
2
|
+
import { rootLayerOf } from "../entities/system/element.js";
|
|
3
|
+
import { classPrefixOf } from "../entities/system/Settings.js";
|
|
4
|
+
import { authoredValue, className, negatedCssValue, renderStyleValue, resolveComponentProps, stylePropLeafForToken, stylePropValueLeaves, stylePropertyPathFor } from "./projections.js";
|
|
5
|
+
import { ruleApplies } from "./layer-styles.js";
|
|
6
|
+
import { createSliceMemo } from "./memo.js";
|
|
7
|
+
//#region src/framework/class-names.ts
|
|
8
|
+
/**
|
|
9
|
+
* What a class is CALLED — the one answer, for everything that has to agree about it.
|
|
10
|
+
*
|
|
11
|
+
* Three things name the same class from three directions: the stylesheet writes the rule, the
|
|
12
|
+
* emitted module puts the class on an element, and the canvas — which renders a component the
|
|
13
|
+
* registry has no module for by expanding its anatomy — has to derive the same string at render
|
|
14
|
+
* time from the live config. v1 kept those derivations apart, and any drift between them
|
|
15
|
+
* tree-shakes away a rule the app uses or puts a class on an element the sheet never styled.
|
|
16
|
+
* Both failures are silent and look like "the styling just didn't apply".
|
|
17
|
+
*
|
|
18
|
+
* It lives in config-v2 rather than in codegen because the third caller runs in a browser: a class
|
|
19
|
+
* name is a projection of the config, like a CSS var name or a token's resolved value, and nothing
|
|
20
|
+
* here reads a source file.
|
|
21
|
+
*/
|
|
22
|
+
/** `HStack` → `hstack`, `AvatarItem` → `avatar-item`. A dash only between a lower/digit and an
|
|
23
|
+
* upper, so an initialism isn't split. */
|
|
24
|
+
function kebabComponent(name) {
|
|
25
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Every attribute Create sets only to hold an element in a condition starts with this. The `create`
|
|
29
|
+
* segment keeps it clear of a consumer's own `data-*` attributes, and `force` says the attribute
|
|
30
|
+
* puts the element in the condition rather than describing it.
|
|
31
|
+
*/
|
|
32
|
+
const FORCE_ATTRIBUTE_PREFIX = "data-create-force-";
|
|
33
|
+
/**
|
|
34
|
+
* The attribute a surface sets to hold a modifier's state open — `data-create-force-focus-visible`.
|
|
35
|
+
*
|
|
36
|
+
* This is a contract between two sides that can't see each other: an editor sets the attribute on an
|
|
37
|
+
* element, and a stylesheet emitted somewhere else has to match it. Every spelling derives from here,
|
|
38
|
+
* including the playground's inlined copy, since a multi-word modifier (`focusVisible`) matches
|
|
39
|
+
* nothing when one side skips the kebab-casing.
|
|
40
|
+
*/
|
|
41
|
+
function forceStateAttribute(modifier) {
|
|
42
|
+
const name = modifier.startsWith("_") ? modifier.slice(1) : modifier;
|
|
43
|
+
return `${FORCE_ATTRIBUTE_PREFIX}${kebabComponent(name.slice(name.lastIndexOf("/") + 1))}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The attribute that forces one mode group on an element and its subtree:
|
|
47
|
+
* `data-create-force-mode-<group>="<option>"`. The group is lowercased and a nested group's slashes
|
|
48
|
+
* become dashes, since an attribute name can hold neither. The emitter admits this attribute beside
|
|
49
|
+
* every selector mode's own selector, so an element carrying it is in the mode whatever shape the
|
|
50
|
+
* author gave the selector.
|
|
51
|
+
*/
|
|
52
|
+
function forceModeAttribute(group) {
|
|
53
|
+
return `${FORCE_ATTRIBUTE_PREFIX}mode-${group.toLowerCase().replaceAll("/", "-")}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The attribute and value that force one mode option (`colorMode/dark` →
|
|
57
|
+
* `data-create-force-mode-colormode="dark"`). A mode outside any group has none, since there is no
|
|
58
|
+
* group to force.
|
|
59
|
+
*/
|
|
60
|
+
function forceModeAttributeOf(modePath) {
|
|
61
|
+
const slash = modePath.lastIndexOf("/");
|
|
62
|
+
if (slash <= 0) return void 0;
|
|
63
|
+
return {
|
|
64
|
+
name: forceModeAttribute(modePath.slice(0, slash)),
|
|
65
|
+
value: modePath.slice(slash + 1)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The spec prop that forces a mode group on an element. It keeps the group's authored casing
|
|
70
|
+
* (`data-create-force-mode-colorMode`), and the render wrapper spells it as
|
|
71
|
+
* {@link forceModeAttribute} when it reaches the DOM.
|
|
72
|
+
*/
|
|
73
|
+
function forceModeProp(group) {
|
|
74
|
+
return `${FORCE_ATTRIBUTE_PREFIX}mode-${group}`;
|
|
75
|
+
}
|
|
76
|
+
/** Persisted specs still carry the spelling this prop had before it was namespaced. */
|
|
77
|
+
const LEGACY_FORCE_MODE_PROP_PREFIX = "data-mode-";
|
|
78
|
+
/** The group a spec prop forces a mode on, or `undefined` when the prop is something else. */
|
|
79
|
+
function forceModePropGroup(key) {
|
|
80
|
+
const current = `${FORCE_ATTRIBUTE_PREFIX}mode-`;
|
|
81
|
+
if (key.startsWith(current)) return key.slice(current.length);
|
|
82
|
+
if (key.startsWith(LEGACY_FORCE_MODE_PROP_PREFIX)) return key.slice(10);
|
|
83
|
+
}
|
|
84
|
+
/** Whether a spec prop forces a mode group, in the current spelling or the one persisted specs carry. */
|
|
85
|
+
function isForceModeProp(key) {
|
|
86
|
+
return forceModePropGroup(key) !== void 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The option a spec's props force for one group, or `undefined`. Reads the current prop first, and
|
|
90
|
+
* falls back to the legacy spelling so a design saved before the rename still forces its mode.
|
|
91
|
+
*/
|
|
92
|
+
function forceModePropValue(props, group) {
|
|
93
|
+
if (!props) return void 0;
|
|
94
|
+
for (const key of forceModeProps(group)) {
|
|
95
|
+
const value = props[key];
|
|
96
|
+
if (typeof value === "string" && value) return value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Every prop that can force one group, current spelling first. A writer clears each of them when it
|
|
101
|
+
* changes the selection, so a legacy key can't keep forcing a mode the user turned off.
|
|
102
|
+
*/
|
|
103
|
+
function forceModeProps(group) {
|
|
104
|
+
return [forceModeProp(group), `${LEGACY_FORCE_MODE_PROP_PREFIX}${group}`];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The class stem for a component — `uds-list-item`.
|
|
108
|
+
*
|
|
109
|
+
* Derived from the component's PATH, not its name, so a grouped component (`forms/Toggle`) gets a
|
|
110
|
+
* stem no other group can collide with. Everything a component wears extends this stem.
|
|
111
|
+
*/
|
|
112
|
+
function componentClassBase(config, path) {
|
|
113
|
+
return kebabComponent(className(config, "component", path));
|
|
114
|
+
}
|
|
115
|
+
/** The class one layer wears unconditionally — `uds-list-item-label`. A component's defaults land on
|
|
116
|
+
* this selector at zero specificity, so nothing about it is conditional. */
|
|
117
|
+
function componentLayerClass(config, path, layer) {
|
|
118
|
+
return `${componentClassBase(config, path)}-${layer}`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* A rule's condition as it appears in a class name: `{size:'xs'}` → `size-xs`, and an empty condition
|
|
122
|
+
* (an unconditional rule) → `''`.
|
|
123
|
+
*
|
|
124
|
+
* A class name is an IDENTIFIER, so the value is made safe for one: an unescaped `.` starts a second
|
|
125
|
+
* class and `/` is not a name character at all, so a rule keyed on `size: '0.5'` emitted
|
|
126
|
+
* `.uds-card-root-size-0.5` — parsed as `.uds-card-root-size-0` plus garbage, discarding the rule,
|
|
127
|
+
* while the module put the literal string on the element.
|
|
128
|
+
*
|
|
129
|
+
* Written out rather than shared with {@link stylePropClassName}, which applies the same transform:
|
|
130
|
+
* as a small module-private helper it did not survive one of the bundlers this module is compiled
|
|
131
|
+
* through, and `uds build` died on `classSafe is not defined`. Two spellings of four characters is
|
|
132
|
+
* the cheaper problem.
|
|
133
|
+
*/
|
|
134
|
+
function ruleCondition(when) {
|
|
135
|
+
return Object.entries(when ?? {}).map(([prop, value]) => `${prop}-${String(value).replaceAll("/", "-").replaceAll(".", "_").replace(/\s+/g, "-")}`).join("-");
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Every conditional class a component's style rules produce.
|
|
139
|
+
*
|
|
140
|
+
* Unconditional rules are absent by design: they land on the layer's own zero-specificity selector
|
|
141
|
+
* ({@link componentLayerClass}), which every element already wears with nothing to test.
|
|
142
|
+
*/
|
|
143
|
+
function componentRuleClasses(config, path) {
|
|
144
|
+
const component = config.resolve("component", path);
|
|
145
|
+
if (!component) return [];
|
|
146
|
+
const { layers = {}, styles = {} } = component.toJSON();
|
|
147
|
+
const base = componentClassBase(config, path);
|
|
148
|
+
const out = [];
|
|
149
|
+
for (const rule of Object.values(styles)) {
|
|
150
|
+
const when = Object.fromEntries(Object.entries(rule.when ?? {}).map(([prop, value]) => [prop, refLeaf(value)]));
|
|
151
|
+
const condition = ruleCondition(when);
|
|
152
|
+
if (!condition) continue;
|
|
153
|
+
for (const layer of Object.keys(rule.layers ?? {})) {
|
|
154
|
+
if (!(layer in layers)) continue;
|
|
155
|
+
out.push({
|
|
156
|
+
layer,
|
|
157
|
+
when,
|
|
158
|
+
className: `${base}-${layer}-${condition}`
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
/** The MEMBER a bag value names, under the group its prop binds — the value is either the qualified
|
|
165
|
+
* ref it is stored as, or the bare leaf an older body holds. */
|
|
166
|
+
function memberNamed(groupRef, value) {
|
|
167
|
+
if (isRef(value)) return pathOf(value.__ref);
|
|
168
|
+
return typeof value === "string" ? `${pathOf(groupRef)}/${value}` : void 0;
|
|
169
|
+
}
|
|
170
|
+
/** The same read for a value whose domain is a whole KIND rather than a group, so the ref's path is
|
|
171
|
+
* the name itself. */
|
|
172
|
+
function presetNamed(value) {
|
|
173
|
+
if (isRef(value)) return pathOf(value.__ref);
|
|
174
|
+
return typeof value === "string" ? value : void 0;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Every COMPOSITE class a component's style rules apply, with the condition each applies under.
|
|
178
|
+
*
|
|
179
|
+
* A composite prop names a value (`variant: 'ui6'`) whose CSS is a class rather than a set of
|
|
180
|
+
* declarations, so it can't reach the element the way a style prop does. Same shape as
|
|
181
|
+
* {@link componentRuleClasses} for that reason.
|
|
182
|
+
*
|
|
183
|
+
* This answers WHICH CLASS a rule's composite ends up as, not who applies it — the layer's receiver
|
|
184
|
+
* does, out of the prop it is forwarded ({@link layerCompositeProps}). The caller is the EXTRACTOR,
|
|
185
|
+
* which has to keep that class's CSS from being shaken out as unreferenced: after the forward the
|
|
186
|
+
* value appears in the emitted module only as a prop string, so nothing else in the build names it.
|
|
187
|
+
*
|
|
188
|
+
* Unlike `componentRuleClasses`, an UNCONDITIONAL rule is included (`when` empty). That function
|
|
189
|
+
* omits them because their declarations land on the layer's own zero-specificity selector — but a
|
|
190
|
+
* composite contributes no declarations there, so omitting it would drop the class entirely.
|
|
191
|
+
*/
|
|
192
|
+
function componentCompositeClasses(config, path) {
|
|
193
|
+
const component = config.resolve("component", path);
|
|
194
|
+
if (!component) return [];
|
|
195
|
+
const { layers = {}, styles = {} } = component.toJSON();
|
|
196
|
+
const out = [];
|
|
197
|
+
for (const rule of Object.values(styles)) {
|
|
198
|
+
const when = Object.fromEntries(Object.entries(rule.when ?? {}).map(([prop, value]) => [prop, refLeaf(value)]));
|
|
199
|
+
for (const [layer, bag] of Object.entries(rule.layers ?? {})) {
|
|
200
|
+
const element = layers[layer];
|
|
201
|
+
if (!isRef(element)) continue;
|
|
202
|
+
const declared = resolveComponentProps(config, pathOf(element.__ref));
|
|
203
|
+
for (const [prop, value] of Object.entries(bag ?? {})) {
|
|
204
|
+
const bound = declared[prop]?.value;
|
|
205
|
+
if (!isRef(bound) || kindOf(bound.__ref) !== "composite") continue;
|
|
206
|
+
const target = memberNamed(bound.__ref, value);
|
|
207
|
+
if (target === void 0 || !config.resolve("composite", target)) continue;
|
|
208
|
+
out.push({
|
|
209
|
+
layer,
|
|
210
|
+
when,
|
|
211
|
+
className: className(config, "composite", target)
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
/** The class a CSS motion preset is applied by. Namespaced, so it doesn't share a space with the
|
|
219
|
+
* style-prop utilities; the `@keyframes` it runs keep their own name. */
|
|
220
|
+
function motionClassName(config, path) {
|
|
221
|
+
return `${classPrefixOf(config)}-motion-${path.replaceAll("/", "-")}`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Every MOTION class a component's style rules apply — a layer bag naming a preset (`motion: 'spin'`).
|
|
225
|
+
*
|
|
226
|
+
* The same shape and the same reason as {@link componentCompositeClasses}: a CSS preset's whole
|
|
227
|
+
* runtime is a class, so a layer that references one has to wear it, under whatever condition its
|
|
228
|
+
* rule declares. Without this the value went nowhere — `motion` names no style property so it isn't
|
|
229
|
+
* a declaration, and it IS a declared prop of the layer's element so it isn't an attribute either.
|
|
230
|
+
*
|
|
231
|
+
* A JS preset is skipped: it animates in the client and has no class to wear.
|
|
232
|
+
*/
|
|
233
|
+
function componentMotionClasses(config, path) {
|
|
234
|
+
const component = config.resolve("component", path);
|
|
235
|
+
if (!component) return [];
|
|
236
|
+
const { layers = {}, styles = {} } = component.toJSON();
|
|
237
|
+
const out = [];
|
|
238
|
+
for (const rule of Object.values(styles)) {
|
|
239
|
+
const when = Object.fromEntries(Object.entries(rule.when ?? {}).map(([prop, value]) => [prop, refLeaf(value)]));
|
|
240
|
+
for (const [layer, bag] of Object.entries(rule.layers ?? {})) {
|
|
241
|
+
const element = layers[layer];
|
|
242
|
+
if (!isRef(element)) continue;
|
|
243
|
+
const declared = resolveComponentProps(config, pathOf(element.__ref));
|
|
244
|
+
for (const [prop, value] of Object.entries(bag ?? {})) {
|
|
245
|
+
if (declared[prop]?.type !== "motion") continue;
|
|
246
|
+
const name = presetNamed(value);
|
|
247
|
+
if (name === void 0) continue;
|
|
248
|
+
const preset = config.resolve("motion", name)?.toJSON();
|
|
249
|
+
if (preset?.runtime !== "css" || !preset.keyframes) continue;
|
|
250
|
+
out.push({
|
|
251
|
+
layer,
|
|
252
|
+
when,
|
|
253
|
+
className: motionClassName(config, name)
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The classes a component's OWN props put on it, by layer — `variant="body"` picking
|
|
262
|
+
* `textVariant/body`'s class.
|
|
263
|
+
*
|
|
264
|
+
* A composite is the only prop that works this way, and it has to: its whole CSS is a class, so it
|
|
265
|
+
* can't ride the prop channel the way a style prop does. That makes it the one piece of an
|
|
266
|
+
* instance's styling a projection can lose entirely, and losing it is what made a component look one
|
|
267
|
+
* way in the component editor and another on a canvas — the expansion resolved it, the anatomy
|
|
268
|
+
* projection had no route for it, and the matrix painted the cell in the wrong typography.
|
|
269
|
+
*
|
|
270
|
+
* So both projections read this and neither derives it. `state` is merged over the component's
|
|
271
|
+
* defaults, because a value the caller didn't set has to read the default — the same rule
|
|
272
|
+
* {@link layerStyles} follows.
|
|
273
|
+
*
|
|
274
|
+
* Keyed by layer even though today it only ever names the ROOT one, so a caller needs no opinion
|
|
275
|
+
* about which layer that is: an instance's own props land where its own props land.
|
|
276
|
+
*/
|
|
277
|
+
function componentPropClasses(config, path, state = {}) {
|
|
278
|
+
const component = config.resolve("component", path);
|
|
279
|
+
if (!component) return {};
|
|
280
|
+
const { layers = {}, props = {}, defaultProps = {} } = component.toJSON();
|
|
281
|
+
const [root] = rootLayerOf(layers);
|
|
282
|
+
const resolved = {
|
|
283
|
+
...defaultProps,
|
|
284
|
+
...state
|
|
285
|
+
};
|
|
286
|
+
const classes = [];
|
|
287
|
+
for (const [prop, decl] of Object.entries(props)) {
|
|
288
|
+
if (decl?.type !== "composite") continue;
|
|
289
|
+
const group = isRef(decl.value) ? decl.value.__ref : void 0;
|
|
290
|
+
const value = resolved[prop];
|
|
291
|
+
if (!group) continue;
|
|
292
|
+
const target = memberNamed(group, value);
|
|
293
|
+
if (target === void 0) continue;
|
|
294
|
+
if (!config.resolve("composite", target)) continue;
|
|
295
|
+
classes.push(className(config, "composite", target));
|
|
296
|
+
}
|
|
297
|
+
return classes.length > 0 ? { [root]: classes } : {};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* The COMPOSITE a style rule sets on each layer, for one instance — forwarded to the layer as a prop.
|
|
301
|
+
*
|
|
302
|
+
* A composite's whole CSS is a class, so a rule's condition class (where the stylesheet hangs its
|
|
303
|
+
* DECLARATIONS) cannot carry one. The route is the layer's RECEIVER: the bag key already IS that
|
|
304
|
+
* receiver's own prop name — `variant` for a `Text`-backed layer, `textVariant` for an `Input`-backed
|
|
305
|
+
* one, both binding the same group — so this copies the key verbatim and there is nothing to resolve.
|
|
306
|
+
* `Text` turns `variant="label3"` into `uds-textVariant-label3` for itself, and always has.
|
|
307
|
+
*
|
|
308
|
+
* Forwarding rather than resolving is what makes a layer's styling live-editable at all: a class only
|
|
309
|
+
* exists once a build has emitted the stylesheet, so an edit that makes a NEW style rule paints
|
|
310
|
+
* nothing until a rebuild, while a prop json-render applies on the spot. Both projections of a
|
|
311
|
+
* component read this, so neither has to know the receiver's name for the group.
|
|
312
|
+
*
|
|
313
|
+
* Only what the receiver DECLARES as composite-typed. A bag key it doesn't declare is an ordinary
|
|
314
|
+
* prop or an attribute, and belongs to whatever channel already carries it.
|
|
315
|
+
*/
|
|
316
|
+
function layerCompositeProps(config, path, state = {}) {
|
|
317
|
+
const component = config.resolve("component", path);
|
|
318
|
+
if (!component) return {};
|
|
319
|
+
const { layers = {}, styles = {}, defaultProps = {} } = component.toJSON();
|
|
320
|
+
const resolved = {
|
|
321
|
+
...defaultProps,
|
|
322
|
+
...state
|
|
323
|
+
};
|
|
324
|
+
const out = {};
|
|
325
|
+
const applicable = Object.values(styles).filter((rule) => ruleApplies(rule.when, resolved)).sort((left, right) => Object.keys(left.when ?? {}).length - Object.keys(right.when ?? {}).length);
|
|
326
|
+
for (const rule of applicable) for (const [layer, bag] of Object.entries(rule.layers ?? {})) {
|
|
327
|
+
const element = layers[layer];
|
|
328
|
+
if (!isRef(element)) continue;
|
|
329
|
+
const declared = resolveComponentProps(config, pathOf(element.__ref));
|
|
330
|
+
for (const [prop, value] of Object.entries(bag ?? {})) {
|
|
331
|
+
const bound = declared[prop]?.value;
|
|
332
|
+
if (!isRef(bound) || kindOf(bound.__ref) !== "composite") continue;
|
|
333
|
+
out[layer] ??= {};
|
|
334
|
+
out[layer][prop] = authoredValue(config, prop, value);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The CSS MOTION classes a style rule puts on a layer, for one instance.
|
|
341
|
+
*
|
|
342
|
+
* A preset's whole runtime is a class too, and a composite's route (forward it, and let the receiver
|
|
343
|
+
* resolve its own prop — {@link layerCompositeProps}) does not exist for this one: `motion` is not a
|
|
344
|
+
* style property, so {@link splitStyleProps} has no dispatch for it and a forwarded `motion="spin"`
|
|
345
|
+
* would reach the element as an attribute and animate nothing. The emitted runtime table DOES carry
|
|
346
|
+
* it — codegen adds a closed `motion` entry — which is why a component with a module needs nothing
|
|
347
|
+
* here, and one expanded from the config alone needs this.
|
|
348
|
+
*/
|
|
349
|
+
function styleRuleMotionClasses(config, path, state = {}) {
|
|
350
|
+
const { defaultProps = {} } = config.resolve("component", path)?.toJSON() ?? {};
|
|
351
|
+
const resolved = {
|
|
352
|
+
...defaultProps,
|
|
353
|
+
...state
|
|
354
|
+
};
|
|
355
|
+
const out = {};
|
|
356
|
+
for (const rule of componentMotionClasses(config, path)) {
|
|
357
|
+
if (!ruleApplies(rule.when, resolved)) continue;
|
|
358
|
+
out[rule.layer] ??= [];
|
|
359
|
+
if (!out[rule.layer].includes(rule.className)) out[rule.layer].push(rule.className);
|
|
360
|
+
}
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* The class-name stem for a style prop: its authored `classPrefix` when it declares one, else its
|
|
365
|
+
* path — or, for an OPACITY COMPANION, its target's stem plus `-opacity`.
|
|
366
|
+
*
|
|
367
|
+
* An EMPTY prefix is meaningful and not the same as an absent one — `position: absolute` ships as
|
|
368
|
+
* `.uds-absolute`, with no prop segment at all — so this tests for `undefined` rather than
|
|
369
|
+
* falsiness.
|
|
370
|
+
*
|
|
371
|
+
* The companion case exists because the path fallback is wrong for one: a companion is named after
|
|
372
|
+
* the prop it modulates (`bgOpacity`), so falling back to the path spells the stem in the prop's
|
|
373
|
+
* camelCase (`uds-bgOpacity`) rather than the kebab every other class uses, and spells it
|
|
374
|
+
* independently of the target whose fade it is. Deriving it from the PAIRING keeps the two in step —
|
|
375
|
+
* renaming `bg`'s prefix moves `bg-opacity` with it — and costs a config nothing to author. Every
|
|
376
|
+
* opacity prop in every config in this repo declares no prefix, which is what made this reachable.
|
|
377
|
+
*/
|
|
378
|
+
function stylePropClassBase(config, path) {
|
|
379
|
+
const { classPrefix, opacityOf } = config.resolve("style-property", path)?.toJSON() ?? {};
|
|
380
|
+
if (classPrefix === void 0 && opacityOf) return `${stylePropClassBase(config, pathOf(opacityOf.__ref))}-opacity`;
|
|
381
|
+
const segment = classPrefix ?? path;
|
|
382
|
+
return segment ? className(config, "style-property", segment) : classPrefixOf(config);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* The class for one authored value — `bg="primary"` → `uds-bg-primary`.
|
|
386
|
+
*
|
|
387
|
+
* The value is a LEAF, which is what a call site writes; an empty leaf is a boolean prop's `true`
|
|
388
|
+
* arm, whose class is the bare stem (`uds-border`) because a flag names no value.
|
|
389
|
+
*
|
|
390
|
+
* A slash becomes a dash and a DOT an underscore, because a class name can hold neither: `.uds-p-0.5`
|
|
391
|
+
* is not one selector but two (`uds-p-0` and `5`), so the rule the sheet wrote could never match the
|
|
392
|
+
* element the module classed. `spacing/0.5` is a real token in a real system, which is how that
|
|
393
|
+
* surfaced.
|
|
394
|
+
*/
|
|
395
|
+
function stylePropClassName(config, path, leaf) {
|
|
396
|
+
const base = stylePropClassBase(config, path);
|
|
397
|
+
const suffix = leaf.replaceAll("/", "-").replaceAll(".", "_").replace(/\s+/g, "-");
|
|
398
|
+
return suffix ? `${base}-${suffix}` : base;
|
|
399
|
+
}
|
|
400
|
+
/** An off-scale value and what it really is — `[13px]` → `13px`, else `undefined`. The brackets mark
|
|
401
|
+
* a value the system doesn't tokenize; they aren't part of it. No class can exist for one, because a
|
|
402
|
+
* class is emitted per DECLARED value and this is by definition not declared. Inside the brackets an
|
|
403
|
+
* underscore encodes a space (`[repeat(7,_36px)]` → `repeat(7, 36px)`); it must be reversed here
|
|
404
|
+
* because a CSS value with a literal underscore is invalid and the browser drops the declaration.
|
|
405
|
+
* A `url(…)` span is exempt — its underscores are part of the address, not an escape (an AI-repaired
|
|
406
|
+
* spec brackets a model-emitted `url(…)` verbatim), which is the same carve-out Tailwind makes. */
|
|
407
|
+
function offScale(value) {
|
|
408
|
+
if (typeof value !== "string") return void 0;
|
|
409
|
+
return value.startsWith("[") && value.endsWith("]") ? unescapeArbitrary(value.slice(1, -1)) : void 0;
|
|
410
|
+
}
|
|
411
|
+
/** `_` → space, except inside `url(…)` where an underscore is literal. */
|
|
412
|
+
function unescapeArbitrary(value) {
|
|
413
|
+
return value.replace(/url\([^)]*\)|_/g, (span) => span === "_" ? " " : span);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Split a prop bag into a class string and the props that aren't styling.
|
|
417
|
+
*
|
|
418
|
+
* This is the same dispatch the emitted `_style-props` runtime performs, over a live config instead
|
|
419
|
+
* of the table that build baked. Both exist because they run in different places — an app's module
|
|
420
|
+
* has no config at runtime, and the canvas has no baked table for a component that was never built —
|
|
421
|
+
* but the CLASS NAMES both produce come from {@link stylePropClassName}, so the two can't disagree
|
|
422
|
+
* about what a value is called.
|
|
423
|
+
*
|
|
424
|
+
* An off-scale value can't be a class, so it lands in `style` on the returned rest; an explicit
|
|
425
|
+
* `style` the caller passed still wins, since that's the escape hatch of last resort.
|
|
426
|
+
*/
|
|
427
|
+
function splitStyleProps({ config, bag, through }) {
|
|
428
|
+
const classes = [];
|
|
429
|
+
const rest = {};
|
|
430
|
+
const style = {};
|
|
431
|
+
const modifiers = new Map(config.list("modifier").map((modifier) => [`_${modifier.leaf}`, modifier.leaf]));
|
|
432
|
+
for (const [key, value] of Object.entries(bag)) {
|
|
433
|
+
const modifier = modifiers.get(key);
|
|
434
|
+
if (modifier) {
|
|
435
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
436
|
+
const inner = splitStyleProps({
|
|
437
|
+
config,
|
|
438
|
+
bag: value,
|
|
439
|
+
through
|
|
440
|
+
});
|
|
441
|
+
for (const cls of inner.className.split(" ").filter(Boolean)) classes.push(`${modifier}:${cls}`);
|
|
442
|
+
}
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
const name = stylePropertyPathFor({
|
|
446
|
+
config,
|
|
447
|
+
through,
|
|
448
|
+
key
|
|
449
|
+
}) ?? key;
|
|
450
|
+
const prop = config.resolve("style-property", name);
|
|
451
|
+
if (!prop) {
|
|
452
|
+
rest[key] = value;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (value === void 0 || value === null) continue;
|
|
456
|
+
const { arbitrary, properties = [], negates } = prop.toJSON();
|
|
457
|
+
const off = arbitrary ? offScale(value) : void 0;
|
|
458
|
+
if (off !== void 0) {
|
|
459
|
+
const declared = negates ? negatedCssValue(off) : off;
|
|
460
|
+
for (const property of properties) style[reactStyleKey(property)] = declared;
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (isRef(value) && kindOf(value.__ref) === "token") {
|
|
464
|
+
const leaf = stylePropLeafForToken(config, name, pathOf(value.__ref));
|
|
465
|
+
if (leaf !== void 0) {
|
|
466
|
+
classes.push(stylePropClassName(config, name, leaf));
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (typeof value === "boolean") {
|
|
471
|
+
if (value) classes.push(stylePropClassName(config, name, ""));
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (typeof value === "object") {
|
|
475
|
+
const rendered = renderStyleValue(config, value);
|
|
476
|
+
const declared = negates ? negatedCssValue(rendered) : rendered;
|
|
477
|
+
for (const property of properties) style[reactStyleKey(property)] = declared;
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
classes.push(stylePropClassName(config, name, String(value)));
|
|
481
|
+
}
|
|
482
|
+
if (Object.keys(style).length > 0) {
|
|
483
|
+
const given = rest.style;
|
|
484
|
+
const explicit = {};
|
|
485
|
+
for (const [property, value] of Object.entries(given ?? {})) explicit[reactStyleKey(property)] = value;
|
|
486
|
+
rest.style = {
|
|
487
|
+
...style,
|
|
488
|
+
...explicit
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
className: classes.join(" "),
|
|
493
|
+
rest
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* A CSS property name as REACT's `style` object spells it.
|
|
498
|
+
*
|
|
499
|
+
* `rest.style` is handed to React, not written into a stylesheet, and React's `style` takes
|
|
500
|
+
* camelCase. It does not merely tolerate the CSS spelling — it DROPS the declaration and warns. So
|
|
501
|
+
* every off-scale value, computed colour and gradient on this path painted nothing, and the only
|
|
502
|
+
* sign was a dev-console line among many.
|
|
503
|
+
*
|
|
504
|
+
* A custom property (`--uds-brand`) is passed through untouched: React writes those verbatim, and
|
|
505
|
+
* camelCasing one would break the case that already worked.
|
|
506
|
+
*/
|
|
507
|
+
function reactStyleKey(property) {
|
|
508
|
+
if (property.startsWith("--")) return property;
|
|
509
|
+
return property.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Every class a prop can produce, by leaf.
|
|
513
|
+
*
|
|
514
|
+
* Deduplicated on the leaf, keeping the FIRST: a prop may bind two token groups that share one
|
|
515
|
+
* (`top` takes both `spacing` and `position`, and both declare `0`), and `stylePropValueFromLeaf`
|
|
516
|
+
* resolves such a value with a `.find()` — so authored order already decides which token a leaf
|
|
517
|
+
* means, and the class set follows that rather than inventing a second answer.
|
|
518
|
+
*/
|
|
519
|
+
function stylePropClasses(config, path) {
|
|
520
|
+
const out = /* @__PURE__ */ new Map();
|
|
521
|
+
for (const leaf of stylePropValueLeaves(config, path)) if (!out.has(leaf)) out.set(leaf, stylePropClassName(config, path, leaf));
|
|
522
|
+
return out;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Every MODIFIER-prefixed utility class the config itself asks for — `focus:uds-border-color-brand`.
|
|
526
|
+
*
|
|
527
|
+
* Modifier utilities can't be emitted exhaustively: every modifier against every utility is 25 ×
|
|
528
|
+
* 9,284 rules for a real system, and a sheet nobody can load is the same as no sheet. So they're
|
|
529
|
+
* driven by USE, and a build takes `used` from having read the app's source files.
|
|
530
|
+
*
|
|
531
|
+
* Studio has no source files to read, and doesn't need any: a config STATES what it asks for. Every
|
|
532
|
+
* bag it holds — a component's defaults, a preview's, each style rule's per-layer bag, each anatomy
|
|
533
|
+
* node's props, a composite's bag — goes through the same {@link splitStyleProps} the runtime uses,
|
|
534
|
+
* so the strings match on both sides by construction rather than by agreement. For the studio system
|
|
535
|
+
* that's 86 classes against 232,100.
|
|
536
|
+
*
|
|
537
|
+
* WHAT THIS CANNOT SEE, stated because the gap is real: a prop set on a design-file NODE (a
|
|
538
|
+
* `_hover` a user adds in the designer panel) is in the document, not the system, so no projection of
|
|
539
|
+
* the system can predict it. Covering those needs the document as a second source of use.
|
|
540
|
+
*/
|
|
541
|
+
function modifierUtilitiesUsed(config) {
|
|
542
|
+
const used = /* @__PURE__ */ new Set();
|
|
543
|
+
const token = vocabularyToken(config);
|
|
544
|
+
const stored = config.snapshot.slice("component").items;
|
|
545
|
+
for (const component of config.list("component")) for (const cls of classesUsedBy(config, stored.get(component.path) ?? component, token, componentBags)) used.add(cls);
|
|
546
|
+
const storedComposites = config.snapshot.slice("composite").items;
|
|
547
|
+
for (const composite of config.list("composite")) for (const cls of classesUsedBy(config, storedComposites.get(composite.path) ?? composite, token, compositeBags)) used.add(cls);
|
|
548
|
+
return used;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Every style bag a COMPONENT states it wants, each with the definitions its keys resolve against.
|
|
552
|
+
*
|
|
553
|
+
* Not uniform, which is the whole reason it travels with the bag. `defaultProps` and `previewProps`
|
|
554
|
+
* are the component's OWN props, and nothing else has a claim. A style rule's per-layer bag and an
|
|
555
|
+
* anatomy node's props are set on a LAYER'S ELEMENT, so that element answers too — after the
|
|
556
|
+
* component itself, whose own declaration of a name is what that name means throughout its
|
|
557
|
+
* definition.
|
|
558
|
+
*/
|
|
559
|
+
function componentBags(entity) {
|
|
560
|
+
const { path } = entity;
|
|
561
|
+
const { defaultProps, previewProps, styles, anatomy, layers } = entity.toJSON();
|
|
562
|
+
const bags = [{
|
|
563
|
+
bag: defaultProps,
|
|
564
|
+
through: [path]
|
|
565
|
+
}, {
|
|
566
|
+
bag: previewProps,
|
|
567
|
+
through: [path]
|
|
568
|
+
}];
|
|
569
|
+
for (const rule of Object.values(styles ?? {})) for (const [layer, bag] of Object.entries(rule?.layers ?? {})) bags.push({
|
|
570
|
+
bag,
|
|
571
|
+
through: [path, componentElementOf(layers?.[layer])]
|
|
572
|
+
});
|
|
573
|
+
for (const node of Object.values(anatomy ?? {})) bags.push({
|
|
574
|
+
bag: node?.props,
|
|
575
|
+
through: [path, componentElementOf(node?.element)]
|
|
576
|
+
});
|
|
577
|
+
return bags;
|
|
578
|
+
}
|
|
579
|
+
/** The component an element ref names, or `undefined` for a raw tag or a layer ref — neither of which
|
|
580
|
+
* is a component whose props could be renamed. */
|
|
581
|
+
function componentElementOf(element) {
|
|
582
|
+
return isRef(element) && kindOf(element.__ref) === "component" ? pathOf(element.__ref) : void 0;
|
|
583
|
+
}
|
|
584
|
+
/** A composite states one bag, and it belongs to no component. */
|
|
585
|
+
function compositeBags(entity) {
|
|
586
|
+
return [{ bag: entity.toJSON().styles }];
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* A token object that changes when the class VOCABULARY does — the style properties, and everything
|
|
590
|
+
* their value domains reach.
|
|
591
|
+
*
|
|
592
|
+
* `splitStyleProps` names a class by asking the config what a prop's leaves are, so a scan's answer
|
|
593
|
+
* survives any edit that leaves those alone. Which is every edit to the entities being scanned.
|
|
594
|
+
*/
|
|
595
|
+
const vocabularyToken = createSliceMemo({
|
|
596
|
+
kinds: [
|
|
597
|
+
"style-property",
|
|
598
|
+
"token",
|
|
599
|
+
"composite",
|
|
600
|
+
"motion",
|
|
601
|
+
"icon",
|
|
602
|
+
"font"
|
|
603
|
+
],
|
|
604
|
+
compute: (_config) => ({})
|
|
605
|
+
});
|
|
606
|
+
const usedClassCache = /* @__PURE__ */ new WeakMap();
|
|
607
|
+
/** One owner's prefixed classes, cached on (its stored entity, the vocabulary). */
|
|
608
|
+
function classesUsedBy(config, stored, token, bagsOf) {
|
|
609
|
+
let byVocabulary = usedClassCache.get(stored);
|
|
610
|
+
if (!byVocabulary) {
|
|
611
|
+
byVocabulary = /* @__PURE__ */ new WeakMap();
|
|
612
|
+
usedClassCache.set(stored, byVocabulary);
|
|
613
|
+
}
|
|
614
|
+
const hit = byVocabulary.get(token);
|
|
615
|
+
if (hit) return hit;
|
|
616
|
+
const found = [];
|
|
617
|
+
for (const { bag, through } of bagsOf(stored)) {
|
|
618
|
+
if (!bag || typeof bag !== "object" || Array.isArray(bag)) continue;
|
|
619
|
+
const { className } = splitStyleProps({
|
|
620
|
+
config,
|
|
621
|
+
bag,
|
|
622
|
+
through
|
|
623
|
+
});
|
|
624
|
+
for (const cls of className.split(" ")) if (cls.includes(":")) found.push(cls);
|
|
625
|
+
}
|
|
626
|
+
byVocabulary.set(token, found);
|
|
627
|
+
return found;
|
|
628
|
+
}
|
|
629
|
+
//#endregion
|
|
630
|
+
export { componentClassBase, componentCompositeClasses, componentLayerClass, componentMotionClasses, componentPropClasses, componentRuleClasses, forceModeAttribute, forceModeAttributeOf, forceModeProp, forceModePropGroup, forceModePropValue, forceModeProps, forceStateAttribute, isForceModeProp, kebabComponent, layerCompositeProps, modifierUtilitiesUsed, motionClassName, ruleCondition, splitStyleProps, stylePropClassBase, stylePropClassName, stylePropClasses, styleRuleMotionClasses };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run an expensive side effect for the LAST value of a burst, never for the ones it superseded.
|
|
3
|
+
*
|
|
4
|
+
* Here rather than in the app because coalescing is not a property of any one derivation: one user
|
|
5
|
+
* gesture reaches a config holder several times — an edit lands optimistically, comes back as a
|
|
6
|
+
* realtime echo, then again as the pull that trues up against what the server persisted. Each landing
|
|
7
|
+
* describes the same edit, so a subscriber that recomputes per landing pays for two results nobody
|
|
8
|
+
* ever sees, on the frames the gesture is trying to respond on. That is true of every `onChange`
|
|
9
|
+
* point, so {@link runChangeHooks} owns it and a hook never writes it again.
|
|
10
|
+
*
|
|
11
|
+
* Leading-edge, not a trailing debounce: the first value is handed to `schedule` right away, so a
|
|
12
|
+
* continuous gesture (a drag that writes per tick) keeps painting instead of going dark until it
|
|
13
|
+
* stops. What coalesces is everything that arrives while a run is scheduled or in flight — those
|
|
14
|
+
* collapse into ONE follow-up run carrying the newest value.
|
|
15
|
+
*
|
|
16
|
+
* `run` may be async; a value arriving mid-run waits for it rather than overlapping, which is what
|
|
17
|
+
* keeps an older result from landing after a newer one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function coalesceLatest<T>({ run, schedule, }: {
|
|
20
|
+
readonly run: (value: T) => void | Promise<void>;
|
|
21
|
+
/** When a queued run fires — an idle callback, a timer, immediately. */
|
|
22
|
+
readonly schedule: (fire: () => void) => void;
|
|
23
|
+
}): ((value: T) => void) & {
|
|
24
|
+
cancel: () => void;
|
|
25
|
+
};
|