@yahoo/uds-create-config 5.57.1 → 5.59.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/authoring/define-component.d.ts +2 -1
- package/dist/entities/system/Component.d.ts +6 -3
- package/dist/entities/system/Component.js +5 -5
- package/dist/entities/system/defineComponent.d.ts +27 -31
- package/dist/entities/system/defineComponent.js +12 -19
- package/dist/entities/system/link-plan.js +2 -1
- package/dist/entities/system/prop-rules.d.ts +10 -0
- package/dist/entities/system/prop-rules.js +42 -0
- package/dist/framework/Config.d.ts +19 -12
- package/dist/framework/Config.js +31 -13
- package/dist/framework/default-conditions.d.ts +28 -1
- package/dist/framework/default-conditions.js +39 -2
- package/dist/framework/projections.d.ts +2 -2
- package/dist/framework/projections.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/entities/system/conditional-defaults.d.ts +0 -67
- package/dist/entities/system/conditional-defaults.js +0 -179
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* The returned handle is a ref AND an `Authored`, so it composes into other components and
|
|
18
18
|
* registers through the generic bridge.
|
|
19
19
|
*/
|
|
20
|
+
import { type PropsOrRules } from '../entities/system/prop-rules';
|
|
20
21
|
import type { Authored } from '../framework/authoring';
|
|
21
22
|
import { type Ref } from '../framework/utils/refs';
|
|
22
23
|
/** A component handle — a ref (import/reference it), an `Authored` (register it), and a
|
|
@@ -69,7 +70,7 @@ interface Body<L, SP extends string, MOD extends string, P extends Record<string
|
|
|
69
70
|
when: Record<string, string>;
|
|
70
71
|
layers: LayerOverrides<L, SP, MOD>;
|
|
71
72
|
}>;
|
|
72
|
-
defaultProps?: Record<string, unknown
|
|
73
|
+
defaultProps?: PropsOrRules<Record<string, unknown>>;
|
|
73
74
|
label?: string;
|
|
74
75
|
description?: string;
|
|
75
76
|
}
|
|
@@ -13,7 +13,8 @@ import { StoredDefaultCondition } from "../../framework/default-conditions.js";
|
|
|
13
13
|
import { StoredPreviewCondition } from "../../framework/preview-store.js";
|
|
14
14
|
import { RepeatSpec } from "../../framework/render-spec.js";
|
|
15
15
|
import { ComponentSourceInput } from "./component-source-fields.js";
|
|
16
|
-
import {
|
|
16
|
+
import { PropsOrRules } from "./prop-rules.js";
|
|
17
|
+
import { AsInput, AuthoredDefaultsOf, LayerMap, PhantomCallProps, PhantomReadProps, PropMap, RenderArgs, StateMap, StyleRuleInput, UnconditionalDefaults } from "./defineComponent.js";
|
|
17
18
|
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
18
19
|
import { cellAt } from "../../spec/cell.js";
|
|
19
20
|
import { instanceAt } from "../../spec/instance.js";
|
|
@@ -871,7 +872,9 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
|
|
|
871
872
|
}: ComputedInput) => string[];
|
|
872
873
|
}, false, Record<never, never>, Record<never, never>>;
|
|
873
874
|
/** Source extensions declare their structure through .render(). */
|
|
874
|
-
type ComponentRefDelta = ComponentSourceInput<Partial<CreateInput<typeof componentFields
|
|
875
|
+
type ComponentRefDelta = Omit<ComponentSourceInput<Partial<CreateInput<typeof componentFields>>>, 'defaultProps'> & {
|
|
876
|
+
/** A record, or `.defaultProps`'s rule list; checked against the props by `ExtensionDefaults`. */readonly defaultProps?: PropsOrRules<Record<string, unknown>>;
|
|
877
|
+
};
|
|
875
878
|
type ExactComponentDelta<Delta> = Delta & { [Key in Exclude<keyof Delta, keyof ComponentRefDelta>]: never };
|
|
876
879
|
type ContractLayers<Contract> = Contract extends {
|
|
877
880
|
layers: infer Layers;
|
|
@@ -908,7 +911,7 @@ type ResolvedDefaults<Contract, Delta> = Delta extends {
|
|
|
908
911
|
readonly defaultProps: infer Defaults;
|
|
909
912
|
} ? OverlayContract<Contract extends {
|
|
910
913
|
defaultProps: infer Base;
|
|
911
|
-
} ? Base : Record<never, never>, Defaults
|
|
914
|
+
} ? Base : Record<never, never>, UnconditionalDefaults<Defaults>> : Contract extends {
|
|
912
915
|
defaultProps: infer Defaults;
|
|
913
916
|
} ? Defaults : Record<never, never>;
|
|
914
917
|
type ResolvedForwards<Contract, Delta> = Delta extends {
|
|
@@ -27,9 +27,9 @@ import { instanceAt } from "../../spec/instance.js";
|
|
|
27
27
|
import { forwardOptions, forwardsWrite } from "./component-forwards.js";
|
|
28
28
|
import { assertComponentSourceInput } from "./component-source-fields.js";
|
|
29
29
|
import { checkStyleSet, styleSetEdits } from "./component-style-set.js";
|
|
30
|
-
import { storedDefaults } from "./conditional-defaults.js";
|
|
31
30
|
import { forwardRouteInvariants, refusedRoutes } from "./forward-route-invariants.js";
|
|
32
31
|
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
32
|
+
import { storedDefaults } from "./prop-rules.js";
|
|
33
33
|
import { rootLayerInvariants } from "./root-layer-invariants.js";
|
|
34
34
|
import { Token } from "./Token.js";
|
|
35
35
|
import { z } from "zod";
|
|
@@ -1199,7 +1199,7 @@ const Preview = defineSubEntity({
|
|
|
1199
1199
|
});
|
|
1200
1200
|
}
|
|
1201
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
|
|
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 a rule in `.defaultProps([{ when, props }])`.";
|
|
1203
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
1204
|
const defaultConditionBase = z.object({
|
|
1205
1205
|
when: z.record(z.string(), z.unknown()),
|
|
@@ -1811,9 +1811,9 @@ const componentFields = z.strictObject({
|
|
|
1811
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."),
|
|
1812
1812
|
defaultProps: Style.optional(),
|
|
1813
1813
|
/** The defaults that hold only under a condition on the component's other props — see
|
|
1814
|
-
*
|
|
1814
|
+
* `.defaultProps([{ when, props }])`. */
|
|
1815
1815
|
defaultPropsWhen: orList(DefaultCondition).optional().describe(DEFAULT_CONDITIONS_DESCRIPTION),
|
|
1816
|
-
/** What the tile and the matrix render with — see
|
|
1816
|
+
/** What the tile and the matrix render with — see `.preview({ defaultProps })`. Read off
|
|
1817
1817
|
* `.preview()` at build, and written per cell from the matrix. */
|
|
1818
1818
|
preview: orList(Preview).optional().describe(PREVIEW_DESCRIPTION),
|
|
1819
1819
|
/**
|
|
@@ -2989,7 +2989,7 @@ function componentRef(path) {
|
|
|
2989
2989
|
assertComponentSourceInput(delta);
|
|
2990
2990
|
const extended = base.extend({
|
|
2991
2991
|
...delta,
|
|
2992
|
-
...storedDefaults(delta)
|
|
2992
|
+
...delta.defaultProps === void 0 ? {} : storedDefaults(delta.defaultProps)
|
|
2993
2993
|
});
|
|
2994
2994
|
Object.defineProperty(extended, "render", {
|
|
2995
2995
|
enumerable: false,
|
|
@@ -3,7 +3,7 @@ import { RegisteredComponentHandles, RegisteredGroupPaths, RegisteredModifiers,
|
|
|
3
3
|
import { Authored } from "../../framework/authoring.js";
|
|
4
4
|
import { StyleValue } from "./style-bag.js";
|
|
5
5
|
import { ComponentSourceInput } from "./component-source-fields.js";
|
|
6
|
-
import {
|
|
6
|
+
import { PropsOrRules } from "./prop-rules.js";
|
|
7
7
|
import { VariantValues } from "./Component.js";
|
|
8
8
|
import { AllHTMLAttributes, ComponentPropsWithRef, ComponentType, ElementType, JSX, ReactElement, ReactNode, Ref } from "react";
|
|
9
9
|
|
|
@@ -664,11 +664,17 @@ type ForwardedPropsOf<L extends LayerMap, F extends string> = [NonRootForward<L,
|
|
|
664
664
|
type DefaultsOf<P extends PropMap> = Partial<DeclaredProps<P>> & {
|
|
665
665
|
[key: string]: unknown;
|
|
666
666
|
};
|
|
667
|
-
/** {@link DefaultsOf} as `.defaultProps`
|
|
668
|
-
*
|
|
669
|
-
type AuthoredDefaultsOf<P extends PropMap> =
|
|
670
|
-
|
|
671
|
-
|
|
667
|
+
/** {@link DefaultsOf} as `.defaultProps` and `.extend({ defaultProps })` take it: the defaults, or
|
|
668
|
+
* a list of rules giving them under conditions. */
|
|
669
|
+
type AuthoredDefaultsOf<P extends PropMap> = PropsOrRules<DefaultsOf<P>>;
|
|
670
|
+
/** The defaults a component applies with nothing set: a record as given, or its unconditional
|
|
671
|
+
* rules folded together. */
|
|
672
|
+
type UnconditionalDefaults<D> = D extends readonly (infer Rule)[] ? [UnconditionalProps<Rule>] extends [never] ? Record<never, never> : UnionToIntersection<UnconditionalProps<Rule>> : D;
|
|
673
|
+
type UnconditionalProps<Rule> = Rule extends {
|
|
674
|
+
when: Readonly<Record<string, unknown>>;
|
|
675
|
+
} ? never : Rule extends {
|
|
676
|
+
props: infer Props;
|
|
677
|
+
} ? Props : never;
|
|
672
678
|
/**
|
|
673
679
|
* `T` without the keys in `K` — `Omit` that leaves an index signature alone.
|
|
674
680
|
*
|
|
@@ -785,10 +791,11 @@ F extends string = never, /** The states `.states()` declared — what the rende
|
|
|
785
791
|
* `const`, so an `as` keeps its literal type: without it `{ as: 'input' }` widens to `string` and
|
|
786
792
|
* there's no tag left to resolve the element's props against.
|
|
787
793
|
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
794
|
+
* Defaults that depend on other props are rules, the way style rules are: a rule without `when`
|
|
795
|
+
* holds always, and a later rule wins on the props it sets.
|
|
796
|
+
* `[{ props: { includeScrim: true } }, { when: { modal: false }, props: { includeScrim: false } }]`.
|
|
790
797
|
*/
|
|
791
|
-
defaultProps<const D2 extends AuthoredDefaultsOf<P>>(defaults: D2): ComponentBuilder<L, P, E, D2
|
|
798
|
+
defaultProps<const D2 extends AuthoredDefaultsOf<P>>(defaults: D2): ComponentBuilder<L, P, E, UnconditionalDefaults<D2>, F, S>;
|
|
792
799
|
/**
|
|
793
800
|
* The layers whose element props this component ALSO exposes, keyed by layer.
|
|
794
801
|
*
|
|
@@ -832,34 +839,23 @@ F extends string = never, /** The states `.states()` declared — what the rende
|
|
|
832
839
|
*/
|
|
833
840
|
renderCanvas<E2 extends E = E>(fn: (args: Without<RenderArgs<L, P, S>, keyof E2> & E2) => unknown): ComponentBuilder<L, P, E, D, F, S>;
|
|
834
841
|
/**
|
|
835
|
-
* What a preview
|
|
842
|
+
* What a preview tile renders with. `defaultProps` takes what `.defaultProps` does: a record, or a
|
|
843
|
+
* list of rules.
|
|
836
844
|
*
|
|
837
|
-
* Only
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
*
|
|
845
|
+
* Only content, because the grid itself is derived: every axis a matrix could sweep is declared in
|
|
846
|
+
* `styles`, as the conditions the rules apply under, and the modifier columns are the
|
|
847
|
+
* `_hover`/`_active` blocks those rules contain. See `previewMatrix`.
|
|
848
|
+
*
|
|
849
|
+
* A rule with `when` gives the content a cell needs at one point on an axis:
|
|
850
|
+
* `{ when: { type: 'image' }, props: { src } }` gives the image kind a photo. A condition naming a
|
|
851
|
+
* prop no rule styles makes that prop an axis too, with the value named.
|
|
842
852
|
*/
|
|
843
853
|
preview(spec: {
|
|
844
|
-
defaultProps?: DefaultsOf<P
|
|
845
|
-
/**
|
|
846
|
-
* Preview props that hold only under a condition — the same `when` grammar a style rule uses.
|
|
847
|
-
* The grid is derived from the styles; what it cannot derive is the CONTENT a cell needs at a
|
|
848
|
-
* given point on an axis: `{ when: { type: 'image' }, props: { src } }` gives the image kind a
|
|
849
|
-
* photo, `{ when: { invalid: true }, props: { selected: true } }` shows the invalid state checked.
|
|
850
|
-
* A condition naming a prop no rule styles makes that prop an axis too, with the value named —
|
|
851
|
-
* so a preview can say a boolean is worth a column the way a rule would.
|
|
852
|
-
*/
|
|
853
|
-
when?: readonly PreviewCondition<P>[];
|
|
854
|
+
defaultProps?: PropsOrRules<DefaultsOf<P>>;
|
|
854
855
|
}): ComponentBuilder<L, P, E, D, F, S>;
|
|
855
856
|
toStored(): Record<string, unknown>;
|
|
856
857
|
assignPath(path: string): void;
|
|
857
858
|
}
|
|
858
|
-
/** Preview props that hold under a condition on the cell's props — see `preview({ when })`. */
|
|
859
|
-
interface PreviewCondition<P extends PropMap = PropMap> {
|
|
860
|
-
readonly when: Partial<Record<keyof P & string, unknown>>;
|
|
861
|
-
readonly props: DefaultsOf<P>;
|
|
862
|
-
}
|
|
863
859
|
/** A component under authorship, with its declarations forgotten — what a registry holds. */
|
|
864
860
|
type AuthoredComponent = ComponentBuilder<LayerMap, PropMap, unknown, unknown>;
|
|
865
861
|
/**
|
|
@@ -901,4 +897,4 @@ interface DefineComponent {
|
|
|
901
897
|
declare function definePropsFirst<const P extends PropMap<LayerPath>>(props: P & NoInfer<{ [K in keyof P]: Exact<P[K], AuthoredProp<LayerPath>> }>): ComponentBuilder<LayerMap, P>;
|
|
902
898
|
declare const defineComponent: DefineComponent;
|
|
903
899
|
//#endregion
|
|
904
|
-
export { AsInput, AuthoredComponent, AuthoredDefaultsOf, AuthoredProp, ComponentBuilder, ComponentPropsOf, GlyphComponent, GlyphValue, LayerElement, LayerMap, LinkedHandle, ModifierProps, PhantomCallProps, PhantomReadProps, PropCondition, PropDecl, PropMap, RegisteredMembers, RenderArgs, SlotCodeForm, SlotDecl, StateMap, StyleProps, StyleRuleInput, defineComponent };
|
|
900
|
+
export { AsInput, AuthoredComponent, AuthoredDefaultsOf, AuthoredProp, ComponentBuilder, ComponentPropsOf, GlyphComponent, GlyphValue, LayerElement, LayerMap, LinkedHandle, ModifierProps, PhantomCallProps, PhantomReadProps, PropCondition, PropDecl, PropMap, RegisteredMembers, RenderArgs, SlotCodeForm, SlotDecl, StateMap, StyleProps, StyleRuleInput, UnconditionalDefaults, defineComponent };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRef, kindOf, memberRef, pathOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { glyphIdentityOf, glyphPackageRefOf, isComponentType } from "./glyph-identity.js";
|
|
3
|
-
import "../../framework/preview-store.js";
|
|
4
3
|
import { assertComponentSourceInput } from "./component-source-fields.js";
|
|
5
|
-
import {
|
|
4
|
+
import { keyedPropRules, storedDefaults } from "./prop-rules.js";
|
|
6
5
|
import { Component, layerRef, storedStyleRules } from "./Component.js";
|
|
7
6
|
//#region src/entities/system/defineComponent.ts
|
|
8
7
|
function build(body) {
|
|
@@ -25,10 +24,7 @@ function build(body) {
|
|
|
25
24
|
metadata: (meta) => next(meta),
|
|
26
25
|
render: () => handle,
|
|
27
26
|
renderCanvas: () => handle,
|
|
28
|
-
preview: (spec) => {
|
|
29
|
-
if (spec?.defaultProps === void 0 && !spec?.when?.length) return handle;
|
|
30
|
-
return next({ preview: spec });
|
|
31
|
-
},
|
|
27
|
+
preview: (spec) => spec?.defaultProps === void 0 ? handle : next({ preview: spec.defaultProps }),
|
|
32
28
|
toStored: () => toStored(body),
|
|
33
29
|
assignPath(path) {
|
|
34
30
|
handle.path = path;
|
|
@@ -146,7 +142,6 @@ function storableElement(value) {
|
|
|
146
142
|
*/
|
|
147
143
|
function storableValue(value) {
|
|
148
144
|
if (value === null) return null;
|
|
149
|
-
if (isConditionalDefault(value)) throw new Error("`conditionalDefault` is a default, so it goes in `.defaultProps` or `.extend({ defaultProps })`. A preview conditions its props with `.preview({ when: [{ when, props }] })`.");
|
|
150
145
|
const type = typeof value;
|
|
151
146
|
if (type === "string" || type === "number" || type === "boolean") return value;
|
|
152
147
|
if (isComponentType(value)) return storableComponentRef(value);
|
|
@@ -376,21 +371,19 @@ function toStored(body) {
|
|
|
376
371
|
assertComponentSourceInput(body);
|
|
377
372
|
const stored = { ...body };
|
|
378
373
|
if (body.preview !== void 0) {
|
|
379
|
-
const authored = body.preview;
|
|
380
374
|
const keyed = {};
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
when
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
};
|
|
375
|
+
for (const [key, { when, props }] of keyedPropRules(body.preview)) {
|
|
376
|
+
const storable = storableProps(props);
|
|
377
|
+
if (storable === void 0 && when === null) continue;
|
|
378
|
+
keyed[key] = {
|
|
379
|
+
when,
|
|
380
|
+
props: storable ?? {}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
390
383
|
if (Object.keys(keyed).length === 0) delete stored.preview;
|
|
391
384
|
else stored.preview = keyed;
|
|
392
385
|
}
|
|
393
|
-
Object.assign(stored, storedDefaults(body));
|
|
386
|
+
if (body.defaultProps !== void 0) Object.assign(stored, storedDefaults(body.defaultProps));
|
|
394
387
|
if (body.props && typeof body.props === "object") {
|
|
395
388
|
const props = {};
|
|
396
389
|
for (const [name, decl] of Object.entries(body.props)) props[name] = storedProp(decl, body.layers);
|
|
@@ -2,6 +2,7 @@ import { collectRefs, isMintedRow, ref, sourceOf, splitRef } from "../../framewo
|
|
|
2
2
|
import { isConfigRejection, rejectData } from "../../framework/rejection.js";
|
|
3
3
|
import { blockedBy } from "../../framework/plan.js";
|
|
4
4
|
import { excludedCondition } from "../../framework/source-integrity.js";
|
|
5
|
+
import { sameOrigin } from "../../framework/Config.js";
|
|
5
6
|
import { PIN_KIND, covers, declarationOf, entriesFor, excludePaths, excludes, includePaths, narrowDeclaration } from "./link-declaration.js";
|
|
6
7
|
import { planCopy, sourceEntries } from "./copy-plan.js";
|
|
7
8
|
//#region src/entities/system/link-plan.ts
|
|
@@ -40,7 +41,7 @@ function sharedWithOrigin({ config, source, slug, kind, path }) {
|
|
|
40
41
|
kind,
|
|
41
42
|
path
|
|
42
43
|
});
|
|
43
|
-
if (!theirs || !mine || theirs
|
|
44
|
+
if (!theirs || !mine || !sameOrigin(theirs, mine)) return void 0;
|
|
44
45
|
return theirs.pin.displayName ?? theirs.key;
|
|
45
46
|
}
|
|
46
47
|
/** Another pin whose declaration covers the path and whose source has it: the pin the path would
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/entities/system/prop-rules.d.ts
|
|
2
|
+
/** One rule: `props` hold while every prop `when` names has its value, or always with no `when`. */
|
|
3
|
+
interface PropRule<Props = Record<string, unknown>> {
|
|
4
|
+
readonly when?: Readonly<Record<string, unknown>> | null;
|
|
5
|
+
readonly props: Props;
|
|
6
|
+
}
|
|
7
|
+
/** The props given unconditionally, or a list of rules. */
|
|
8
|
+
type PropsOrRules<Props> = Props | readonly PropRule<Props>[];
|
|
9
|
+
//#endregion
|
|
10
|
+
export { PropRule, PropsOrRules };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { canonicalCondition } from "../../framework/utils/refs.js";
|
|
2
|
+
//#region src/entities/system/prop-rules.ts
|
|
3
|
+
/**
|
|
4
|
+
* Rules keyed by condition, `*` for the unconditional one. Two rules with the same condition are
|
|
5
|
+
* one: their props merge, the later value winning, and the merged rule takes the later one's place.
|
|
6
|
+
*/
|
|
7
|
+
function keyedPropRules(authored) {
|
|
8
|
+
const rules = Array.isArray(authored) ? authored : [{ props: authored }];
|
|
9
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const rule of rules) {
|
|
11
|
+
const key = canonicalCondition(rule.when);
|
|
12
|
+
const prior = keyed.get(key);
|
|
13
|
+
keyed.delete(key);
|
|
14
|
+
keyed.set(key, {
|
|
15
|
+
when: key === "*" ? null : { ...rule.when },
|
|
16
|
+
props: {
|
|
17
|
+
...prior?.props,
|
|
18
|
+
...rule.props
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return keyed;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Authored defaults as stored: the unconditional rule in `defaultProps`, each other in
|
|
26
|
+
* `defaultPropsWhen`. A plain record stores as it was written, with no `defaultPropsWhen`.
|
|
27
|
+
*/
|
|
28
|
+
function storedDefaults(authored) {
|
|
29
|
+
if (!Array.isArray(authored)) return { defaultProps: { ...authored } };
|
|
30
|
+
const keyed = keyedPropRules(authored);
|
|
31
|
+
const defaultPropsWhen = {};
|
|
32
|
+
for (const [key, { when, props }] of keyed) if (when) defaultPropsWhen[key] = {
|
|
33
|
+
when,
|
|
34
|
+
props
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
defaultProps: keyed.get("*")?.props ?? {},
|
|
38
|
+
...Object.keys(defaultPropsWhen).length > 0 ? { defaultPropsWhen } : {}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { keyedPropRules, storedDefaults };
|
|
@@ -1972,10 +1972,7 @@ declare class Config {
|
|
|
1972
1972
|
* kind's `sourceOrigin`, so the two pins may name different versions. `undefined` for a source of
|
|
1973
1973
|
* one hop, or one whose system no pin here reaches.
|
|
1974
1974
|
*
|
|
1975
|
-
* The two pins match
|
|
1976
|
-
* the whole key: a pin by path is stamped with its sibling's id when it's pushed, so the Bridge's
|
|
1977
|
-
* `yos` reads `configPath` and `systemId` where this config's pin to the same system names only the
|
|
1978
|
-
* id — and a `configPath` is relative to the config holding it, so it can't be compared across two.
|
|
1975
|
+
* The two pins match by {@link sameOriginFields}.
|
|
1979
1976
|
*/
|
|
1980
1977
|
private directRoute;
|
|
1981
1978
|
/**
|
|
@@ -2569,11 +2566,15 @@ declare class Config {
|
|
|
2569
2566
|
* to a system linked to a foundation answers with the foundation. A row a materialized artifact
|
|
2570
2567
|
* flattened to a literal has no pointer left, so the pin whose `link` declaration covers the path
|
|
2571
2568
|
* stands in, provided the row still reads as the source's ({@link matchesSource}); one the
|
|
2572
|
-
* publisher changed is its own
|
|
2573
|
-
*
|
|
2569
|
+
* publisher changed is its own, and so is a linked row this config lays a value of its own over: the
|
|
2570
|
+
* Bridge's `spectrum/blue/0` points at Yahoo OS's with the Bridge's colours on it, which is the
|
|
2571
|
+
* Bridge's entity, not a second route to Yahoo OS's. Two answers that are {@link sameOrigin} are one
|
|
2572
|
+
* entity reached by two routes, whatever versions the pins name: they compare the pin kind's
|
|
2573
|
+
* `sourceOrigin`, not its identity.
|
|
2574
2574
|
*
|
|
2575
2575
|
* `pin` is the pin entity at the hop where the answer was found, for a surface that names the
|
|
2576
|
-
* origin the way it names any source.
|
|
2576
|
+
* origin the way it names any source. `key` is its origin fields joined, for a surface with no
|
|
2577
|
+
* name to show.
|
|
2577
2578
|
*/
|
|
2578
2579
|
originOf({
|
|
2579
2580
|
kind,
|
|
@@ -2581,10 +2582,7 @@ declare class Config {
|
|
|
2581
2582
|
}: {
|
|
2582
2583
|
kind: string;
|
|
2583
2584
|
path: string;
|
|
2584
|
-
}):
|
|
2585
|
-
key: string;
|
|
2586
|
-
pin: Entity;
|
|
2587
|
-
} | undefined;
|
|
2585
|
+
}): Origin | undefined;
|
|
2588
2586
|
/**
|
|
2589
2587
|
* The pin whose `link` declaration covers `kind:path` while the row there still reads as that
|
|
2590
2588
|
* source's: how a row a materialized artifact flattened to a literal is traced back to the pin it
|
|
@@ -2899,5 +2897,14 @@ declare class Config {
|
|
|
2899
2897
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
2900
2898
|
protected hydrateFrom(stored: StoredConfig, options?: HydrationOptions): this;
|
|
2901
2899
|
}
|
|
2900
|
+
/** Where an entity originates ({@link Config.originOf}): the pin at the hop that answered, and its origin fields. */
|
|
2901
|
+
interface Origin {
|
|
2902
|
+
readonly key: string;
|
|
2903
|
+
/** The pin kind's `sourceOrigin` fields as the pin reads them, `''` where unset. */
|
|
2904
|
+
readonly fields: readonly string[];
|
|
2905
|
+
readonly pin: Entity;
|
|
2906
|
+
}
|
|
2907
|
+
/** Whether two {@link Config.originOf} answers are one origin, by {@link sameOriginFields}. */
|
|
2908
|
+
declare function sameOrigin(a: Origin, b: Origin): boolean;
|
|
2902
2909
|
//#endregion
|
|
2903
|
-
export { AppliedOp, AttachedSources, BatchReceipt, Config, CssGrammar, Edition, HydrationOptions, ListOptions, LiveConfig, Patch, RecordedSource, SERIALIZED_CONFIG_VERSION, SerializedConfig, SettledSource, SkippedOp, SourceCollision, SourcesBySlug, StoredConfig, SubPatch, TreeNode };
|
|
2910
|
+
export { AppliedOp, AttachedSources, BatchReceipt, Config, CssGrammar, Edition, HydrationOptions, ListOptions, LiveConfig, Origin, Patch, RecordedSource, SERIALIZED_CONFIG_VERSION, SerializedConfig, SettledSource, SkippedOp, SourceCollision, SourcesBySlug, StoredConfig, SubPatch, TreeNode, sameOrigin };
|
package/dist/framework/Config.js
CHANGED
|
@@ -3992,10 +3992,7 @@ var Config = class Config {
|
|
|
3992
3992
|
* kind's `sourceOrigin`, so the two pins may name different versions. `undefined` for a source of
|
|
3993
3993
|
* one hop, or one whose system no pin here reaches.
|
|
3994
3994
|
*
|
|
3995
|
-
* The two pins match
|
|
3996
|
-
* the whole key: a pin by path is stamped with its sibling's id when it's pushed, so the Bridge's
|
|
3997
|
-
* `yos` reads `configPath` and `systemId` where this config's pin to the same system names only the
|
|
3998
|
-
* id — and a `configPath` is relative to the config holding it, so it can't be compared across two.
|
|
3995
|
+
* The two pins match by {@link sameOriginFields}.
|
|
3999
3996
|
*/
|
|
4000
3997
|
directRoute(source) {
|
|
4001
3998
|
const hops = sourceHops(source);
|
|
@@ -4009,8 +4006,7 @@ var Config = class Config {
|
|
|
4009
4006
|
if (theirs === void 0) continue;
|
|
4010
4007
|
const direct = this.sourceSlugs().find((slug) => {
|
|
4011
4008
|
const mine = this.sourceFields(sourceKind, slug, "sourceOrigin");
|
|
4012
|
-
|
|
4013
|
-
return shared.length > 0 && shared.every((field) => theirs[field] === mine?.[field]);
|
|
4009
|
+
return mine !== void 0 && sameOriginFields(theirs, mine);
|
|
4014
4010
|
});
|
|
4015
4011
|
if (direct !== void 0) return direct;
|
|
4016
4012
|
}
|
|
@@ -5519,15 +5515,21 @@ var Config = class Config {
|
|
|
5519
5515
|
* to a system linked to a foundation answers with the foundation. A row a materialized artifact
|
|
5520
5516
|
* flattened to a literal has no pointer left, so the pin whose `link` declaration covers the path
|
|
5521
5517
|
* stands in, provided the row still reads as the source's ({@link matchesSource}); one the
|
|
5522
|
-
* publisher changed is its own
|
|
5523
|
-
*
|
|
5518
|
+
* publisher changed is its own, and so is a linked row this config lays a value of its own over: the
|
|
5519
|
+
* Bridge's `spectrum/blue/0` points at Yahoo OS's with the Bridge's colours on it, which is the
|
|
5520
|
+
* Bridge's entity, not a second route to Yahoo OS's. Two answers that are {@link sameOrigin} are one
|
|
5521
|
+
* entity reached by two routes, whatever versions the pins name: they compare the pin kind's
|
|
5522
|
+
* `sourceOrigin`, not its identity.
|
|
5524
5523
|
*
|
|
5525
5524
|
* `pin` is the pin entity at the hop where the answer was found, for a surface that names the
|
|
5526
|
-
* origin the way it names any source.
|
|
5525
|
+
* origin the way it names any source. `key` is its origin fields joined, for a surface with no
|
|
5526
|
+
* name to show.
|
|
5527
5527
|
*/
|
|
5528
5528
|
originOf({ kind, path }) {
|
|
5529
5529
|
const held = this.resolve(kind, path);
|
|
5530
5530
|
if (!held) return void 0;
|
|
5531
|
+
const stored = this.storedBody(kind, path);
|
|
5532
|
+
if (isExtendedRef(stored) && Object.keys(stored.extend).length > 0) return;
|
|
5531
5533
|
let through = held.borrowedFrom;
|
|
5532
5534
|
if (through === void 0 && held.copiedThrough !== void 0) {
|
|
5533
5535
|
if (this.copyDiffers({
|
|
@@ -5543,11 +5545,12 @@ var Config = class Config {
|
|
|
5543
5545
|
});
|
|
5544
5546
|
if (upstream) return upstream;
|
|
5545
5547
|
for (const sourceKind of this.sourceKinds()) {
|
|
5546
|
-
const
|
|
5548
|
+
const fields = this.sourceFields(sourceKind, through, "sourceOrigin");
|
|
5547
5549
|
const pin = this.resolve(sourceKind, through);
|
|
5548
|
-
if (
|
|
5550
|
+
if (fields === void 0 || !pin) continue;
|
|
5549
5551
|
return {
|
|
5550
|
-
key,
|
|
5552
|
+
key: fields.join("\0"),
|
|
5553
|
+
fields,
|
|
5551
5554
|
pin
|
|
5552
5555
|
};
|
|
5553
5556
|
}
|
|
@@ -6325,6 +6328,21 @@ function extendBody(base, delta) {
|
|
|
6325
6328
|
/** The paths each config is reading through a re-pointed link, for {@link Config.laidLinkedBody} to
|
|
6326
6329
|
* find a loop by. Keyed on the config's state, which every read of one config shares. */
|
|
6327
6330
|
const redirecting = /* @__PURE__ */ new WeakMap();
|
|
6331
|
+
/** Whether two {@link Config.originOf} answers are one origin, by {@link sameOriginFields}. */
|
|
6332
|
+
function sameOrigin(a, b) {
|
|
6333
|
+
return sameOriginFields(a.fields, b.fields);
|
|
6334
|
+
}
|
|
6335
|
+
/**
|
|
6336
|
+
* Whether two pins' `sourceOrigin` fields name one system: they agree on every field both set, and
|
|
6337
|
+
* share at least one. Not the whole key: a pin by path is stamped with its sibling's id when it's
|
|
6338
|
+
* pushed, so the Bridge's `yos` reads `configPath` and `systemId` where a pin to the same system by id
|
|
6339
|
+
* names only the id — and a `configPath` is relative to the config holding it, so it can't be compared
|
|
6340
|
+
* across two.
|
|
6341
|
+
*/
|
|
6342
|
+
function sameOriginFields(theirs, mine) {
|
|
6343
|
+
const shared = theirs.flatMap((value, field) => value !== "" && mine[field] ? [field] : []);
|
|
6344
|
+
return shared.length > 0 && shared.every((field) => theirs[field] === mine[field]);
|
|
6345
|
+
}
|
|
6328
6346
|
/**
|
|
6329
6347
|
* The entity an `extend` re-points its path to, and the rest of it: a link's `override` written as a
|
|
6330
6348
|
* ref lands in the stored `extend` as its `__ref`, beside whatever the `extend` verb adds.
|
|
@@ -6539,4 +6557,4 @@ function loadGroupChange(meta, kind, path, raw, phase = "author") {
|
|
|
6539
6557
|
};
|
|
6540
6558
|
}
|
|
6541
6559
|
//#endregion
|
|
6542
|
-
export { Config, SERIALIZED_CONFIG_VERSION };
|
|
6560
|
+
export { Config, SERIALIZED_CONFIG_VERSION, sameOrigin };
|
|
@@ -22,5 +22,32 @@ declare function defaultsFor({
|
|
|
22
22
|
body: unknown;
|
|
23
23
|
given: Readonly<Record<string, unknown>>;
|
|
24
24
|
}): Record<string, unknown>;
|
|
25
|
+
/** One condition a prop defaults under, seen from that prop: the value it takes while `when` holds. */
|
|
26
|
+
interface PropDefaultCondition<V = unknown> {
|
|
27
|
+
readonly when: Readonly<Record<string, unknown>>;
|
|
28
|
+
readonly value: V;
|
|
29
|
+
}
|
|
30
|
+
/** The conditions one prop defaults under, in stored order, each with the value it gives the prop. */
|
|
31
|
+
declare function propDefaultConditions({
|
|
32
|
+
defaultPropsWhen,
|
|
33
|
+
prop
|
|
34
|
+
}: {
|
|
35
|
+
defaultPropsWhen: Readonly<Record<string, StoredDefaultCondition>> | undefined;
|
|
36
|
+
prop: string;
|
|
37
|
+
}): PropDefaultCondition[];
|
|
38
|
+
/**
|
|
39
|
+
* `defaultPropsWhen` with one prop's conditions replaced by `entries`: the prop leaves every entry it
|
|
40
|
+
* was in, an entry left setting nothing goes, and each new condition joins the entry already keyed
|
|
41
|
+
* by it or is added at the end. What a surface editing one prop's conditions writes back whole.
|
|
42
|
+
*/
|
|
43
|
+
declare function withPropDefaultConditions({
|
|
44
|
+
defaultPropsWhen,
|
|
45
|
+
prop,
|
|
46
|
+
entries
|
|
47
|
+
}: {
|
|
48
|
+
defaultPropsWhen: Readonly<Record<string, StoredDefaultCondition>> | undefined;
|
|
49
|
+
prop: string;
|
|
50
|
+
entries: readonly PropDefaultCondition[];
|
|
51
|
+
}): Record<string, StoredDefaultCondition>;
|
|
25
52
|
//#endregion
|
|
26
|
-
export { StoredDefaultCondition, defaultsFor, storedDefaultConditions };
|
|
53
|
+
export { PropDefaultCondition, StoredDefaultCondition, defaultsFor, propDefaultConditions, storedDefaultConditions, withPropDefaultConditions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isPlainObject } from "./utils/field-path.js";
|
|
2
|
-
import { refLeaf } from "./utils/refs.js";
|
|
2
|
+
import { canonicalCondition, refLeaf } from "./utils/refs.js";
|
|
3
3
|
//#region src/framework/default-conditions.ts
|
|
4
4
|
/**
|
|
5
5
|
* A component's stored `defaultPropsWhen` collection, read off a body with nothing else in scope:
|
|
@@ -31,5 +31,42 @@ function defaultsFor({ body, given }) {
|
|
|
31
31
|
})) Object.assign(out, props);
|
|
32
32
|
return out;
|
|
33
33
|
}
|
|
34
|
+
/** The conditions one prop defaults under, in stored order, each with the value it gives the prop. */
|
|
35
|
+
function propDefaultConditions({ defaultPropsWhen, prop }) {
|
|
36
|
+
return Object.values(defaultPropsWhen ?? {}).flatMap(({ when, props }) => props && Object.hasOwn(props, prop) ? [{
|
|
37
|
+
when,
|
|
38
|
+
value: props[prop]
|
|
39
|
+
}] : []);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `defaultPropsWhen` with one prop's conditions replaced by `entries`: the prop leaves every entry it
|
|
43
|
+
* was in, an entry left setting nothing goes, and each new condition joins the entry already keyed
|
|
44
|
+
* by it or is added at the end. What a surface editing one prop's conditions writes back whole.
|
|
45
|
+
*/
|
|
46
|
+
function withPropDefaultConditions({ defaultPropsWhen, prop, entries }) {
|
|
47
|
+
const out = {};
|
|
48
|
+
for (const [key, { when, props }] of Object.entries(defaultPropsWhen ?? {})) {
|
|
49
|
+
const { [prop]: _left, ...rest } = props ?? {};
|
|
50
|
+
if (Object.keys(rest).length > 0) out[key] = {
|
|
51
|
+
when,
|
|
52
|
+
props: rest
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const key = canonicalCondition(entry.when);
|
|
57
|
+
const existing = out[key];
|
|
58
|
+
out[key] = existing ? {
|
|
59
|
+
...existing,
|
|
60
|
+
props: {
|
|
61
|
+
...existing.props,
|
|
62
|
+
[prop]: entry.value
|
|
63
|
+
}
|
|
64
|
+
} : {
|
|
65
|
+
when: { ...entry.when },
|
|
66
|
+
props: { [prop]: entry.value }
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
34
71
|
//#endregion
|
|
35
|
-
export { defaultsFor, storedDefaultConditions };
|
|
72
|
+
export { defaultsFor, propDefaultConditions, storedDefaultConditions, withPropDefaultConditions };
|
|
@@ -788,7 +788,7 @@ declare function validateComponentProps(config: Config, componentPath: string, p
|
|
|
788
788
|
* serialization is for storage and the wire.
|
|
789
789
|
*/
|
|
790
790
|
declare function previewDefaults(config: Config, path: string,
|
|
791
|
-
/** The cell's own prop values. Given, every
|
|
791
|
+
/** The cell's own prop values. Given, every conditional preview rule that holds for the cell —
|
|
792
792
|
* tested against the defaults under these values, as a rule's `when` is — adds its props. */
|
|
793
793
|
|
|
794
794
|
cell?: Record<string, unknown>,
|
|
@@ -799,7 +799,7 @@ options?: {
|
|
|
799
799
|
readonly firstVariants?: boolean;
|
|
800
800
|
}): Record<string, unknown>;
|
|
801
801
|
/**
|
|
802
|
-
* Only what the
|
|
802
|
+
* Only what the conditional preview rules add for a cell — the props of every condition that holds
|
|
803
803
|
* for the cell's values over the defaults, later entries over earlier. Nothing else: a caller that
|
|
804
804
|
* merges these onto a cell's own props is adding the content the author tied to that coordinate,
|
|
805
805
|
* without restating defaults that would shadow an edit.
|
|
@@ -1996,7 +1996,7 @@ function firstVariantValues(props) {
|
|
|
1996
1996
|
return out;
|
|
1997
1997
|
}
|
|
1998
1998
|
/**
|
|
1999
|
-
* Only what the
|
|
1999
|
+
* Only what the conditional preview rules add for a cell — the props of every condition that holds
|
|
2000
2000
|
* for the cell's values over the defaults, later entries over earlier. Nothing else: a caller that
|
|
2001
2001
|
* merges these onto a cell's own props is adding the content the author tied to that coordinate,
|
|
2002
2002
|
* without restating defaults that would shadow an edit.
|