@yahoo/uds-create-config 4.51.3 → 4.53.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/dist/capture/node-ops.js +1 -11
- package/dist/configs/CanvasConfig.js +5 -1
- package/dist/configs/system.js +6 -0
- package/dist/entities/canvas/node-gestures.d.ts +2 -0
- package/dist/entities/canvas/node-gestures.js +616 -0
- package/dist/{capture → entities/canvas}/node-patches.d.ts +6 -4
- package/dist/{capture → entities/canvas}/node-patches.js +16 -3
- package/dist/entities/system/Component.d.ts +47 -32
- package/dist/entities/system/Component.js +181 -30
- package/dist/entities/system/LinkedSystem.d.ts +10 -3
- package/dist/entities/system/Motion.d.ts +5 -1
- package/dist/entities/system/Motion.js +7 -2
- package/dist/entities/system/component-forwards.d.ts +46 -0
- package/dist/entities/system/component-forwards.js +131 -0
- package/dist/entities/system/token-values.d.ts +9 -1
- package/dist/entities/system/token-values.js +4 -3
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +1 -1
- package/dist/framework/defineSubEntity.d.ts +10 -1
- package/dist/framework/defineSubEntity.js +19 -1
- package/dist/framework/rejection.js +16 -4
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/schemas.js +14 -3
- package/dist/index.d.ts +7 -6
- package/dist/index.js +5 -5
- package/dist/migrations/20261001112308_style_rules_as_list.d.ts +12 -0
- package/dist/migrations/20261001112308_style_rules_as_list.js +8 -0
- package/dist/migrations/20261001130958_motion_exit_and_element_duplicate.d.ts +9 -0
- package/dist/migrations/20261001130958_motion_exit_and_element_duplicate.js +10 -0
- package/dist/migrations/20261001131000_layer_style_and_forward_ops.d.ts +11 -0
- package/dist/migrations/20261001131000_layer_style_and_forward_ops.js +10 -0
- package/dist/spec/slot.d.ts +19 -1
- package/dist/spec/slot.js +49 -11
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -12,9 +12,10 @@ import { TokenClass } from "./Token.js";
|
|
|
12
12
|
import { StoredPreviewCondition } from "../../framework/preview-store.js";
|
|
13
13
|
import { RepeatSpec } from "../../framework/render-spec.js";
|
|
14
14
|
import { AsInput, DefaultsOf, LayerMap, PhantomCallProps, PhantomReadProps, PropMap, RenderArgs, StyleRuleInput } from "./defineComponent.js";
|
|
15
|
-
import { listSlots, namedSlots, slotHostedBy, slotOf } from "../../spec/slot.js";
|
|
15
|
+
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
16
16
|
import { cellAt } from "../../spec/cell.js";
|
|
17
17
|
import { instanceAt } from "../../spec/instance.js";
|
|
18
|
+
import { ForwardOptions, forwardOptions } from "./component-forwards.js";
|
|
18
19
|
import { Config } from "../../framework/Config.js";
|
|
19
20
|
import { z } from "zod";
|
|
20
21
|
|
|
@@ -320,30 +321,6 @@ interface ComponentStyleBody {
|
|
|
320
321
|
* exposes), which no single static type can state — so the bag stays open here. */
|
|
321
322
|
layers?: Record<string, Record<string, unknown> | undefined>;
|
|
322
323
|
}
|
|
323
|
-
declare const StyleRuleDefinition: SubEntityClass<z.ZodType<ComponentStyleBody, unknown, z.core.$ZodTypeInternals<ComponentStyleBody, unknown>>>;
|
|
324
|
-
interface StyleRuleClass extends Named<typeof StyleRuleDefinition> {}
|
|
325
|
-
/**
|
|
326
|
-
* The props a cell previews with, keyed by the condition they hold under the way a style rule is:
|
|
327
|
-
* `*` for every cell, a condition on the component's own props for some. `when` names those props,
|
|
328
|
-
* so a prop rename moves it and a value rename moves the ref it stores; `props` is keyed by prop
|
|
329
|
-
* too, which `Prop.keyedByNameIn` and `VariantValue.namedValuesIn` reach through `preview/*\/props`.
|
|
330
|
-
* Deleting a prop or a value drops the entries conditioned on it.
|
|
331
|
-
*/
|
|
332
|
-
declare const PreviewDefinition: SubEntityClass<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>;
|
|
333
|
-
interface PreviewClass extends Named<typeof PreviewDefinition> {}
|
|
334
|
-
/**
|
|
335
|
-
* One node of an inserted subtree, in the shape the anatomy already stores.
|
|
336
|
-
*
|
|
337
|
-
* An insert takes a whole subtree because inserting one is a single user action: "restore this slot's
|
|
338
|
-
* default" puts back a stack holding a text, and splitting that into one row per node would make one
|
|
339
|
-
* gesture several rows in the changes panel and several things to undo. It is the same reason the op
|
|
340
|
-
* already writes the layer and the node together.
|
|
341
|
-
*
|
|
342
|
-
* Flat, keyed, with `children` as an edge list of keys — because that is what anatomy is, and what a
|
|
343
|
-
* json-render spec is. A nested form would need converting at both ends: the caller holds a flat spec
|
|
344
|
-
* subtree, and the store keeps a flat edge list. Every descendant gets its own layer, for the reason
|
|
345
|
-
* the root does: a thing a person added is added in order to be styled, and `styles` keys on layers.
|
|
346
|
-
*/
|
|
347
324
|
declare const visibilityDefinition: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodPipe<z.ZodObject<{
|
|
348
325
|
not: z.ZodOptional<z.ZodLiteral<true>>;
|
|
349
326
|
eq: z.ZodOptional<z.ZodUnknown>;
|
|
@@ -669,11 +646,11 @@ declare const componentFields: z.ZodObject<{
|
|
|
669
646
|
layers: LayerClass;
|
|
670
647
|
props: z.ZodOptional<PropClass>;
|
|
671
648
|
forwards: z.ZodOptional<ForwardClass>;
|
|
672
|
-
styles: z.ZodOptional<
|
|
649
|
+
styles: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<ComponentStyleBody, unknown, z.core.$ZodTypeInternals<ComponentStyleBody, unknown>>>, z.ZodTransform<Record<string, ComponentStyleBody>, ComponentStyleBody[]>>, SubEntityClass<z.ZodType<ComponentStyleBody, unknown, z.core.$ZodTypeInternals<ComponentStyleBody, unknown>>>]>>;
|
|
673
650
|
renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
674
651
|
anatomy: z.ZodOptional<AnatomyNodeClass>;
|
|
675
652
|
defaultProps: z.ZodOptional<StyleClass>;
|
|
676
|
-
preview: z.ZodOptional<
|
|
653
|
+
preview: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>, z.ZodTransform<Record<string, StoredPreviewCondition>, StoredPreviewCondition[]>>, SubEntityClass<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>]>>;
|
|
677
654
|
file: z.ZodOptional<z.ZodObject<{
|
|
678
655
|
__ref: z.ZodString;
|
|
679
656
|
}, z.core.$strip>>;
|
|
@@ -703,11 +680,11 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
703
680
|
layers: LayerClass;
|
|
704
681
|
props: z.ZodOptional<PropClass>;
|
|
705
682
|
forwards: z.ZodOptional<ForwardClass>;
|
|
706
|
-
styles: z.ZodOptional<
|
|
683
|
+
styles: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<ComponentStyleBody, unknown, z.core.$ZodTypeInternals<ComponentStyleBody, unknown>>>, z.ZodTransform<Record<string, ComponentStyleBody>, ComponentStyleBody[]>>, SubEntityClass<z.ZodType<ComponentStyleBody, unknown, z.core.$ZodTypeInternals<ComponentStyleBody, unknown>>>]>>;
|
|
707
684
|
renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
708
685
|
anatomy: z.ZodOptional<AnatomyNodeClass>;
|
|
709
686
|
defaultProps: z.ZodOptional<StyleClass>;
|
|
710
|
-
preview: z.ZodOptional<
|
|
687
|
+
preview: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>, z.ZodTransform<Record<string, StoredPreviewCondition>, StoredPreviewCondition[]>>, SubEntityClass<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>]>>;
|
|
711
688
|
file: z.ZodOptional<z.ZodObject<{
|
|
712
689
|
__ref: z.ZodString;
|
|
713
690
|
}, z.core.$strip>>;
|
|
@@ -763,6 +740,26 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
763
740
|
}, z.core.$strip>>;
|
|
764
741
|
}, z.core.$strip>;
|
|
765
742
|
};
|
|
743
|
+
readonly 'element-duplicate': {
|
|
744
|
+
readonly input: z.ZodObject<{
|
|
745
|
+
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
746
|
+
key: z.ZodString;
|
|
747
|
+
data: z.ZodPrefault<z.ZodObject<{
|
|
748
|
+
count: z.ZodOptional<z.ZodNumber>;
|
|
749
|
+
}, z.core.$strip>>;
|
|
750
|
+
}, z.core.$strip>;
|
|
751
|
+
};
|
|
752
|
+
readonly 'layer-forward': {
|
|
753
|
+
readonly input: z.ZodObject<{
|
|
754
|
+
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
755
|
+
key: z.ZodString;
|
|
756
|
+
data: z.ZodObject<{
|
|
757
|
+
props: z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodArray<z.ZodString>]>;
|
|
758
|
+
except: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
759
|
+
replace: z.ZodOptional<z.ZodBoolean>;
|
|
760
|
+
}, z.core.$strip>;
|
|
761
|
+
}, z.core.$strip>;
|
|
762
|
+
};
|
|
766
763
|
readonly 'element-delete': {
|
|
767
764
|
readonly input: z.ZodObject<{
|
|
768
765
|
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
@@ -792,6 +789,17 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
792
789
|
}, z.core.$strip>;
|
|
793
790
|
};
|
|
794
791
|
}, {
|
|
792
|
+
/**
|
|
793
|
+
* What each layer can forward, for the layers that render a component with props: every prop its
|
|
794
|
+
* element exposes, whether the layer forwards it now, and why one is blocked (the component
|
|
795
|
+
* declares it, or a sibling layer forwards it). Read before writing `forwards`, so "everything
|
|
796
|
+
* but icon" is a list the caller can spell.
|
|
797
|
+
*/
|
|
798
|
+
readonly forwardable: ({
|
|
799
|
+
config,
|
|
800
|
+
path,
|
|
801
|
+
member
|
|
802
|
+
}: ComputedInput) => Record<string, ForwardOptions>;
|
|
795
803
|
/**
|
|
796
804
|
* The prop names an instance may fill through a spec element's `slots` field — every prop that
|
|
797
805
|
* routes content: a `slot`, or a `forward` whose far end takes content. Resolved over the
|
|
@@ -872,9 +880,14 @@ type ExtensionDefaults<Contract, Delta> = {
|
|
|
872
880
|
type ComponentCreateInput = CreateInput<typeof componentFields>;
|
|
873
881
|
/** `Component.item`'s body: the stored fields, with `styles` also taking the rule list
|
|
874
882
|
* `defineComponent.styles` takes, checked against this item's own layers. */
|
|
875
|
-
type ComponentItemInput<L extends LayerMap> = Omit<
|
|
883
|
+
type ComponentItemInput<L extends LayerMap> = Omit<ComponentRecordInput, 'styles'> & {
|
|
876
884
|
readonly layers: L;
|
|
877
|
-
readonly styles?:
|
|
885
|
+
readonly styles?: ComponentRecordInput['styles'] | readonly StyleRuleInput<L>[];
|
|
886
|
+
};
|
|
887
|
+
/** A component body with its `styles` as the keyed record, so a rule list is checked by
|
|
888
|
+
* {@link ComponentItemInput} against the item's own layers rather than taken unchecked. */
|
|
889
|
+
type ComponentRecordInput = Omit<ComponentCreateInput, 'styles'> & {
|
|
890
|
+
readonly styles?: Exclude<ComponentCreateInput['styles'], readonly unknown[]>;
|
|
878
891
|
};
|
|
879
892
|
/**
|
|
880
893
|
* Component keeps the generic entity surface, plus the questions only a component answers: its
|
|
@@ -887,12 +900,14 @@ interface ComponentClass extends Omit<typeof ComponentEntity, 'ref' | 'item'> {
|
|
|
887
900
|
/** One component. `styles` takes the stored record or the rule list `defineComponent.styles`
|
|
888
901
|
* takes, and a list is stored as the record. */
|
|
889
902
|
item<const L extends LayerMap>(def: ComponentItemInput<L>): ComponentCreateInput;
|
|
890
|
-
item(def:
|
|
903
|
+
item(def: ComponentRecordInput | string | number | Ref$1): ComponentCreateInput | string | number | Ref$1;
|
|
891
904
|
ref<const Path extends PathOf<'component'>>(path: Path): ComponentReference<ComponentContractOf<Path>, Path>;
|
|
892
905
|
slots: typeof listSlots;
|
|
893
906
|
slot: typeof slotOf;
|
|
894
907
|
slotHostedBy: typeof slotHostedBy;
|
|
895
908
|
namedSlots: typeof namedSlots;
|
|
909
|
+
slotsFor: typeof slotsFor;
|
|
910
|
+
forwardOptions: typeof forwardOptions;
|
|
896
911
|
cell: typeof cellAt;
|
|
897
912
|
instance: typeof instanceAt;
|
|
898
913
|
}
|
|
@@ -5,7 +5,7 @@ import { pathInput } from "../../framework/schemas.js";
|
|
|
5
5
|
import { derivedColor, gradient } from "./color.js";
|
|
6
6
|
import { shadowValue } from "./shadow.js";
|
|
7
7
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
8
|
-
import { defineSubEntity } from "../../framework/defineSubEntity.js";
|
|
8
|
+
import { defineSubEntity, orList } from "../../framework/defineSubEntity.js";
|
|
9
9
|
import { childrenPolicy, forwardedPropName } from "./element.js";
|
|
10
10
|
import { listedIn } from "../../framework/utils/enumerated.js";
|
|
11
11
|
import { valueSchemaOf } from "../../framework/value-domain.js";
|
|
@@ -16,9 +16,10 @@ import { storedPreview } from "../../framework/preview-store.js";
|
|
|
16
16
|
import { glyphPropsOf, propOwner, propValueDomain, refListOf, resolveComponentProps, stylePropValueLeaves, validateComponentProps } from "../../framework/projections.js";
|
|
17
17
|
import { carriesContent, intoName, isValueSlot, renderBoundProp, routedPropIn, routesContent } from "../../framework/prop-surface.js";
|
|
18
18
|
import { slotAnatomyPropOf, slotTargetsOf, withoutTruthyTerm } from "../../framework/render-spec.js";
|
|
19
|
-
import { listSlots, namedSlots, slotHostedBy, slotOf } from "../../spec/slot.js";
|
|
19
|
+
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
20
20
|
import { cellAt } from "../../spec/cell.js";
|
|
21
21
|
import { instanceAt } from "../../spec/instance.js";
|
|
22
|
+
import { forwardOptions, forwardsWrite } from "./component-forwards.js";
|
|
22
23
|
import { File } from "./File.js";
|
|
23
24
|
import { forwardRouteInvariants, refusedRoutes } from "./forward-route-invariants.js";
|
|
24
25
|
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
@@ -275,6 +276,11 @@ const ForwardDefinition = defineSubEntity({
|
|
|
275
276
|
input: entry,
|
|
276
277
|
message: `"${name}" is not a prop of layer "${key}"'s element (${pathOf(element.__ref)}).`
|
|
277
278
|
});
|
|
279
|
+
if (name && body.props?.[name] != null) ctx.issues.push({
|
|
280
|
+
code: "custom",
|
|
281
|
+
input: entry,
|
|
282
|
+
message: `"${name}" is declared by the component itself, which wins over a forward.`
|
|
283
|
+
});
|
|
278
284
|
}
|
|
279
285
|
const mine = forwardedNames(config, element, ctx.value);
|
|
280
286
|
if (!mine) return;
|
|
@@ -934,18 +940,18 @@ function composedCreateExample(config, path) {
|
|
|
934
940
|
props: { name: "children" }
|
|
935
941
|
}
|
|
936
942
|
},
|
|
937
|
-
...Object.keys(styleLayers).length ? { styles: {
|
|
943
|
+
...Object.keys(styleLayers).length ? { styles: [{
|
|
938
944
|
when: null,
|
|
939
945
|
layers: styleLayers
|
|
940
|
-
} }
|
|
941
|
-
preview:
|
|
946
|
+
}] } : {},
|
|
947
|
+
preview: [{
|
|
942
948
|
when: null,
|
|
943
949
|
props: {
|
|
944
950
|
icon: true,
|
|
945
951
|
label: "Example",
|
|
946
952
|
children: "Body text"
|
|
947
953
|
}
|
|
948
|
-
}
|
|
954
|
+
}]
|
|
949
955
|
}
|
|
950
956
|
};
|
|
951
957
|
}
|
|
@@ -983,7 +989,7 @@ function rendersLayer(element, key) {
|
|
|
983
989
|
return typeof element === "object" && element !== null && "$state" in element && element.layer === key;
|
|
984
990
|
}
|
|
985
991
|
/** The shape of a rule, for a bag written where the rule belongs or a rule with no `layers`. */
|
|
986
|
-
const ruleShapeError = (issue) => issue.code === "invalid_type" || issue.code === "unrecognized_keys" ? "a style rule is `{ \"when\": null, \"layers\": { \"<layer>\": { \"<styleProp>\": \"<value>\" } } }`
|
|
992
|
+
const ruleShapeError = (issue) => issue.code === "invalid_type" || issue.code === "unrecognized_keys" ? "a style rule is `{ \"when\": null, \"layers\": { \"<layer>\": { \"<styleProp>\": \"<value>\" } } }` for the unconditional rule, or with `\"when\": { \"<prop>\": \"<value>\" }` for a variant, and `styles` is a list of them; the layer bags sit under `layers`, never directly under the rule" : void 0;
|
|
987
993
|
/** Whether a rule declares nothing: no `layers`, or every bag empty. A rule is its declarations, so
|
|
988
994
|
* such a rule emits no CSS and styles no layer. */
|
|
989
995
|
function ruleStylesNothing(rule) {
|
|
@@ -1048,7 +1054,7 @@ function perOwner({ cache, config, owner, build }) {
|
|
|
1048
1054
|
return schema;
|
|
1049
1055
|
}
|
|
1050
1056
|
const ruleSchemas = /* @__PURE__ */ new WeakMap();
|
|
1051
|
-
const PREVIEW_DESCRIPTION = "What the catalogue tile and the matrix render with,
|
|
1057
|
+
const PREVIEW_DESCRIPTION = "What the catalogue tile and the matrix render with: a list of entries, each identified by its condition the way a style rule is. The entry `{ \"when\": null, \"props\": { ... } }` is what every cell starts from; an entry with a condition, `{ \"when\": { \"type\": \"image\" }, \"props\": { \"src\": \"…\" } }`, adds its props to the cells whose values match, in the grammar a style rule uses. A slot prop previews with a stored element, `{ \"element\": { \"__ref\": \"component:<Name>\" } }`. A condition on a prop no rule styles makes that prop a preview axis with the value named. A component whose root takes children renders empty until an entry or `defaultProps` carries some.";
|
|
1052
1058
|
const previewShapeError = "a preview entry is `{ \"when\": null | { \"<prop>\": \"<value>\" }, \"props\": { \"<prop>\": <value> } }`: `when` names this component's own props at one of their values (`null` for the entry every cell reads) and `props` the props the matching cells preview with.";
|
|
1053
1059
|
const previewBase = z.object({
|
|
1054
1060
|
when: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
@@ -1534,7 +1540,7 @@ const componentFields = z.strictObject({
|
|
|
1534
1540
|
* forwards nothing rather than being quietly translated.
|
|
1535
1541
|
*/
|
|
1536
1542
|
forwards: Forward.optional(),
|
|
1537
|
-
styles: StyleRule.optional(),
|
|
1543
|
+
styles: orList(StyleRule).optional(),
|
|
1538
1544
|
/** The props the render reads that the component neither declares nor forwards — its render
|
|
1539
1545
|
* extras (`.render<{ swatchColor?: string }>()`). Read off the render at build like `anatomy`,
|
|
1540
1546
|
* never authored as data. The module consumes them; a component painted out of its anatomy has
|
|
@@ -1544,7 +1550,7 @@ const componentFields = z.strictObject({
|
|
|
1544
1550
|
defaultProps: Style.optional(),
|
|
1545
1551
|
/** What the tile and the matrix render with — see `preview({ defaultProps, when })`. Read off
|
|
1546
1552
|
* `.preview()` at build, and written per cell from the matrix. */
|
|
1547
|
-
preview: Preview.optional().describe(PREVIEW_DESCRIPTION),
|
|
1553
|
+
preview: orList(Preview).optional().describe(PREVIEW_DESCRIPTION),
|
|
1548
1554
|
/**
|
|
1549
1555
|
* The source that implements this component — a ref, because the file is an entity the seal owns.
|
|
1550
1556
|
*
|
|
@@ -1671,31 +1677,52 @@ const ComponentEntity = defineEntity({
|
|
|
1671
1677
|
anatomy: AnatomyNode,
|
|
1672
1678
|
defaultProps: Style
|
|
1673
1679
|
},
|
|
1674
|
-
computed: {
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1680
|
+
computed: {
|
|
1681
|
+
/**
|
|
1682
|
+
* What each layer can forward, for the layers that render a component with props: every prop its
|
|
1683
|
+
* element exposes, whether the layer forwards it now, and why one is blocked (the component
|
|
1684
|
+
* declares it, or a sibling layer forwards it). Read before writing `forwards`, so "everything
|
|
1685
|
+
* but icon" is a list the caller can spell.
|
|
1686
|
+
*/
|
|
1687
|
+
forwardable: ({ config, path, member }) => {
|
|
1688
|
+
const out = {};
|
|
1689
|
+
const body = member;
|
|
1690
|
+
for (const layer of Object.keys(body.layers ?? {})) {
|
|
1691
|
+
const options = forwardOptions({
|
|
1692
|
+
config,
|
|
1693
|
+
path,
|
|
1694
|
+
layer,
|
|
1695
|
+
member: body
|
|
1696
|
+
});
|
|
1697
|
+
if (options) out[layer] = options;
|
|
1698
|
+
}
|
|
1699
|
+
return out;
|
|
1700
|
+
},
|
|
1701
|
+
/**
|
|
1702
|
+
* The prop names an instance may fill through a spec element's `slots` field — every prop that
|
|
1703
|
+
* routes content: a `slot`, or a `forward` whose far end takes content. Resolved over the
|
|
1704
|
+
* inheritance chain, since an inherited slot is as fillable as a declared one. This is the
|
|
1705
|
+
* `slots: string[]` json-render's catalog metadata declares per component, computed here so the
|
|
1706
|
+
* emitted catalog, the validator, and every picker read one answer.
|
|
1707
|
+
*/
|
|
1708
|
+
slots: ({ config, path, member }) => {
|
|
1709
|
+
const layers = member.layers;
|
|
1710
|
+
const names = [];
|
|
1711
|
+
for (const [name, decl] of Object.entries(resolveComponentProps(config, path))) {
|
|
1712
|
+
const body = decl;
|
|
1713
|
+
if (!body) continue;
|
|
1714
|
+
if (carriesContent(config, layers, body)) names.push(name);
|
|
1715
|
+
}
|
|
1716
|
+
return names;
|
|
1689
1717
|
}
|
|
1690
|
-
|
|
1691
|
-
} },
|
|
1718
|
+
},
|
|
1692
1719
|
nameEdges: bagNameEdges(componentBags),
|
|
1693
1720
|
styleBags: componentBags,
|
|
1694
1721
|
rewriteName: bagRewriteName(componentBags),
|
|
1695
1722
|
schemas: {
|
|
1696
1723
|
create: {
|
|
1697
1724
|
data: componentFields,
|
|
1698
|
-
description: "Create a component at a new qualified `path`. For a component with nothing in it yet, one to design on the canvas before it has props or variants, use `create-blank` with only a `path` instead of authoring a minimal body here. When its complete body is known, include all layers, anatomy, props, defaults, and styles in this one operation. `data.layers` maps each stable layer name to the element it renders and must include `root` — a tag for a primitive (`{ \"layers\": { \"root\": \"div\" } }`), and for anything built on top, a ref to a primitive (`{ \"root\": { \"__ref\": \"component:Box\" }, \"label\": { \"__ref\": \"component:Text\" } }`), which is what lets the layer take that primitive's style props. A primitive exposes style props as `{ \"type\": \"styleProperty\", \"value\": { \"__ref\": \"style-property:bg\" } }` and declares `children: { \"type\": \"slot\", \"text\": true }` when it holds content — without the slot, nothing nested inside it renders. A composed component exposes a layer's props at its own top level through `forwards`, keyed by layer: `{ \"forwards\": { \"root\": \"*\" } }` passes every prop the root's element takes (so `<Button width=\"full\">` reaches the root's `width`), and a list of member refs (`[{ \"__ref\": \"component:Box#props/width\" }]`, each naming the component that declares the prop) passes only those. A prop a layer already exposes is forwarded, never redeclared in `props`; a `props` entry of `{ \"type\": \"forward\" }` is the reverse route, one of this component's props into a layer's. `anatomy` is the tree the build would read off a render: each node renders a layer (`{ \"__ref\": \"layer:<name>\" }`), an intrinsic tag, or `Slot` (`{ \"element\": \"Slot\", \"props\": { \"name\": \"children\" } }`, where a slot prop's content lands — but a declared slot fills `root` by default, so a primitive still declares its `children` slot prop yet needs no `Slot` node or `children` entry for it, and a `Slot` node is only for landing that content in a nested layer); `children` lists sibling node keys from the `root` node, never a prop name; `text` is a fixed string; `visible` is a condition on a prop (`{ \"$state\": \"<prop>\" }`, or with `eq`); content shown in a nested layer is a route, `children: { \"type\": \"forward\", \"target\": \"label/children\" }`. `$state` appears only in `visible` and in an `element` a prop chooses, never as a prop value. A glyph is a node of its own, `{ \"element\": { \"__ref\": \"icon:<library>/<Name>\" } }`, listed in the `children` of the layer node that holds it, never a prop value. Text a prop supplies to a text layer is never a node either: declare the prop `{ \"type\": \"forward\", \"target\": \"<layer>/children\" }` and the layer shows it; a `Slot` node goes only under a layer that takes nodes.
|
|
1725
|
+
description: "Create a component at a new qualified `path`. For a component with nothing in it yet, one to design on the canvas before it has props or variants, use `create-blank` with only a `path` instead of authoring a minimal body here. When its complete body is known, include all layers, anatomy, props, defaults, and styles in this one operation. `data.layers` maps each stable layer name to the element it renders and must include `root` — a tag for a primitive (`{ \"layers\": { \"root\": \"div\" } }`), and for anything built on top, a ref to a primitive (`{ \"root\": { \"__ref\": \"component:Box\" }, \"label\": { \"__ref\": \"component:Text\" } }`), which is what lets the layer take that primitive's style props. A primitive exposes style props as `{ \"type\": \"styleProperty\", \"value\": { \"__ref\": \"style-property:bg\" } }` and declares `children: { \"type\": \"slot\", \"text\": true }` when it holds content — without the slot, nothing nested inside it renders. A composed component exposes a layer's props at its own top level through `forwards`, keyed by layer: `{ \"forwards\": { \"root\": \"*\" } }` passes every prop the root's element takes (so `<Button width=\"full\">` reaches the root's `width`), and a list of member refs (`[{ \"__ref\": \"component:Box#props/width\" }]`, each naming the component that declares the prop) passes only those. A prop a layer already exposes is forwarded, never redeclared in `props`; a `props` entry of `{ \"type\": \"forward\" }` is the reverse route, one of this component's props into a layer's. `anatomy` is the tree the build would read off a render: each node renders a layer (`{ \"__ref\": \"layer:<name>\" }`), an intrinsic tag, or `Slot` (`{ \"element\": \"Slot\", \"props\": { \"name\": \"children\" } }`, where a slot prop's content lands — but a declared slot fills `root` by default, so a primitive still declares its `children` slot prop yet needs no `Slot` node or `children` entry for it, and a `Slot` node is only for landing that content in a nested layer); `children` lists sibling node keys from the `root` node, never a prop name; `text` is a fixed string; `visible` is a condition on a prop (`{ \"$state\": \"<prop>\" }`, or with `eq`); content shown in a nested layer is a route, `children: { \"type\": \"forward\", \"target\": \"label/children\" }`. `$state` appears only in `visible` and in an `element` a prop chooses, never as a prop value. A glyph is a node of its own, `{ \"element\": { \"__ref\": \"icon:<library>/<Name>\" } }`, listed in the `children` of the layer node that holds it, never a prop value. Text a prop supplies to a text layer is never a node either: declare the prop `{ \"type\": \"forward\", \"target\": \"<layer>/children\" }` and the layer shows it; a `Slot` node goes only under a layer that takes nodes. `styles` is a list of rules, `\"styles\": [{ \"when\": null, \"layers\": { \"root\": { \"bg\": \"surface\" } } }]`, each identified by its `when`, with each layer's bag under `layers`. A composed component carries its own styles: give it an unconditional (`\"when\": null`) rule that lays out and surfaces it through the system's style properties — spacing, alignment and gap on the container, a background and color where it has one — rather than leaning on the bare primitives, which paint flat. Style a layer only with the style props the primitive it renders exposes, set to the values those props accept: `component/get` on the primitive lists both, so read it and choose from that rather than reaching for a CSS name or value the system has no style property for. Set `preview` (`[{ \"when\": null, \"props\": { \"children\": \"Example\" } }]`) or `defaultProps` so the component previews with content; a root that takes children renders empty otherwise. A style rule's layer bag is keyed by style-prop name (`fontWeight`, `color`), never by CSS property name, and each value is one of that prop's values.",
|
|
1699
1726
|
example: ({ config }) => {
|
|
1700
1727
|
const path = freeExamplePath(config);
|
|
1701
1728
|
const composed = composedCreateExample(config, path);
|
|
@@ -1731,10 +1758,10 @@ slots: ({ config, path, member }) => {
|
|
|
1731
1758
|
children: ["icon", "content"]
|
|
1732
1759
|
}
|
|
1733
1760
|
},
|
|
1734
|
-
preview:
|
|
1761
|
+
preview: [{
|
|
1735
1762
|
when: null,
|
|
1736
1763
|
props: { children: "Example" }
|
|
1737
|
-
}
|
|
1764
|
+
}]
|
|
1738
1765
|
}
|
|
1739
1766
|
};
|
|
1740
1767
|
}
|
|
@@ -1956,6 +1983,126 @@ slots: ({ config, path, member }) => {
|
|
|
1956
1983
|
}
|
|
1957
1984
|
},
|
|
1958
1985
|
/**
|
|
1986
|
+
* Copy an element of a composition, with everything beneath it, right after it: each copy gets
|
|
1987
|
+
* layers of its own, and every style rule that styles a copied layer styles its copy the same.
|
|
1988
|
+
* One op for the reason `element-insert` is one: the layers, the nodes, the parent's edge and the
|
|
1989
|
+
* rule bags are one gesture, and any of them alone is a copy that renders wrong.
|
|
1990
|
+
*/
|
|
1991
|
+
"element-duplicate": {
|
|
1992
|
+
input: z.object({
|
|
1993
|
+
path: pathInput("component"),
|
|
1994
|
+
key: z.string(),
|
|
1995
|
+
data: z.object({
|
|
1996
|
+
/** How many copies, each after the last. */
|
|
1997
|
+
count: z.number().int().min(1).max(50).optional() }).prefault({})
|
|
1998
|
+
}),
|
|
1999
|
+
readOnly: false,
|
|
2000
|
+
label: "Duplicate element",
|
|
2001
|
+
description: "Copy an element of a component, with its subtree and its styles, right after it: each copy gets its own layers, and every style rule styling a copied layer styles the copy the same.",
|
|
2002
|
+
scope: "item",
|
|
2003
|
+
creates: true,
|
|
2004
|
+
title: (entity) => `Duplicate ${entity} element`,
|
|
2005
|
+
handler: (input, config) => {
|
|
2006
|
+
const path = String(input.path);
|
|
2007
|
+
const source = String(input.key);
|
|
2008
|
+
const count = input.data?.count ?? 1;
|
|
2009
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
2010
|
+
const anatomy = body?.anatomy ?? {};
|
|
2011
|
+
if (!anatomy[source]) return rejectData(`"${source}" is not an element of ${path}.`, ["key"]);
|
|
2012
|
+
const parentEntry = Object.entries(anatomy).find(([, node]) => [...node.children ?? [], ...Object.values(node.slots ?? {}).flat()].includes(source));
|
|
2013
|
+
if (!parentEntry) return rejectData(`"${source}" is the root of ${path}; it has no place to copy into.`, ["key"]);
|
|
2014
|
+
const [parent, parentNode] = parentEntry;
|
|
2015
|
+
const slotProp = Object.entries(parentNode.slots ?? {}).find(([, fills]) => fills.includes(source))?.[0];
|
|
2016
|
+
const subtree = [];
|
|
2017
|
+
const visit = (at) => {
|
|
2018
|
+
subtree.push(at);
|
|
2019
|
+
const node = anatomy[at];
|
|
2020
|
+
for (const kid of [...node?.children ?? [], ...Object.values(node?.slots ?? {}).flat()]) visit(kid);
|
|
2021
|
+
};
|
|
2022
|
+
visit(source);
|
|
2023
|
+
const elements = Object.fromEntries(subtree.map((at) => {
|
|
2024
|
+
const node = anatomy[at] ?? {};
|
|
2025
|
+
return [at, {
|
|
2026
|
+
element: body?.layers?.[at] ?? "div",
|
|
2027
|
+
...node.props ? { props: node.props } : {},
|
|
2028
|
+
...node.children?.length ? { children: node.children } : {},
|
|
2029
|
+
...node.slots ? { slots: node.slots } : {},
|
|
2030
|
+
...node.visible !== void 0 ? { visible: node.visible } : {},
|
|
2031
|
+
...node.text !== void 0 ? { text: node.text } : {}
|
|
2032
|
+
}];
|
|
2033
|
+
}));
|
|
2034
|
+
let next = config;
|
|
2035
|
+
let previous = source;
|
|
2036
|
+
for (let n = 0; n < count; n++) {
|
|
2037
|
+
const key = freeLayerKey(next, path, source);
|
|
2038
|
+
const siblings = (next.resolve("component", path)?.toJSON())?.anatomy?.[parent]?.children ?? [];
|
|
2039
|
+
const index = siblings.indexOf(previous) + 1;
|
|
2040
|
+
next = next.run([{
|
|
2041
|
+
kind: "component",
|
|
2042
|
+
operation: "element-insert",
|
|
2043
|
+
path,
|
|
2044
|
+
key,
|
|
2045
|
+
data: {
|
|
2046
|
+
parent,
|
|
2047
|
+
...slotProp ? { slotProp } : { index: index > 0 ? index : siblings.length },
|
|
2048
|
+
subtree: {
|
|
2049
|
+
root: source,
|
|
2050
|
+
elements
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
}]);
|
|
2054
|
+
const writes = {};
|
|
2055
|
+
for (const [rule, entry] of Object.entries(body?.styles ?? {})) for (const at of subtree) {
|
|
2056
|
+
const bag = entry.layers?.[at];
|
|
2057
|
+
if (bag === void 0) continue;
|
|
2058
|
+
const copy = at === source ? key : graftKey(key, at);
|
|
2059
|
+
writes[`styles.${rule}.layers.${copy}`] = bag;
|
|
2060
|
+
}
|
|
2061
|
+
if (Object.keys(writes).length > 0) next = next.apply({
|
|
2062
|
+
kind: "component",
|
|
2063
|
+
operation: "update",
|
|
2064
|
+
path,
|
|
2065
|
+
data: writes
|
|
2066
|
+
});
|
|
2067
|
+
previous = key;
|
|
2068
|
+
}
|
|
2069
|
+
return next;
|
|
2070
|
+
}
|
|
2071
|
+
},
|
|
2072
|
+
/**
|
|
2073
|
+
* Make a layer forward the props a request names. The stored write is the generic `forwards`
|
|
2074
|
+
* `sub-upsert` or `sub-delete`; this op works out which, from what the layer forwards now.
|
|
2075
|
+
*/
|
|
2076
|
+
"layer-forward": {
|
|
2077
|
+
input: z.object({
|
|
2078
|
+
path: pathInput("component"),
|
|
2079
|
+
/** The layer whose element's props are forwarded. */
|
|
2080
|
+
key: z.string(),
|
|
2081
|
+
data: z.object({
|
|
2082
|
+
/** Every prop the layer can forward, or the ones to add to what it forwards now. */
|
|
2083
|
+
props: z.union([z.literal("*"), z.array(z.string().min(1))]),
|
|
2084
|
+
/** Props to leave out of either. */
|
|
2085
|
+
except: z.array(z.string().min(1)).optional(),
|
|
2086
|
+
/** Forward exactly `props`, dropping what the layer forwards now. */
|
|
2087
|
+
replace: z.boolean().optional()
|
|
2088
|
+
})
|
|
2089
|
+
}),
|
|
2090
|
+
readOnly: false,
|
|
2091
|
+
label: "Forward layer props",
|
|
2092
|
+
description: "Expose a layer's props at the component's top level (\"forward everything from the root but icon\", \"also forward width\"): `props` is `\"*\"` for every prop the layer's element takes, or a list added to what the layer forwards now, or that replaces it with `replace`; `except` leaves props out of either. A prop the element lacks, one the component declares itself, and one a sibling layer already forwards are refused. Read `component/get` for what a layer forwards now.",
|
|
2093
|
+
scope: "item",
|
|
2094
|
+
title: (entity) => `Forward ${entity} layer props`,
|
|
2095
|
+
handler: (input, config) => {
|
|
2096
|
+
const patch = forwardsWrite({
|
|
2097
|
+
config,
|
|
2098
|
+
path: String(input.path),
|
|
2099
|
+
layer: String(input.key),
|
|
2100
|
+
request: input.data
|
|
2101
|
+
});
|
|
2102
|
+
return patch ? config.apply(patch) : config;
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2105
|
+
/**
|
|
1959
2106
|
* Remove an element from a composition — the node, its layer, and everything that named it.
|
|
1960
2107
|
*
|
|
1961
2108
|
* A custom op for the same reason `element-insert` is: it writes more than one thing and either
|
|
@@ -2271,6 +2418,10 @@ const Component = Object.assign(ComponentEntity, {
|
|
|
2271
2418
|
slotHostedBy,
|
|
2272
2419
|
/** The named node slots alone, without a positioned `children`. */
|
|
2273
2420
|
namedSlots,
|
|
2421
|
+
/** Every component slot whose `accepts` names an element. */
|
|
2422
|
+
slotsFor,
|
|
2423
|
+
/** What one layer can forward, and why a prop is blocked. */
|
|
2424
|
+
forwardOptions,
|
|
2274
2425
|
/** The component under one coordinate of its matrix. */
|
|
2275
2426
|
cell: cellAt,
|
|
2276
2427
|
/** The component a design file's spec element places, with what the file put in its slots. */
|
|
@@ -248,9 +248,11 @@ type PinComponentAdjustment<E, P extends string> = {
|
|
|
248
248
|
type PinComponentBody<E, P extends string> = Omit<PartialBodyOf<E>, 'styles'> & {
|
|
249
249
|
styles?: StoredStylesOf<PartialBodyOf<E>> | PinStyleRules<P>;
|
|
250
250
|
};
|
|
251
|
+
/** The keyed record a body's `styles` is stored as, so a rule list is checked by
|
|
252
|
+
* {@link PinStyleRules} against the linked component's layers rather than taken unchecked. */
|
|
251
253
|
type StoredStylesOf<Body> = Body extends {
|
|
252
254
|
styles?: infer Styles;
|
|
253
|
-
} ? Styles : never;
|
|
255
|
+
} ? Exclude<Styles, readonly unknown[]> : never;
|
|
254
256
|
/** The linked contracts registered at `path`, from whichever source. */
|
|
255
257
|
type LinkedContractKey<P extends string> = Extract<keyof RegisteredComponentContracts, `${P}@${string}`>;
|
|
256
258
|
type PinStyleRules<P extends string> = [LinkedContractKey<P>] extends [never] ? readonly StyleRuleInput<LayerMap>[] : ContractStyleRules<RegisteredComponentContracts[LinkedContractKey<P>]>;
|
|
@@ -259,10 +261,15 @@ type LinkDeclaration = '*' | Record<string, '*' | readonly string[]>;
|
|
|
259
261
|
/** One `options` entry, checked against the kind its accessor addresses. The runtime floor — that an
|
|
260
262
|
* entry names at least one of the three — is the schema's `refine`, which reports the path. */
|
|
261
263
|
type PinAdjustment<E> = {
|
|
262
|
-
override?: PartialBodyOf<E
|
|
263
|
-
extend?: PartialBodyOf<E
|
|
264
|
+
override?: StoredBodyOf<PartialBodyOf<E>>;
|
|
265
|
+
extend?: StoredBodyOf<PartialBodyOf<E>>;
|
|
264
266
|
hidden?: boolean;
|
|
265
267
|
};
|
|
268
|
+
/** A body with its `styles` as the keyed record it is stored as. A rule list is taken only where
|
|
269
|
+
* {@link PinOptionsInput} checks it against the linked component's layers. */
|
|
270
|
+
type StoredBodyOf<Body> = 'styles' extends keyof Body ? Omit<Body, 'styles'> & {
|
|
271
|
+
styles?: StoredStylesOf<Body>;
|
|
272
|
+
} : Body;
|
|
266
273
|
/**
|
|
267
274
|
* One `options` entry as stored — what this config does to that path, with the two bodies left open.
|
|
268
275
|
*
|
|
@@ -3,6 +3,9 @@ import { Named } from "../../framework/named.js";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region src/entities/system/Motion.d.ts
|
|
6
|
+
/** The fields of a JS preset that `motion.create` reads as props, in schema order. The emitter
|
|
7
|
+
* reads this rather than restating the schema, so a field added here reaches every emitted preset. */
|
|
8
|
+
declare const jsMotionPropFields: readonly string[];
|
|
6
9
|
declare const MotionDefinition: EntityClass<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
7
10
|
runtime: z.ZodLiteral<"css">;
|
|
8
11
|
keyframes: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -16,6 +19,7 @@ declare const MotionDefinition: EntityClass<z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
16
19
|
runtime: z.ZodLiteral<"js">;
|
|
17
20
|
initial: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
18
21
|
animate: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
22
|
+
exit: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
19
23
|
transition: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
20
24
|
whileHover: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
21
25
|
whileTap: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -28,4 +32,4 @@ declare const MotionDefinition: EntityClass<z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
28
32
|
interface MotionClass extends Named<typeof MotionDefinition> {}
|
|
29
33
|
declare const Motion: MotionClass;
|
|
30
34
|
//#endregion
|
|
31
|
-
export { Motion, MotionClass };
|
|
35
|
+
export { Motion, MotionClass, jsMotionPropFields };
|
|
@@ -6,7 +6,8 @@ import { z } from "zod";
|
|
|
6
6
|
* coupled to how it animates, not loosely optional:
|
|
7
7
|
* - `css` → `keyframes` REQUIRED (codegen emits `@keyframes` from them); a css preset with
|
|
8
8
|
* no keyframes — which used to validate and silently emit nothing — is now rejected.
|
|
9
|
-
* - `js` → no keyframes; carries the interaction state the client drives
|
|
9
|
+
* - `js` → no keyframes; carries the interaction state the client drives, `exit` included,
|
|
10
|
+
* which runs under an `AnimatePresence` ancestor when the element unmounts.
|
|
10
11
|
* Illegal cross-runtime mixes (a css preset with `animate`, a js preset with `keyframes`)
|
|
11
12
|
* can't be represented — each member is strict.
|
|
12
13
|
*
|
|
@@ -30,6 +31,7 @@ const JsMotion = z.strictObject({
|
|
|
30
31
|
runtime: z.literal("js").describe(RUNTIME),
|
|
31
32
|
initial: gesture.describe("The starting values, as `motion/react` reads them."),
|
|
32
33
|
animate: gesture.describe("The values to animate to."),
|
|
34
|
+
exit: gesture.describe("The values to animate to as the element leaves."),
|
|
33
35
|
transition: gesture.describe("How the animation moves, such as a spring."),
|
|
34
36
|
whileHover: gesture.describe("Values held while the element is hovered."),
|
|
35
37
|
whileTap: gesture.describe("Values held while the element is pressed."),
|
|
@@ -39,6 +41,9 @@ const JsMotion = z.strictObject({
|
|
|
39
41
|
dragConstraints: z.record(z.string(), z.number()).optional().describe("The box a drag stays within."),
|
|
40
42
|
dragElastic: z.number().optional().describe("How far past its constraints a drag can stretch.")
|
|
41
43
|
});
|
|
44
|
+
/** The fields of a JS preset that `motion.create` reads as props, in schema order. The emitter
|
|
45
|
+
* reads this rather than restating the schema, so a field added here reaches every emitted preset. */
|
|
46
|
+
const jsMotionPropFields = Object.keys(JsMotion.shape).filter((field) => field !== "runtime");
|
|
42
47
|
const Motion = defineEntity({
|
|
43
48
|
kind: "motion",
|
|
44
49
|
label: "Motion",
|
|
@@ -46,4 +51,4 @@ const Motion = defineEntity({
|
|
|
46
51
|
fields: z.discriminatedUnion("runtime", [CssMotion, JsMotion])
|
|
47
52
|
});
|
|
48
53
|
//#endregion
|
|
49
|
-
export { Motion };
|
|
54
|
+
export { Motion, jsMotionPropFields };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ComponentBody } from "./Component.js";
|
|
2
|
+
import { Config } from "../../framework/Config.js";
|
|
3
|
+
|
|
4
|
+
//#region src/entities/system/component-forwards.d.ts
|
|
5
|
+
/** Why a prop can't be forwarded from a layer: the component declares it itself, which always wins
|
|
6
|
+
* over a forward, or a sibling layer's entry already delivers it. */
|
|
7
|
+
type ForwardBlockedReason = {
|
|
8
|
+
readonly by: 'own';
|
|
9
|
+
} | {
|
|
10
|
+
readonly by: 'layer';
|
|
11
|
+
readonly layer: string;
|
|
12
|
+
};
|
|
13
|
+
/** One prop a layer's element exposes, as a forward from that layer sees it. */
|
|
14
|
+
interface ForwardOption {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/** Whether the layer's `forwards` entry covers it now. */
|
|
17
|
+
readonly forwarded: boolean;
|
|
18
|
+
readonly blocked?: ForwardBlockedReason;
|
|
19
|
+
}
|
|
20
|
+
/** What one layer of a component can forward, and what it forwards now. */
|
|
21
|
+
interface ForwardOptions {
|
|
22
|
+
/** Every prop the layer's element exposes, in name order. */
|
|
23
|
+
readonly options: readonly ForwardOption[];
|
|
24
|
+
/** Whether the layer has a `forwards` entry at all. */
|
|
25
|
+
readonly forwarded: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* What `layer` of the component at `path` can forward. An option the component declares itself, or a
|
|
29
|
+
* sibling layer already delivers, is listed with the reason it's blocked rather than left out. Null
|
|
30
|
+
* when the layer renders a tag, or its element declares no props.
|
|
31
|
+
*/
|
|
32
|
+
declare function forwardOptions(args: {
|
|
33
|
+
config: Config;
|
|
34
|
+
path: string;
|
|
35
|
+
layer: string;
|
|
36
|
+
member?: ComponentBody;
|
|
37
|
+
}): ForwardOptions | null;
|
|
38
|
+
/** What a forward asks for: every prop, or a list that joins what the layer forwards now unless it
|
|
39
|
+
* replaces it, less `except`. */
|
|
40
|
+
interface ForwardRequest {
|
|
41
|
+
readonly props: '*' | readonly string[];
|
|
42
|
+
readonly except?: readonly string[];
|
|
43
|
+
readonly replace?: boolean;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { ForwardBlockedReason, ForwardOption, ForwardOptions, ForwardRequest, forwardOptions };
|