@yahoo/uds-create-config 5.54.0 → 5.55.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture/node-ops.js +1 -1
- package/dist/configs/system.js +2 -0
- package/dist/entities/canvas/node-gestures.js +1 -1
- package/dist/entities/canvas/node-patches.js +1 -1
- package/dist/entities/system/Component.d.ts +5 -2
- package/dist/entities/system/Component.js +142 -16
- package/dist/entities/system/LinkedSystem.js +2 -2
- package/dist/entities/system/Operation.js +1 -1
- package/dist/entities/system/component-forwards.js +1 -1
- package/dist/entities/system/component-module.js +9 -9
- package/dist/entities/system/component-source-fields.js +1 -1
- package/dist/entities/system/component-style-set.js +1 -1
- package/dist/entities/system/conditional-defaults.d.ts +45 -0
- package/dist/entities/system/conditional-defaults.js +142 -0
- package/dist/entities/system/copy-plan.js +1 -1
- package/dist/entities/system/css-motion-reach.js +1 -1
- package/dist/entities/system/defineComponent.d.ts +11 -2
- package/dist/entities/system/defineComponent.js +3 -0
- package/dist/entities/system/link-plan.js +1 -1
- package/dist/entities/system/motion-convert.js +1 -1
- package/dist/entities/system/motion-variants.js +2 -2
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +21 -5
- package/dist/framework/class-names.js +18 -6
- package/dist/framework/default-conditions.d.ts +26 -0
- package/dist/framework/default-conditions.js +35 -0
- package/dist/framework/defineEntity.js +1 -1
- package/dist/framework/inline-sources.js +1 -1
- package/dist/framework/layer-styles.js +25 -3
- package/dist/framework/memo.d.ts +2 -2
- package/dist/framework/memo.js +7 -1
- package/dist/framework/plan.js +1 -1
- package/dist/framework/projections.js +18 -5
- package/dist/framework/prop-surface.d.ts +1 -0
- package/dist/framework/prop-surface.js +13 -0
- package/dist/framework/render-spec.d.ts +3 -16
- package/dist/framework/render-spec.js +10 -2
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/schemas.js +2 -2
- package/dist/framework/source-integrity.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +5 -3
- package/dist/migrations/20261023152030_conditional_defaults.d.ts +6 -0
- package/dist/migrations/20261023152030_conditional_defaults.js +8 -0
- package/dist/spec/bake.js +14 -6
- package/dist/spec/cell.d.ts +2 -1
- package/dist/spec/cell.js +14 -6
- package/dist/spec/detach.js +5 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/capture/node-ops.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "../framework/rejection.js";
|
|
2
1
|
import { pathOf } from "../framework/utils/refs.js";
|
|
2
|
+
import { rejectData } from "../framework/rejection.js";
|
|
3
3
|
import { pathInput } from "../framework/schemas.js";
|
|
4
4
|
import { CapturedNode } from "./captured-tree.js";
|
|
5
5
|
import { specFromCapture } from "./capture-to-spec.js";
|
package/dist/configs/system.js
CHANGED
|
@@ -29,6 +29,7 @@ import { lintSettingsMigration } from "../migrations/20261020183330_lint_setting
|
|
|
29
29
|
import { directLayerCompositesMigration } from "../migrations/20261022124223_direct_layer_composites.js";
|
|
30
30
|
import { cssContentScriptsMigration } from "../migrations/20261022152120_css_content_scripts.js";
|
|
31
31
|
import { linkTypeMigration } from "../migrations/20261022184639_link_type.js";
|
|
32
|
+
import { conditionalDefaultsMigration } from "../migrations/20261023152030_conditional_defaults.js";
|
|
32
33
|
import { CanvasRole } from "../entities/system/CanvasRole.js";
|
|
33
34
|
import { GlobalStyle } from "../entities/system/GlobalStyle.js";
|
|
34
35
|
import { Guidance } from "../entities/system/Guidance.js";
|
|
@@ -191,5 +192,6 @@ if (!registeredSchemaMigrations().has(20261020183330)) {
|
|
|
191
192
|
}
|
|
192
193
|
if (!registeredSchemaMigrations().has(20261022152120)) registerSchemaMigrations(cssContentScriptsMigration);
|
|
193
194
|
if (!registeredSchemaMigrations().has(20261022184639)) registerSchemaMigrations(linkTypeMigration);
|
|
195
|
+
if (!registeredSchemaMigrations().has(20261023152030)) registerSchemaMigrations(conditionalDefaultsMigration);
|
|
194
196
|
//#endregion
|
|
195
197
|
export { System };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "../../framework/rejection.js";
|
|
2
1
|
import { pathOf, ref } from "../../framework/utils/refs.js";
|
|
2
|
+
import { rejectData } from "../../framework/rejection.js";
|
|
3
3
|
import { pathInput } from "../../framework/schemas.js";
|
|
4
4
|
import { childrenPolicy } from "../system/element.js";
|
|
5
5
|
import { surfaceProps } from "../../framework/prop-surface.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "../../framework/rejection.js";
|
|
2
1
|
import { ref } from "../../framework/utils/refs.js";
|
|
2
|
+
import { rejectData } from "../../framework/rejection.js";
|
|
3
3
|
//#region src/entities/canvas/node-patches.ts
|
|
4
4
|
/**
|
|
5
5
|
* A spec as the node rows of one new placed node. A placed node's content is its subtree rows, one
|
|
@@ -9,10 +9,11 @@ import { Named } from "../../framework/named.js";
|
|
|
9
9
|
import { PackageClass } from "./Package.js";
|
|
10
10
|
import { StyleClass } from "./style-bag.js";
|
|
11
11
|
import { TokenClass } from "./Token.js";
|
|
12
|
+
import { StoredDefaultCondition } from "../../framework/default-conditions.js";
|
|
12
13
|
import { StoredPreviewCondition } from "../../framework/preview-store.js";
|
|
13
14
|
import { RepeatSpec } from "../../framework/render-spec.js";
|
|
14
15
|
import { ComponentSourceInput } from "./component-source-fields.js";
|
|
15
|
-
import { AsInput,
|
|
16
|
+
import { AsInput, AuthoredDefaultsOf, LayerMap, PhantomCallProps, PhantomReadProps, PropMap, RenderArgs, StateMap, StyleRuleInput } from "./defineComponent.js";
|
|
16
17
|
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
17
18
|
import { cellAt } from "../../spec/cell.js";
|
|
18
19
|
import { instanceAt } from "../../spec/instance.js";
|
|
@@ -658,6 +659,7 @@ declare const componentFields: z.ZodObject<{
|
|
|
658
659
|
renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
659
660
|
anatomy: z.ZodOptional<AnatomyNodeClass>;
|
|
660
661
|
defaultProps: z.ZodOptional<StyleClass>;
|
|
662
|
+
defaultPropsWhen: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>, z.ZodTransform<Record<string, StoredDefaultCondition>, StoredDefaultCondition[]>>, SubEntityClass<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>]>>;
|
|
661
663
|
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>>>]>>;
|
|
662
664
|
file: z.ZodOptional<z.ZodObject<{
|
|
663
665
|
__ref: z.ZodString;
|
|
@@ -699,6 +701,7 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
699
701
|
renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
700
702
|
anatomy: z.ZodOptional<AnatomyNodeClass>;
|
|
701
703
|
defaultProps: z.ZodOptional<StyleClass>;
|
|
704
|
+
defaultPropsWhen: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>, z.ZodTransform<Record<string, StoredDefaultCondition>, StoredDefaultCondition[]>>, SubEntityClass<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>]>>;
|
|
702
705
|
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>>>]>>;
|
|
703
706
|
file: z.ZodOptional<z.ZodObject<{
|
|
704
707
|
__ref: z.ZodString;
|
|
@@ -954,7 +957,7 @@ type ComponentReference<Contract = ComponentContractOf<string>, Path extends str
|
|
|
954
957
|
/** An extension's `defaultProps`, checked against the props it ends up with the way
|
|
955
958
|
* `defineComponent` checks its own: a declared prop takes its values, and any other key stays open. */
|
|
956
959
|
type ExtensionDefaults<Contract, Delta> = {
|
|
957
|
-
readonly defaultProps?:
|
|
960
|
+
readonly defaultProps?: AuthoredDefaultsOf<ResolvedProps<Contract, Delta>>;
|
|
958
961
|
};
|
|
959
962
|
/**
|
|
960
963
|
* Two style rules with the same condition, as the one rule they are: each layer's bag merged, the
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import "../../configs/platform.js";
|
|
2
|
-
import { reject, rejectData } from "../../framework/rejection.js";
|
|
3
|
-
import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
|
|
4
2
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
3
|
+
import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
|
|
4
|
+
import { storedDefaultConditions } from "../../framework/default-conditions.js";
|
|
5
|
+
import { reject, rejectData } from "../../framework/rejection.js";
|
|
5
6
|
import { pathInput } from "../../framework/schemas.js";
|
|
6
7
|
import { derivedColor, gradient, oklchColor } from "./color.js";
|
|
7
8
|
import { shadowValue } from "./shadow.js";
|
|
@@ -26,6 +27,7 @@ import { instanceAt } from "../../spec/instance.js";
|
|
|
26
27
|
import { forwardOptions, forwardsWrite } from "./component-forwards.js";
|
|
27
28
|
import { assertComponentSourceInput } from "./component-source-fields.js";
|
|
28
29
|
import { checkStyleSet, styleSetEdits } from "./component-style-set.js";
|
|
30
|
+
import { storedDefaults } from "./conditional-defaults.js";
|
|
29
31
|
import { forwardRouteInvariants, refusedRoutes } from "./forward-route-invariants.js";
|
|
30
32
|
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
31
33
|
import { rootLayerInvariants } from "./root-layer-invariants.js";
|
|
@@ -346,8 +348,16 @@ const VariantValue = defineSubEntity({
|
|
|
346
348
|
* which takes its styling with it. */
|
|
347
349
|
deprecated: z.boolean().optional()
|
|
348
350
|
}),
|
|
349
|
-
namedValuesIn: [
|
|
350
|
-
|
|
351
|
+
namedValuesIn: [
|
|
352
|
+
"defaultProps",
|
|
353
|
+
"preview/*/props",
|
|
354
|
+
"defaultPropsWhen/*/props"
|
|
355
|
+
],
|
|
356
|
+
orphans: [
|
|
357
|
+
"styles",
|
|
358
|
+
"preview",
|
|
359
|
+
"defaultPropsWhen"
|
|
360
|
+
]
|
|
351
361
|
});
|
|
352
362
|
/**
|
|
353
363
|
* A variant's domain: the values it owns, a ref that delegates to whatever owns them, or a list of
|
|
@@ -557,8 +567,16 @@ const Prop = defineSubEntity({
|
|
|
557
567
|
namespaces: "value",
|
|
558
568
|
namesMembersOf: { when: "props" },
|
|
559
569
|
subEntities: { value: VariantValue },
|
|
560
|
-
keyedByNameIn: [
|
|
561
|
-
|
|
570
|
+
keyedByNameIn: [
|
|
571
|
+
"defaultProps",
|
|
572
|
+
"preview/*/props",
|
|
573
|
+
"defaultPropsWhen/*/props"
|
|
574
|
+
],
|
|
575
|
+
orphans: [
|
|
576
|
+
"styles",
|
|
577
|
+
"preview",
|
|
578
|
+
"defaultPropsWhen"
|
|
579
|
+
]
|
|
562
580
|
});
|
|
563
581
|
/** {@link Prop}'s per-owner schema. Reached only through the memo in its `fields`. */
|
|
564
582
|
function propSchemaFor(config, owner) {
|
|
@@ -737,6 +755,17 @@ function withNone(value, declaration) {
|
|
|
737
755
|
if (declaration?.required === true) return value;
|
|
738
756
|
return z.union([value, z.literal(false)]);
|
|
739
757
|
}
|
|
758
|
+
/** Optional values build their domain on first use, not while the bag enumerates its keys. */
|
|
759
|
+
function optionalBagValue(build) {
|
|
760
|
+
let schema;
|
|
761
|
+
return z.unknown().transform((input, ctx) => {
|
|
762
|
+
schema ??= build();
|
|
763
|
+
const result = schema.safeParse(input);
|
|
764
|
+
if (result.success) return result.data;
|
|
765
|
+
for (const issue of result.error.issues) ctx.addIssue({ ...issue });
|
|
766
|
+
return z.NEVER;
|
|
767
|
+
}).optional();
|
|
768
|
+
}
|
|
740
769
|
/** One element's bag, built. Reached only through the memo above. */
|
|
741
770
|
function buildBagFor(config, layerElement) {
|
|
742
771
|
const shape = { ...stylePropShape(config) };
|
|
@@ -744,13 +773,15 @@ function buildBagFor(config, layerElement) {
|
|
|
744
773
|
const glyphProps = component ? glyphPropsOf(config, component) : {};
|
|
745
774
|
for (const [name, decl] of Object.entries(component ? resolveComponentProps(config, component) : {})) {
|
|
746
775
|
const forwarded = decl?.type === "forward";
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
776
|
+
shape[name] = optionalBagValue(() => {
|
|
777
|
+
const value = styleBagValue({
|
|
778
|
+
config,
|
|
779
|
+
declaration: decl,
|
|
780
|
+
name,
|
|
781
|
+
glyphLibraries: forwarded ? glyphProps[name] : void 0
|
|
782
|
+
});
|
|
783
|
+
return forwarded ? withNone(value, decl) : value;
|
|
752
784
|
});
|
|
753
|
-
shape[name] = (forwarded ? withNone(value, decl) : value).optional();
|
|
754
785
|
}
|
|
755
786
|
const declared = component ? (config.resolve("component", component)?.toJSON())?.props ?? {} : {};
|
|
756
787
|
for (const [name, decl] of Object.entries(declared)) {
|
|
@@ -801,14 +832,14 @@ function stylePropShape(config) {
|
|
|
801
832
|
const cached = stylePropShapes.get(config);
|
|
802
833
|
if (cached) return cached;
|
|
803
834
|
const shape = {};
|
|
804
|
-
for (const prop of config.list("style-property")) shape[prop.path] = styleBagValue({
|
|
835
|
+
for (const prop of config.list("style-property")) shape[prop.path] = optionalBagValue(() => styleBagValue({
|
|
805
836
|
config,
|
|
806
837
|
declaration: {
|
|
807
838
|
type: "styleProperty",
|
|
808
839
|
value: { __ref: `style-property:${prop.path}` }
|
|
809
840
|
},
|
|
810
841
|
name: prop.path
|
|
811
|
-
})
|
|
842
|
+
}));
|
|
812
843
|
stylePropShapes.set(config, shape);
|
|
813
844
|
return shape;
|
|
814
845
|
}
|
|
@@ -1168,6 +1199,61 @@ const Preview = defineSubEntity({
|
|
|
1168
1199
|
});
|
|
1169
1200
|
}
|
|
1170
1201
|
});
|
|
1202
|
+
const DEFAULT_CONDITIONS_DESCRIPTION = "Defaults that hold only under a condition on this component's other props, laid over `defaultProps` the way a style rule is over the unconditional one: a list of entries, each identified by its condition. `{ \"when\": { \"modal\": false }, \"props\": { \"includeScrim\": false } }` defaults `includeScrim` to `false` while `modal` is `false`, and to its `defaultProps` value otherwise. When several entries hold, the later one wins on the prop it sets. Both sides name the component's own variant, string, number or boolean props, a prop set here is never part of a condition, and a value the call site passes always wins. Authored as `conditionalDefault(fallback, [{ when, value }])` inside `.defaultProps`.";
|
|
1203
|
+
const defaultConditionShapeError = "a conditional default is `{ \"when\": { \"<prop>\": <value> }, \"props\": { \"<prop>\": <value> } }`: both name this component's own variant, string, number or boolean props (not `as`), `when` at one of their values.";
|
|
1204
|
+
const defaultConditionBase = z.object({
|
|
1205
|
+
when: z.record(z.string(), z.unknown()),
|
|
1206
|
+
props: z.record(z.string(), z.unknown())
|
|
1207
|
+
});
|
|
1208
|
+
const defaultConditionSchemas = /* @__PURE__ */ new WeakMap();
|
|
1209
|
+
/** The props a conditional default may set or condition on: the component's own scalar props, the
|
|
1210
|
+
* ones its module binds and tests. `as` decides the element, so it never depends on another prop. */
|
|
1211
|
+
function conditionallyDefaultable(props) {
|
|
1212
|
+
return Object.entries(props ?? {}).filter(([name, decl]) => {
|
|
1213
|
+
const type = decl?.type;
|
|
1214
|
+
return name !== "as" && (type === "variant" || type === "string" || type === "number" || type === "boolean");
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
/** Whether a conditional default sets nothing: its `props` are empty. */
|
|
1218
|
+
function defaultConditionSetsNothing(entry) {
|
|
1219
|
+
const props = entry?.props;
|
|
1220
|
+
return !props || Object.keys(props).length === 0;
|
|
1221
|
+
}
|
|
1222
|
+
const DefaultCondition = defineSubEntity({
|
|
1223
|
+
name: "defaultCondition",
|
|
1224
|
+
label: "Conditional default",
|
|
1225
|
+
labelPlural: "Conditional defaults",
|
|
1226
|
+
key: (entry) => canonicalWhen(entry?.when),
|
|
1227
|
+
vacant: defaultConditionSetsNothing,
|
|
1228
|
+
namesMembersOf: { when: "props" },
|
|
1229
|
+
base: defaultConditionBase,
|
|
1230
|
+
fields: ({ config, parent }) => {
|
|
1231
|
+
const body = parent;
|
|
1232
|
+
if (!config || !body) return defaultConditionBase;
|
|
1233
|
+
return perOwner({
|
|
1234
|
+
cache: defaultConditionSchemas,
|
|
1235
|
+
config,
|
|
1236
|
+
owner: body,
|
|
1237
|
+
build: () => {
|
|
1238
|
+
const styleField = Style.fields;
|
|
1239
|
+
const when = {};
|
|
1240
|
+
const props = {};
|
|
1241
|
+
for (const [name, decl] of conditionallyDefaultable(body.props)) {
|
|
1242
|
+
when[name] = conditionValue(name, decl, config).optional();
|
|
1243
|
+
props[name] = styleField({
|
|
1244
|
+
config,
|
|
1245
|
+
parent: body,
|
|
1246
|
+
key: name
|
|
1247
|
+
}).optional();
|
|
1248
|
+
}
|
|
1249
|
+
return z.strictObject({
|
|
1250
|
+
when: z.strictObject(when, { error: defaultConditionShapeError }).refine((value) => Object.keys(value).length > 0, { error: "a conditional default holds under a condition; an unconditional one belongs in `defaultProps`." }),
|
|
1251
|
+
props: z.strictObject(props, { error: defaultConditionShapeError })
|
|
1252
|
+
}, { error: defaultConditionShapeError });
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1171
1257
|
/** Why a slot refuses an element, for a write the config turns away. */
|
|
1172
1258
|
function slotRefusal({ slot, element }) {
|
|
1173
1259
|
const named = isRef(element) ? element.__ref : String(element);
|
|
@@ -1724,6 +1810,9 @@ const componentFields = z.strictObject({
|
|
|
1724
1810
|
renderProps: z.array(z.string()).optional().describe("Props the render reads beyond those declared, read off the source at build. Not authored: declare a prop in `props` instead."),
|
|
1725
1811
|
anatomy: AnatomyNode.optional().describe("The tree of what this component renders, keyed by node. Each node names what it renders (a layer, for anything a style rule reaches) and lists its `children`; the node keyed `root` is the top. A one-layer component may omit it. Anatomy read from an extension's own source file replaces the inherited tree; edits to a borrowed render merge into its tree."),
|
|
1726
1812
|
defaultProps: Style.optional(),
|
|
1813
|
+
/** The defaults that hold only under a condition on the component's other props — see
|
|
1814
|
+
* `conditionalDefault`. */
|
|
1815
|
+
defaultPropsWhen: orList(DefaultCondition).optional().describe(DEFAULT_CONDITIONS_DESCRIPTION),
|
|
1727
1816
|
/** What the tile and the matrix render with — see `preview({ defaultProps, when })`. Read off
|
|
1728
1817
|
* `.preview()` at build, and written per cell from the matrix. */
|
|
1729
1818
|
preview: orList(Preview).optional().describe(PREVIEW_DESCRIPTION),
|
|
@@ -1769,6 +1858,39 @@ const componentFields = z.strictObject({
|
|
|
1769
1858
|
message: `\`${name}\` conditions on itself. \`when\` names a sibling prop and one of its values.`
|
|
1770
1859
|
});
|
|
1771
1860
|
}
|
|
1861
|
+
const conditions = storedDefaultConditions(body);
|
|
1862
|
+
const defaulted = new Set(Object.values(conditions).flatMap(({ props }) => Object.keys(props ?? {})));
|
|
1863
|
+
const defaultable = new Set(conditionallyDefaultable(body.props).map(([name]) => name));
|
|
1864
|
+
for (const [key, { when, props }] of Object.entries(conditions)) {
|
|
1865
|
+
for (const [field, names] of [["when", Object.keys(when ?? {})], ["props", Object.keys(props ?? {})]]) for (const name of names) {
|
|
1866
|
+
if (defaultable.has(name)) continue;
|
|
1867
|
+
ctx.issues.push({
|
|
1868
|
+
code: "custom",
|
|
1869
|
+
input: field === "when" ? when : props,
|
|
1870
|
+
path: [
|
|
1871
|
+
"defaultPropsWhen",
|
|
1872
|
+
key,
|
|
1873
|
+
field,
|
|
1874
|
+
name
|
|
1875
|
+
],
|
|
1876
|
+
message: `\`${name}\` isn't one of this component's own variant, string, number or boolean props, so a conditional default can't name it. ${defaultConditionShapeError}`
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
for (const name of Object.keys(when ?? {})) {
|
|
1880
|
+
if (!defaulted.has(name)) continue;
|
|
1881
|
+
ctx.issues.push({
|
|
1882
|
+
code: "custom",
|
|
1883
|
+
input: when,
|
|
1884
|
+
path: [
|
|
1885
|
+
"defaultPropsWhen",
|
|
1886
|
+
key,
|
|
1887
|
+
"when",
|
|
1888
|
+
name
|
|
1889
|
+
],
|
|
1890
|
+
message: `\`${name}\` has a conditional default of its own, so it can't be part of a condition. Condition on the props it depends on instead.`
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1772
1894
|
if (isPlainObject(body.states) && Object.keys(body.states).length > 0) {
|
|
1773
1895
|
const props = isPlainObject(body.props) ? body.props : {};
|
|
1774
1896
|
if (Object.hasOwn(props, "states")) ctx.issues.push({
|
|
@@ -1905,7 +2027,8 @@ const ComponentEntity = defineEntity({
|
|
|
1905
2027
|
styles: StyleRule,
|
|
1906
2028
|
preview: Preview,
|
|
1907
2029
|
anatomy: AnatomyNode,
|
|
1908
|
-
defaultProps: Style
|
|
2030
|
+
defaultProps: Style,
|
|
2031
|
+
defaultPropsWhen: DefaultCondition
|
|
1909
2032
|
},
|
|
1910
2033
|
computed: {
|
|
1911
2034
|
/**
|
|
@@ -2846,7 +2969,10 @@ function componentRef(path) {
|
|
|
2846
2969
|
*/
|
|
2847
2970
|
const step = (delta) => {
|
|
2848
2971
|
assertComponentSourceInput(delta);
|
|
2849
|
-
const extended = base.extend(
|
|
2972
|
+
const extended = base.extend({
|
|
2973
|
+
...delta,
|
|
2974
|
+
...storedDefaults(delta)
|
|
2975
|
+
});
|
|
2850
2976
|
Object.defineProperty(extended, "render", {
|
|
2851
2977
|
enumerable: false,
|
|
2852
2978
|
configurable: false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { rejectData } from "../../framework/rejection.js";
|
|
2
|
-
import { isRef, kindOf, pathOf, refSchema } from "../../framework/utils/refs.js";
|
|
3
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { isRef, kindOf, pathOf, refSchema } from "../../framework/utils/refs.js";
|
|
3
|
+
import { rejectData } from "../../framework/rejection.js";
|
|
4
4
|
import { pathInput } from "../../framework/schemas.js";
|
|
5
5
|
import { kindBorrowable } from "../../framework/registry.js";
|
|
6
6
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CONFIG_OPERATION_KIND } from "../../framework/config-operation-kind.js";
|
|
2
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { CONFIG_OPERATION_KIND } from "../../framework/config-operation-kind.js";
|
|
3
3
|
import { resolveInputSchema } from "../../framework/schemas.js";
|
|
4
4
|
import { opsForKind } from "../../framework/registry.js";
|
|
5
5
|
import { opOf } from "../../framework/config-op.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { reject } from "../../framework/rejection.js";
|
|
2
1
|
import { isRef, kindOf, memberRef, pathOf } from "../../framework/utils/refs.js";
|
|
2
|
+
import { reject } from "../../framework/rejection.js";
|
|
3
3
|
import { forwardedPropName } from "./element.js";
|
|
4
4
|
import { propOwner, resolveComponentProps } from "../../framework/projections.js";
|
|
5
5
|
import { forwardClaims } from "../../framework/prop-surface.js";
|
|
@@ -55,7 +55,7 @@ function isCreatedComponent(config, path) {
|
|
|
55
55
|
if (isNativeConfig(config)) return false;
|
|
56
56
|
const component = Component.get(config, path);
|
|
57
57
|
if (!component || component.source !== void 0) return false;
|
|
58
|
-
const { file, export: exportName, anatomy } = component
|
|
58
|
+
const { file, export: exportName, anatomy } = component;
|
|
59
59
|
return !file && !exportName && Object.keys(anatomy ?? {}).length > 0;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
@@ -133,7 +133,7 @@ function componentsByFile(config) {
|
|
|
133
133
|
if (cached) return cached;
|
|
134
134
|
const byFile = /* @__PURE__ */ new Map();
|
|
135
135
|
for (const component of Component.list(config)) {
|
|
136
|
-
const { file, export: exportName } = component
|
|
136
|
+
const { file, export: exportName } = component;
|
|
137
137
|
if (!file || !exportName) continue;
|
|
138
138
|
const ref = splitRef(file.__ref);
|
|
139
139
|
if (ref.source) continue;
|
|
@@ -163,7 +163,7 @@ function componentRegistryImports(config, filePath) {
|
|
|
163
163
|
const byExport = /* @__PURE__ */ new Map();
|
|
164
164
|
const ambiguous = /* @__PURE__ */ new Set();
|
|
165
165
|
for (const component of byFile.get(target.path) ?? []) {
|
|
166
|
-
const { export: exportName } = component
|
|
166
|
+
const { export: exportName } = component;
|
|
167
167
|
if (!exportName) continue;
|
|
168
168
|
if (byExport.has(exportName)) ambiguous.add(exportName);
|
|
169
169
|
byExport.set(exportName, {
|
|
@@ -221,7 +221,8 @@ function componentModuleBuildPlan(config, filePath) {
|
|
|
221
221
|
const parsed = splitRef(target);
|
|
222
222
|
if (parsed.kind !== "component" || parsed.source) return false;
|
|
223
223
|
const component = Component.get(config, parsed.path);
|
|
224
|
-
const
|
|
224
|
+
const file = component?.file;
|
|
225
|
+
const exportName = component?.export;
|
|
225
226
|
if (!component || !file || !exportName) return false;
|
|
226
227
|
const owner = splitRef(file.__ref);
|
|
227
228
|
if (owner.kind !== "file" || owner.source) return false;
|
|
@@ -257,7 +258,7 @@ function componentModuleBuildPlan(config, filePath) {
|
|
|
257
258
|
const file = File.get(config, next);
|
|
258
259
|
if (!file?.hash) continue;
|
|
259
260
|
recordEntity(`file:${next}`);
|
|
260
|
-
const imports = file.
|
|
261
|
+
const imports = file.imports ?? {};
|
|
261
262
|
const registryImports = new Map(componentRegistryImports(config, next).map((entry) => [entry.specifier, entry]));
|
|
262
263
|
for (const [specifier, imported] of Object.entries(imports)) {
|
|
263
264
|
const registryImport = registryImports.get(specifier);
|
|
@@ -305,7 +306,7 @@ function componentModuleSource(config, componentPathOrRef) {
|
|
|
305
306
|
if (isNativeConfig(config)) return void 0;
|
|
306
307
|
const component = Component.get(config, componentPathOrRef);
|
|
307
308
|
if (!component) return void 0;
|
|
308
|
-
const { file, export: exportName } = component
|
|
309
|
+
const { file, export: exportName } = component;
|
|
309
310
|
if (!file || !exportName) {
|
|
310
311
|
if (!isCreatedComponent(config, component.path)) return void 0;
|
|
311
312
|
const moduleKey = createdModuleKey(config, component.path);
|
|
@@ -405,7 +406,7 @@ function cachedView(consumer, owner, slug, shadowed) {
|
|
|
405
406
|
function linkedComponentModule(config, componentPathOrRef) {
|
|
406
407
|
const component = Component.get(config, componentPathOrRef);
|
|
407
408
|
if (!component) return void 0;
|
|
408
|
-
const { file, export: exportName } = component
|
|
409
|
+
const { file, export: exportName } = component;
|
|
409
410
|
if (!file || !exportName) return void 0;
|
|
410
411
|
const asked = typeof componentPathOrRef === "string" ? componentPathOrRef : componentPathOrRef.__ref;
|
|
411
412
|
const parsed = asked.includes(":") ? splitRef(asked) : void 0;
|
|
@@ -422,8 +423,7 @@ function linkedComponentModule(config, componentPathOrRef) {
|
|
|
422
423
|
const moduleKey = componentModuleKey(view, filePath);
|
|
423
424
|
if (!moduleKey) return void 0;
|
|
424
425
|
const authored = Component.list(owner).find((candidate) => {
|
|
425
|
-
|
|
426
|
-
return fields.export === exportName && fields.file !== void 0 && splitRef(fields.file.__ref).path === filePath;
|
|
426
|
+
return candidate.export === exportName && candidate.file !== void 0 && splitRef(candidate.file.__ref).path === filePath;
|
|
427
427
|
});
|
|
428
428
|
return {
|
|
429
429
|
source: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "../../framework/rejection.js";
|
|
2
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { rejectData } from "../../framework/rejection.js";
|
|
3
3
|
//#region src/entities/system/component-source-fields.ts
|
|
4
4
|
/** Source constructors leave these facts to the render extractor and module build.
|
|
5
5
|
* Stored component bodies, including Create drafts, still carry them. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { reject } from "../../framework/rejection.js";
|
|
2
1
|
import { canonicalCondition } from "../../framework/utils/refs.js";
|
|
2
|
+
import { reject } from "../../framework/rejection.js";
|
|
3
3
|
//#region src/entities/system/component-style-set.ts
|
|
4
4
|
/** A modifier as a style bag keys it: its leaf with a leading `_`. */
|
|
5
5
|
function bagKey(modifier) {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StoredDefaultCondition } from "../../framework/default-conditions.js";
|
|
2
|
+
|
|
3
|
+
//#region src/entities/system/conditional-defaults.d.ts
|
|
4
|
+
declare const CONDITIONAL_DEFAULT: unique symbol;
|
|
5
|
+
/** One condition of a {@link ConditionalDefault}: the value the prop defaults to while `when` holds. */
|
|
6
|
+
interface ConditionalDefaultEntry<V = unknown> {
|
|
7
|
+
readonly when: Readonly<Record<string, unknown>>;
|
|
8
|
+
readonly value: V;
|
|
9
|
+
}
|
|
10
|
+
/** A default chosen by the component's other props — see {@link conditionalDefault}. */
|
|
11
|
+
interface ConditionalDefault<V = unknown> {
|
|
12
|
+
readonly [CONDITIONAL_DEFAULT]: true;
|
|
13
|
+
readonly fallback: V;
|
|
14
|
+
readonly entries: readonly ConditionalDefaultEntry<V>[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A default that depends on the component's other props, for `.defaultProps` and
|
|
18
|
+
* `.extend({ defaultProps })` only.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* .defaultProps({
|
|
22
|
+
* modal: true,
|
|
23
|
+
* includeScrim: conditionalDefault(true, [{ when: { modal: false }, value: false }]),
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* `fallback` applies when no entry's `when` holds; when several hold, the later entry wins. A `when`
|
|
28
|
+
* is the grammar a style rule uses, over the component's own props. A value the call site passes
|
|
29
|
+
* still wins over any of it.
|
|
30
|
+
*/
|
|
31
|
+
declare function conditionalDefault<const V>(fallback: V, entries: readonly ConditionalDefaultEntry<V>[]): ConditionalDefault<V>;
|
|
32
|
+
declare function isConditionalDefault(value: unknown): value is ConditionalDefault;
|
|
33
|
+
/**
|
|
34
|
+
* Stored defaults as authored: the inverse of {@link splitConditionalDefaults}, each prop
|
|
35
|
+
* `defaultPropsWhen` names given back as a {@link conditionalDefault} over its fallback.
|
|
36
|
+
*/
|
|
37
|
+
declare function joinConditionalDefaults({
|
|
38
|
+
defaultProps,
|
|
39
|
+
defaultPropsWhen
|
|
40
|
+
}: {
|
|
41
|
+
defaultProps: Readonly<Record<string, unknown>> | undefined;
|
|
42
|
+
defaultPropsWhen: Readonly<Record<string, StoredDefaultCondition>> | undefined;
|
|
43
|
+
}): Record<string, unknown>;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { ConditionalDefault, ConditionalDefaultEntry, conditionalDefault, isConditionalDefault, joinConditionalDefaults };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { canonicalCondition } from "../../framework/utils/refs.js";
|
|
3
|
+
//#region src/entities/system/conditional-defaults.ts
|
|
4
|
+
const CONDITIONAL_DEFAULT = Symbol.for("uds.conditionalDefault");
|
|
5
|
+
/**
|
|
6
|
+
* A default that depends on the component's other props, for `.defaultProps` and
|
|
7
|
+
* `.extend({ defaultProps })` only.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* .defaultProps({
|
|
11
|
+
* modal: true,
|
|
12
|
+
* includeScrim: conditionalDefault(true, [{ when: { modal: false }, value: false }]),
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* `fallback` applies when no entry's `when` holds; when several hold, the later entry wins. A `when`
|
|
17
|
+
* is the grammar a style rule uses, over the component's own props. A value the call site passes
|
|
18
|
+
* still wins over any of it.
|
|
19
|
+
*/
|
|
20
|
+
function conditionalDefault(fallback, entries) {
|
|
21
|
+
return {
|
|
22
|
+
[CONDITIONAL_DEFAULT]: true,
|
|
23
|
+
fallback,
|
|
24
|
+
entries
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function isConditionalDefault(value) {
|
|
28
|
+
return typeof value === "object" && value !== null && value[CONDITIONAL_DEFAULT] === true;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Authored defaults as stored: each {@link conditionalDefault} leaves its fallback in `defaultProps`
|
|
32
|
+
* and its entries in `defaultPropsWhen`. `defaultPropsWhen` is `undefined` when nothing was
|
|
33
|
+
* conditional, so a body without one stores exactly what it did before.
|
|
34
|
+
*
|
|
35
|
+
* Stored by condition, every prop shares one order of conditions, while precedence is per prop. The
|
|
36
|
+
* order taken keeps each prop's own; two props that order the same two conditions oppositely can't
|
|
37
|
+
* share one, and are refused.
|
|
38
|
+
*/
|
|
39
|
+
function splitConditionalDefaults(authored) {
|
|
40
|
+
const defaultProps = {};
|
|
41
|
+
const perProp = /* @__PURE__ */ new Map();
|
|
42
|
+
for (const [prop, value] of Object.entries(authored)) {
|
|
43
|
+
if (!isConditionalDefault(value)) {
|
|
44
|
+
defaultProps[prop] = value;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (value.fallback !== void 0) defaultProps[prop] = value.fallback;
|
|
48
|
+
const entries = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const entry of value.entries) {
|
|
50
|
+
const key = canonicalCondition(entry.when);
|
|
51
|
+
entries.delete(key);
|
|
52
|
+
entries.set(key, entry);
|
|
53
|
+
}
|
|
54
|
+
perProp.set(prop, entries);
|
|
55
|
+
}
|
|
56
|
+
if (perProp.size === 0) return { defaultProps };
|
|
57
|
+
const order = conditionOrder(perProp);
|
|
58
|
+
const defaultPropsWhen = {};
|
|
59
|
+
for (const key of order) {
|
|
60
|
+
let when;
|
|
61
|
+
const props = {};
|
|
62
|
+
for (const [prop, entries] of perProp) {
|
|
63
|
+
const entry = entries.get(key);
|
|
64
|
+
if (!entry) continue;
|
|
65
|
+
when ??= { ...entry.when };
|
|
66
|
+
props[prop] = entry.value;
|
|
67
|
+
}
|
|
68
|
+
if (when) defaultPropsWhen[key] = {
|
|
69
|
+
when,
|
|
70
|
+
props
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
defaultProps,
|
|
75
|
+
defaultPropsWhen
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* `defaultProps` as stored: each `conditionalDefault` splits into its fallback, which stays in
|
|
80
|
+
* `defaultProps`, and its conditions, which go to `defaultPropsWhen`. Empty for a body whose
|
|
81
|
+
* defaults are all plain, so it stores what it did before.
|
|
82
|
+
*/
|
|
83
|
+
function storedDefaults(body) {
|
|
84
|
+
if (!isPlainObject(body.defaultProps)) return {};
|
|
85
|
+
const { defaultProps, defaultPropsWhen } = splitConditionalDefaults(body.defaultProps);
|
|
86
|
+
return defaultPropsWhen ? {
|
|
87
|
+
defaultProps,
|
|
88
|
+
defaultPropsWhen
|
|
89
|
+
} : {};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* One order of every condition that keeps each prop's own order, by first appearance where props
|
|
93
|
+
* don't constrain it.
|
|
94
|
+
*/
|
|
95
|
+
function conditionOrder(perProp) {
|
|
96
|
+
const seen = [];
|
|
97
|
+
const after = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const [prop, entries] of perProp) {
|
|
99
|
+
const keys = [...entries.keys()];
|
|
100
|
+
keys.forEach((key, at) => {
|
|
101
|
+
if (!seen.includes(key)) seen.push(key);
|
|
102
|
+
const earlier = after.get(key) ?? /* @__PURE__ */ new Map();
|
|
103
|
+
for (const before of keys.slice(0, at)) earlier.set(before, prop);
|
|
104
|
+
after.set(key, earlier);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
for (const [key, earlier] of after) for (const [before, prop] of earlier) {
|
|
108
|
+
const other = after.get(before)?.get(key);
|
|
109
|
+
if (other === void 0) continue;
|
|
110
|
+
throw new Error(`\`${prop}\` puts \`${before}\` before \`${key}\` and \`${other}\` puts them the other way round. Conditional defaults share one order of conditions, so give both props the same order.`);
|
|
111
|
+
}
|
|
112
|
+
const order = [];
|
|
113
|
+
const placed = /* @__PURE__ */ new Set();
|
|
114
|
+
const placing = /* @__PURE__ */ new Set();
|
|
115
|
+
const place = (key) => {
|
|
116
|
+
if (placed.has(key)) return;
|
|
117
|
+
if (placing.has(key)) throw new Error(`Conditional defaults order \`${key}\` both before and after another condition across their props. They share one order of conditions, so give every prop the same order.`);
|
|
118
|
+
placing.add(key);
|
|
119
|
+
for (const before of after.get(key)?.keys() ?? []) place(before);
|
|
120
|
+
placing.delete(key);
|
|
121
|
+
placed.add(key);
|
|
122
|
+
order.push(key);
|
|
123
|
+
};
|
|
124
|
+
for (const key of seen) place(key);
|
|
125
|
+
return order;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Stored defaults as authored: the inverse of {@link splitConditionalDefaults}, each prop
|
|
129
|
+
* `defaultPropsWhen` names given back as a {@link conditionalDefault} over its fallback.
|
|
130
|
+
*/
|
|
131
|
+
function joinConditionalDefaults({ defaultProps, defaultPropsWhen }) {
|
|
132
|
+
const out = { ...defaultProps };
|
|
133
|
+
const entries = /* @__PURE__ */ new Map();
|
|
134
|
+
for (const { when, props } of Object.values(defaultPropsWhen ?? {})) for (const [prop, value] of Object.entries(props ?? {})) entries.set(prop, [...entries.get(prop) ?? [], {
|
|
135
|
+
when,
|
|
136
|
+
value
|
|
137
|
+
}]);
|
|
138
|
+
for (const [prop, list] of entries) out[prop] = conditionalDefault(out[prop], list);
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { conditionalDefault, isConditionalDefault, joinConditionalDefaults, storedDefaults };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "../../framework/rejection.js";
|
|
2
1
|
import { MINTED, collectRefs, isMintedRow, kindOf, pathOf, rewriteRefs, sourceOf, splitRef } from "../../framework/utils/refs.js";
|
|
2
|
+
import { rejectData } from "../../framework/rejection.js";
|
|
3
3
|
import { kindBorrowable } from "../../framework/registry.js";
|
|
4
4
|
import { File } from "./File.js";
|
|
5
5
|
import { componentModuleFilePaths, componentRegistryImports } from "./component-module.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
2
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
3
3
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
4
4
|
import { drawnMotionBody, drawnMotionName } from "./drawn-motion.js";
|
|
5
5
|
import { convertMotion } from "./motion-convert.js";
|