@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
|
@@ -3,6 +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 { ConditionalDefault } from "./conditional-defaults.js";
|
|
6
7
|
import { VariantValues } from "./Component.js";
|
|
7
8
|
import { AllHTMLAttributes, ComponentPropsWithRef, ComponentType, ElementType, JSX, ReactElement, ReactNode, Ref } from "react";
|
|
8
9
|
|
|
@@ -663,6 +664,11 @@ type ForwardedPropsOf<L extends LayerMap, F extends string> = [NonRootForward<L,
|
|
|
663
664
|
type DefaultsOf<P extends PropMap> = Partial<DeclaredProps<P>> & {
|
|
664
665
|
[key: string]: unknown;
|
|
665
666
|
};
|
|
667
|
+
/** {@link DefaultsOf} as `.defaultProps` takes it: a declared prop other than `as` may also default
|
|
668
|
+
* through {@link conditionalDefault}. */
|
|
669
|
+
type AuthoredDefaultsOf<P extends PropMap> = { [K in keyof DeclaredProps<P>]?: K extends 'as' ? DeclaredProps<P>[K] : DeclaredProps<P>[K] | ConditionalDefault<DeclaredProps<P>[K]> } & {
|
|
670
|
+
[key: string]: unknown;
|
|
671
|
+
};
|
|
666
672
|
/**
|
|
667
673
|
* `T` without the keys in `K` — `Omit` that leaves an index signature alone.
|
|
668
674
|
*
|
|
@@ -778,8 +784,11 @@ F extends string = never, /** The states `.states()` declared — what the rende
|
|
|
778
784
|
*
|
|
779
785
|
* `const`, so an `as` keeps its literal type: without it `{ as: 'input' }` widens to `string` and
|
|
780
786
|
* there's no tag left to resolve the element's props against.
|
|
787
|
+
*
|
|
788
|
+
* A default that depends on another prop is a `conditionalDefault`:
|
|
789
|
+
* `includeScrim: conditionalDefault(true, [{ when: { modal: false }, value: false }])`.
|
|
781
790
|
*/
|
|
782
|
-
defaultProps<const D2 extends
|
|
791
|
+
defaultProps<const D2 extends AuthoredDefaultsOf<P>>(defaults: D2): ComponentBuilder<L, P, E, D2, F, S>;
|
|
783
792
|
/**
|
|
784
793
|
* The layers whose element props this component ALSO exposes, keyed by layer.
|
|
785
794
|
*
|
|
@@ -892,4 +901,4 @@ interface DefineComponent {
|
|
|
892
901
|
declare function definePropsFirst<const P extends PropMap<LayerPath>>(props: P & NoInfer<{ [K in keyof P]: Exact<P[K], AuthoredProp<LayerPath>> }>): ComponentBuilder<LayerMap, P>;
|
|
893
902
|
declare const defineComponent: DefineComponent;
|
|
894
903
|
//#endregion
|
|
895
|
-
export { AsInput, AuthoredComponent, AuthoredProp, ComponentBuilder, ComponentPropsOf,
|
|
904
|
+
export { AsInput, AuthoredComponent, AuthoredDefaultsOf, AuthoredProp, ComponentBuilder, ComponentPropsOf, GlyphComponent, GlyphValue, LayerElement, LayerMap, LinkedHandle, PhantomCallProps, PhantomReadProps, PropCondition, PropDecl, PropMap, RegisteredMembers, RenderArgs, SlotCodeForm, SlotDecl, StateMap, StyleRuleInput, defineComponent };
|
|
@@ -2,6 +2,7 @@ import { canonicalCondition, isRef, kindOf, memberRef, pathOf } from "../../fram
|
|
|
2
2
|
import { glyphIdentityOf, glyphPackageRefOf, isComponentType } from "./glyph-identity.js";
|
|
3
3
|
import "../../framework/preview-store.js";
|
|
4
4
|
import { assertComponentSourceInput } from "./component-source-fields.js";
|
|
5
|
+
import { isConditionalDefault, storedDefaults } from "./conditional-defaults.js";
|
|
5
6
|
import { Component, layerRef, storedStyleRules } from "./Component.js";
|
|
6
7
|
//#region src/entities/system/defineComponent.ts
|
|
7
8
|
function build(body) {
|
|
@@ -145,6 +146,7 @@ function storableElement(value) {
|
|
|
145
146
|
*/
|
|
146
147
|
function storableValue(value) {
|
|
147
148
|
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 }] })`.");
|
|
148
150
|
const type = typeof value;
|
|
149
151
|
if (type === "string" || type === "number" || type === "boolean") return value;
|
|
150
152
|
if (isComponentType(value)) return storableComponentRef(value);
|
|
@@ -388,6 +390,7 @@ function toStored(body) {
|
|
|
388
390
|
if (Object.keys(keyed).length === 0) delete stored.preview;
|
|
389
391
|
else stored.preview = keyed;
|
|
390
392
|
}
|
|
393
|
+
Object.assign(stored, storedDefaults(body));
|
|
391
394
|
if (body.props && typeof body.props === "object") {
|
|
392
395
|
const props = {};
|
|
393
396
|
for (const [name, decl] of Object.entries(body.props)) props[name] = storedProp(decl, body.layers);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isConfigRejection, rejectData } from "../../framework/rejection.js";
|
|
2
1
|
import { collectRefs, isMintedRow, ref, sourceOf, splitRef } from "../../framework/utils/refs.js";
|
|
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
5
|
import { PIN_KIND, covers, declarationOf, entriesFor, excludePaths, excludes, includePaths, narrowDeclaration } from "./link-declaration.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isRef } from "../../framework/utils/refs.js";
|
|
2
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { isRef } from "../../framework/utils/refs.js";
|
|
3
3
|
import { MOTION_EASING_NAMES, bezierPoints, motionOfCssKeyword } from "./easings.js";
|
|
4
4
|
import { cssEasing } from "./css-timing.js";
|
|
5
5
|
import { JS_ONLY_FIELDS } from "./Motion.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { reject } from "../../framework/rejection.js";
|
|
2
|
-
import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
3
1
|
import { isPlainObject } from "../../framework/utils/field-path.js";
|
|
2
|
+
import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
3
|
+
import { reject } from "../../framework/rejection.js";
|
|
4
4
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
5
5
|
import { drawnMotionBody, drawnMotionName } from "./drawn-motion.js";
|
|
6
6
|
import { webMotionBody } from "./motion-types.js";
|
|
@@ -73,7 +73,7 @@ interface RecordedSource {
|
|
|
73
73
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
74
74
|
* that replaced it (see `detectedWireVersion`).
|
|
75
75
|
*/
|
|
76
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
76
|
+
declare const SERIALIZED_CONFIG_VERSION = 20261023152030;
|
|
77
77
|
interface SerializedConfig {
|
|
78
78
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
79
79
|
readonly version: number;
|
package/dist/framework/Config.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { applyPathDelta, isPlainObject, namedFields, pathSegments, sectionDelta, touchedFields } from "./utils/field-path.js";
|
|
2
|
+
import { MINTED, collectRefs, entityPathProblem, entityRefOf, isExtendedRef, isMintedRow, isRef, kindOf, memberOf, memberRef, pathOf, qualifyRefs, ref, rewriteRefNamespace, rewriteRefSource, rewriteRefs, routedSource, singletonRef, sourceHops, sourceOf, splitRef } from "./utils/refs.js";
|
|
1
3
|
import "./config-operation-kind.js";
|
|
2
4
|
import { ConfigFormatError, ConfigRejection, isConfigRejection, issuePath, refusalIssues, reject, rejectData, rejectInvalid, rejectReferrers } from "./rejection.js";
|
|
3
|
-
import { MINTED, collectRefs, entityPathProblem, entityRefOf, isExtendedRef, isMintedRow, isRef, kindOf, memberOf, memberRef, pathOf, qualifyRefs, ref, rewriteRefNamespace, rewriteRefSource, rewriteRefs, routedSource, singletonRef, sourceHops, sourceOf, splitRef } from "./utils/refs.js";
|
|
4
5
|
import { describePatch } from "./plan.js";
|
|
5
|
-
import { applyPathDelta, isPlainObject, namedFields, pathSegments, sectionDelta, touchedFields } from "./utils/field-path.js";
|
|
6
6
|
import { METADATA_KEYS, declaredField } from "./utils/field-schema.js";
|
|
7
7
|
import { dataSchema, resolveInputSchema } from "./schemas.js";
|
|
8
8
|
import { isComposedValue } from "../entities/system/composed-values.js";
|
|
@@ -280,6 +280,7 @@ function cachesFor(snapshot, sources) {
|
|
|
280
280
|
if (found) return found;
|
|
281
281
|
const bucket = {
|
|
282
282
|
sources: current,
|
|
283
|
+
entities: /* @__PURE__ */ new Map(),
|
|
283
284
|
extensions: /* @__PURE__ */ new Map(),
|
|
284
285
|
overlays: /* @__PURE__ */ new Map(),
|
|
285
286
|
lists: /* @__PURE__ */ new Map(),
|
|
@@ -438,13 +439,18 @@ function storeCollection(def, patch, next) {
|
|
|
438
439
|
}
|
|
439
440
|
/** Drop every member of a declared `orphans` collection that still points at `target` — what a
|
|
440
441
|
* delete leaves behind when a sibling member exists only to describe the one removed. */
|
|
441
|
-
function dropOrphans(sub, def, target, namespace) {
|
|
442
|
+
function dropOrphans(sub, def, target, namespace, keyed) {
|
|
442
443
|
if (!sub?.orphans?.length) return def;
|
|
443
444
|
let out = def;
|
|
444
445
|
for (const field of sub.orphans) {
|
|
445
446
|
const collection = out[field];
|
|
446
447
|
if (!isPlainObject(collection)) continue;
|
|
448
|
+
const keyedFields = Object.entries(keyed?.subEntities[field]?.namesMembersOf ?? {}).filter(([, names]) => names === keyed?.collection).map(([record]) => record);
|
|
447
449
|
const kept = Object.fromEntries(Object.entries(collection).filter(([, member]) => {
|
|
450
|
+
if (keyed && isPlainObject(member) && keyedFields.some((record) => {
|
|
451
|
+
const names = member[record];
|
|
452
|
+
return isPlainObject(names) && Object.hasOwn(names, keyed.key);
|
|
453
|
+
})) return false;
|
|
448
454
|
const refs = collectRefs(member);
|
|
449
455
|
if (refs.includes(target)) return false;
|
|
450
456
|
if (!namespace) return true;
|
|
@@ -2401,6 +2407,10 @@ var Config = class Config {
|
|
|
2401
2407
|
def = dropOrphans(sub, def, `${leafOf(patch.field).replace(/s$/, "")}:${refPathOf(patch, patch.key)}`, sub?.namespaces ? {
|
|
2402
2408
|
kind: sub.namespaces,
|
|
2403
2409
|
path: patch.key
|
|
2410
|
+
} : void 0, patch.owner === void 0 ? {
|
|
2411
|
+
collection: patch.field,
|
|
2412
|
+
key: patch.key,
|
|
2413
|
+
subEntities: entry.subEntities
|
|
2404
2414
|
} : void 0);
|
|
2405
2415
|
}
|
|
2406
2416
|
const next = snapshot.withChanges([itemChange(entry, patch.kind, patch.path, def)]);
|
|
@@ -2907,7 +2917,13 @@ var Config = class Config {
|
|
|
2907
2917
|
return new Entity(path, withComputed, [...entry.fieldKeys, ...Object.keys(computed)]);
|
|
2908
2918
|
}
|
|
2909
2919
|
resolve(kind, path) {
|
|
2910
|
-
|
|
2920
|
+
const cache = this.caches.entities;
|
|
2921
|
+
const key = `${kind}\u0000${path}`;
|
|
2922
|
+
const cached = cache.get(key);
|
|
2923
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
2924
|
+
const resolved = this.resolvedIn(kind, path)?.entity;
|
|
2925
|
+
cache.set(key, resolved ?? null);
|
|
2926
|
+
return resolved;
|
|
2911
2927
|
}
|
|
2912
2928
|
/**
|
|
2913
2929
|
* Whether this config holds `target`'s entity, at the path the source spells it, through `slug`.
|
|
@@ -6044,7 +6060,7 @@ var Config = class Config {
|
|
|
6044
6060
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
6045
6061
|
hydrateFrom(stored, options) {
|
|
6046
6062
|
const claimed = schemaVersionOf(stored);
|
|
6047
|
-
if (claimed >
|
|
6063
|
+
if (claimed > 20261023152030) throw new SchemaVersionTooNew(claimed);
|
|
6048
6064
|
const wire = upgradeSerializedConfig(stored);
|
|
6049
6065
|
if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating.`);
|
|
6050
6066
|
const leftover = wire.options;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf, refLeaf, refOfKey, sourceHops, sourceOf } from "./utils/refs.js";
|
|
2
|
+
import { defaultsFor } from "./default-conditions.js";
|
|
2
3
|
import { forwardsOf, rootLayerOf } from "../entities/system/element.js";
|
|
3
4
|
import { createSliceMemo } from "./memo.js";
|
|
4
5
|
import { moduleViewOf } from "./module-views.js";
|
|
@@ -658,9 +659,13 @@ function compositeMemberBag({ config, path, markedIn = config }) {
|
|
|
658
659
|
function layerRoutedProps(config, path, state = {}) {
|
|
659
660
|
const component = config.resolve("component", path);
|
|
660
661
|
if (!component) return {};
|
|
661
|
-
const
|
|
662
|
+
const body = component.toJSON();
|
|
663
|
+
const { layers = {}, styles = {} } = body;
|
|
662
664
|
const resolved = {
|
|
663
|
-
...
|
|
665
|
+
...defaultsFor({
|
|
666
|
+
body,
|
|
667
|
+
given: state
|
|
668
|
+
}),
|
|
664
669
|
...state
|
|
665
670
|
};
|
|
666
671
|
const out = {};
|
|
@@ -707,9 +712,13 @@ function layerRoutedProps(config, path, state = {}) {
|
|
|
707
712
|
* that layer through motion's factory and hands it the preset's props.
|
|
708
713
|
*/
|
|
709
714
|
function layerJsMotionPresets(config, path, state = {}) {
|
|
710
|
-
const
|
|
715
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
716
|
+
const { styles = {} } = body ?? {};
|
|
711
717
|
const resolved = {
|
|
712
|
-
...
|
|
718
|
+
...defaultsFor({
|
|
719
|
+
body,
|
|
720
|
+
given: state
|
|
721
|
+
}),
|
|
713
722
|
...state
|
|
714
723
|
};
|
|
715
724
|
const rules = Object.entries(styles);
|
|
@@ -746,9 +755,12 @@ function layerJsMotionPresets(config, path, state = {}) {
|
|
|
746
755
|
* here, and one expanded from the config alone needs this.
|
|
747
756
|
*/
|
|
748
757
|
function styleRuleMotionClasses(config, path, state = {}) {
|
|
749
|
-
const
|
|
758
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
750
759
|
const resolved = {
|
|
751
|
-
...
|
|
760
|
+
...defaultsFor({
|
|
761
|
+
body,
|
|
762
|
+
given: state
|
|
763
|
+
}),
|
|
752
764
|
...state
|
|
753
765
|
};
|
|
754
766
|
const out = {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/framework/default-conditions.d.ts
|
|
2
|
+
/** One `defaultPropsWhen` entry as stored: the condition, and the defaults that hold under it. */
|
|
3
|
+
interface StoredDefaultCondition {
|
|
4
|
+
readonly when: Record<string, unknown>;
|
|
5
|
+
readonly props: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
/** Every `defaultPropsWhen` entry a body stores, keyed and ordered as stored. Empty for none. */
|
|
8
|
+
declare function storedDefaultConditions(body: unknown): Readonly<Record<string, StoredDefaultCondition>>;
|
|
9
|
+
/**
|
|
10
|
+
* The defaults that apply to a component given the props it was handed: `defaultProps`, with every
|
|
11
|
+
* `defaultPropsWhen` entry whose condition holds laid over it in stored order, so a later entry wins
|
|
12
|
+
* on the prop it sets.
|
|
13
|
+
*
|
|
14
|
+
* A condition reads a prop's given value, else its unconditional default. A prop that is itself
|
|
15
|
+
* conditionally defaulted can't be a condition (the schema refuses it), so one pass decides.
|
|
16
|
+
* Values compare by leaf, so a stored value ref and the bare name a call site writes match.
|
|
17
|
+
*/
|
|
18
|
+
declare function defaultsFor({
|
|
19
|
+
body,
|
|
20
|
+
given
|
|
21
|
+
}: {
|
|
22
|
+
body: unknown;
|
|
23
|
+
given: Readonly<Record<string, unknown>>;
|
|
24
|
+
}): Record<string, unknown>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { StoredDefaultCondition, defaultsFor, storedDefaultConditions };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isPlainObject } from "./utils/field-path.js";
|
|
2
|
+
import { refLeaf } from "./utils/refs.js";
|
|
3
|
+
//#region src/framework/default-conditions.ts
|
|
4
|
+
/**
|
|
5
|
+
* A component's stored `defaultPropsWhen` collection, read off a body with nothing else in scope:
|
|
6
|
+
* the defaults that hold only under a condition on the component's other props, beside the
|
|
7
|
+
* unconditional `defaultProps` they override.
|
|
8
|
+
*/
|
|
9
|
+
/** Every `defaultPropsWhen` entry a body stores, keyed and ordered as stored. Empty for none. */
|
|
10
|
+
function storedDefaultConditions(body) {
|
|
11
|
+
const stored = body?.defaultPropsWhen;
|
|
12
|
+
return isPlainObject(stored) ? stored : {};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The defaults that apply to a component given the props it was handed: `defaultProps`, with every
|
|
16
|
+
* `defaultPropsWhen` entry whose condition holds laid over it in stored order, so a later entry wins
|
|
17
|
+
* on the prop it sets.
|
|
18
|
+
*
|
|
19
|
+
* A condition reads a prop's given value, else its unconditional default. A prop that is itself
|
|
20
|
+
* conditionally defaulted can't be a condition (the schema refuses it), so one pass decides.
|
|
21
|
+
* Values compare by leaf, so a stored value ref and the bare name a call site writes match.
|
|
22
|
+
*/
|
|
23
|
+
function defaultsFor({ body, given }) {
|
|
24
|
+
const defaults = body?.defaultProps ?? {};
|
|
25
|
+
const conditions = Object.values(storedDefaultConditions(body));
|
|
26
|
+
if (conditions.length === 0) return defaults;
|
|
27
|
+
const out = { ...defaults };
|
|
28
|
+
for (const { when, props } of conditions) if (Object.entries(when).every(([prop, value]) => {
|
|
29
|
+
const current = given[prop] !== void 0 ? given[prop] : defaults[prop];
|
|
30
|
+
return String(refLeaf(current)) === String(refLeaf(value));
|
|
31
|
+
})) Object.assign(out, props);
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { defaultsFor, storedDefaultConditions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CONFIG_OPERATION_KIND } from "./config-operation-kind.js";
|
|
2
1
|
import { isRef, kindOf, pathOf, ref, refSchema, refTo, sourceOf } from "./utils/refs.js";
|
|
2
|
+
import { CONFIG_OPERATION_KIND } from "./config-operation-kind.js";
|
|
3
3
|
import { resolveFields } from "./schemas.js";
|
|
4
4
|
import { buildKind } from "./registry.js";
|
|
5
5
|
import { brandGroup } from "./utils/group.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { rejectData } from "./rejection.js";
|
|
2
1
|
import { MINTED, collectRefs, entityRefOf, isRef, kindOf, pathOf, ref, rewriteRefs, sourceOf } from "./utils/refs.js";
|
|
2
|
+
import { rejectData } from "./rejection.js";
|
|
3
3
|
import { kindBorrowable } from "./registry.js";
|
|
4
4
|
//#region src/framework/inline-sources.ts
|
|
5
5
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isRef, refLeaf } from "./utils/refs.js";
|
|
2
|
+
import { defaultsFor } from "./default-conditions.js";
|
|
2
3
|
import { authoredBag } from "./projections.js";
|
|
3
4
|
import { resolveAppliedComposites } from "../entities/system/applied-composites.js";
|
|
4
5
|
//#region src/framework/layer-styles.ts
|
|
@@ -44,6 +45,20 @@ function interactionHolds(state, key, value) {
|
|
|
44
45
|
if (on(state[key])) return true;
|
|
45
46
|
return on(state[`${key}@${value === true || value === "true" ? "root" : String(value)}`]);
|
|
46
47
|
}
|
|
48
|
+
const authoredBags = /* @__PURE__ */ new WeakMap();
|
|
49
|
+
/** Every cell reads the same authored rules under its own coordinate. */
|
|
50
|
+
function resolvedBag({ config, bag }) {
|
|
51
|
+
let bags = authoredBags.get(config);
|
|
52
|
+
if (!bags) {
|
|
53
|
+
bags = /* @__PURE__ */ new WeakMap();
|
|
54
|
+
authoredBags.set(config, bags);
|
|
55
|
+
}
|
|
56
|
+
const cached = bags.get(bag);
|
|
57
|
+
if (cached) return cached;
|
|
58
|
+
const resolved = authoredBag(config, resolveAppliedComposites(config, bag));
|
|
59
|
+
bags.set(bag, resolved);
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
47
62
|
/**
|
|
48
63
|
* A bag's values as declarations, flattening any forced modifier block one specificity step up.
|
|
49
64
|
*
|
|
@@ -83,9 +98,13 @@ function ruleSpecificity(when) {
|
|
|
83
98
|
* "styled with nothing".
|
|
84
99
|
*/
|
|
85
100
|
function layerStyles(config, path, props = {}, options = {}) {
|
|
86
|
-
const
|
|
101
|
+
const body = config.resolve("component", path)?.toJSON();
|
|
102
|
+
const { styles = {} } = body ?? {};
|
|
87
103
|
const state = {
|
|
88
|
-
...
|
|
104
|
+
...defaultsFor({
|
|
105
|
+
body,
|
|
106
|
+
given: props
|
|
107
|
+
}),
|
|
89
108
|
...props
|
|
90
109
|
};
|
|
91
110
|
const forced = (options.forced ?? []).map((name) => name.replace(/^_/, ""));
|
|
@@ -94,7 +113,10 @@ function layerStyles(config, path, props = {}, options = {}) {
|
|
|
94
113
|
Object.values(styles).forEach((rule, index) => {
|
|
95
114
|
if (!ruleApplies(rule.when, state)) return;
|
|
96
115
|
for (const [layer, bag] of Object.entries(rule.layers ?? {})) collectBag({
|
|
97
|
-
bag:
|
|
116
|
+
bag: resolvedBag({
|
|
117
|
+
config,
|
|
118
|
+
bag: bag ?? {}
|
|
119
|
+
}),
|
|
98
120
|
forced,
|
|
99
121
|
specificity: ruleSpecificity(rule.when),
|
|
100
122
|
push: (key, value, specificity) => declarations.push({
|
package/dist/framework/memo.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Snapshot } from "./snapshot.js";
|
|
2
2
|
|
|
3
3
|
//#region src/framework/memo.d.ts
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
4
|
+
/** An immutable config value. A changed snapshot or source requires a new value.
|
|
5
|
+
* Structural to avoid importing `Config`, which memoizes through this module. */
|
|
6
6
|
interface HasSnapshot {
|
|
7
7
|
readonly snapshot: Snapshot;
|
|
8
8
|
/**
|
package/dist/framework/memo.js
CHANGED
|
@@ -63,7 +63,9 @@ function sameSliceKeys({ before, after }) {
|
|
|
63
63
|
function createSliceMemo({ kinds, compute }) {
|
|
64
64
|
if (kinds.length === 0) throw new Error("createSliceMemo needs at least one kind — a computation that reads nothing has nothing to key on");
|
|
65
65
|
const root = /* @__PURE__ */ new WeakMap();
|
|
66
|
+
const byConfig = /* @__PURE__ */ new WeakMap();
|
|
66
67
|
return (config) => {
|
|
68
|
+
if (byConfig.has(config)) return byConfig.get(config);
|
|
67
69
|
const keys = sliceKeys({
|
|
68
70
|
config,
|
|
69
71
|
kinds
|
|
@@ -78,9 +80,13 @@ function createSliceMemo({ kinds, compute }) {
|
|
|
78
80
|
level = next;
|
|
79
81
|
}
|
|
80
82
|
const cached = level.has(RESULT) ? level.get(RESULT) : MISS;
|
|
81
|
-
if (cached !== MISS)
|
|
83
|
+
if (cached !== MISS) {
|
|
84
|
+
byConfig.set(config, cached);
|
|
85
|
+
return cached;
|
|
86
|
+
}
|
|
82
87
|
const value = compute(config);
|
|
83
88
|
level.set(RESULT, value);
|
|
89
|
+
byConfig.set(config, value);
|
|
84
90
|
return value;
|
|
85
91
|
};
|
|
86
92
|
}
|
package/dist/framework/plan.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isConfigRejection } from "./rejection.js";
|
|
2
1
|
import { splitRef } from "./utils/refs.js";
|
|
2
|
+
import { isConfigRejection } from "./rejection.js";
|
|
3
3
|
//#region src/framework/plan.ts
|
|
4
4
|
/**
|
|
5
5
|
* One line for a patch, read off the patch itself: its kind, what it did, and where. The payload
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { declarationText, hasRefMarker, isRef, kindOf, memberOf, pathOf, ref, refLeaf, refOfKey, replaceRefMarkers, routedSource, sourceHops, sourceOf, splitRef } from "./utils/refs.js";
|
|
2
|
+
import { defaultsFor } from "./default-conditions.js";
|
|
2
3
|
import { evaluateCalc, isCalc, leadingNumber } from "../entities/system/calc.js";
|
|
3
4
|
import { isOklchColor, renderOklch } from "../entities/system/color.js";
|
|
4
5
|
import { isComposedValue, renderComposedValue } from "../entities/system/composed-values.js";
|
|
@@ -1963,12 +1964,18 @@ function validateComponentProps(config, componentPath, props) {
|
|
|
1963
1964
|
function previewDefaults(config, path, cell, options = {}) {
|
|
1964
1965
|
const component = config.resolve("component", path);
|
|
1965
1966
|
if (!component) return {};
|
|
1966
|
-
const { props
|
|
1967
|
+
const { props } = component.body;
|
|
1967
1968
|
const previewProps = unconditionalPreviewProps(component.body);
|
|
1968
1969
|
const base = {
|
|
1969
1970
|
...options.firstVariants === false ? {} : firstVariantValues(props),
|
|
1970
1971
|
...declaredPropDefaults(props),
|
|
1971
|
-
...
|
|
1972
|
+
...defaultsFor({
|
|
1973
|
+
body: component.body,
|
|
1974
|
+
given: {
|
|
1975
|
+
...previewProps,
|
|
1976
|
+
...cell
|
|
1977
|
+
}
|
|
1978
|
+
}),
|
|
1972
1979
|
...previewProps
|
|
1973
1980
|
};
|
|
1974
1981
|
if (!cell) return base;
|
|
@@ -2011,10 +2018,16 @@ function previewConditionalProps(config, path, cell) {
|
|
|
2011
2018
|
function holdingPreviewConditions({ config, path, cell }) {
|
|
2012
2019
|
const component = config.resolve("component", path);
|
|
2013
2020
|
if (!component) return [];
|
|
2014
|
-
const
|
|
2021
|
+
const previewProps = unconditionalPreviewProps(component.body);
|
|
2015
2022
|
const state = {
|
|
2016
|
-
...
|
|
2017
|
-
|
|
2023
|
+
...defaultsFor({
|
|
2024
|
+
body: component.body,
|
|
2025
|
+
given: {
|
|
2026
|
+
...previewProps,
|
|
2027
|
+
...cell
|
|
2028
|
+
}
|
|
2029
|
+
}),
|
|
2030
|
+
...previewProps,
|
|
2018
2031
|
...cell
|
|
2019
2032
|
};
|
|
2020
2033
|
return Object.entries(keyedPreviewConditions(config, path)).flatMap(([key, condition]) => {
|
|
@@ -164,6 +164,7 @@ declare function routesContent(config: Config, layers: Readonly<Record<string, u
|
|
|
164
164
|
}): boolean;
|
|
165
165
|
/**
|
|
166
166
|
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
167
|
+
* Independent reads reuse the result for this immutable config.
|
|
167
168
|
*
|
|
168
169
|
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
169
170
|
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
@@ -277,13 +277,25 @@ function slotProp(config, componentPath, name, decl) {
|
|
|
277
277
|
...routedKind === "composite" ? { compositeName: refPath(routed?.value) } : {}
|
|
278
278
|
};
|
|
279
279
|
}
|
|
280
|
+
const surfaces = /* @__PURE__ */ new WeakMap();
|
|
280
281
|
/**
|
|
281
282
|
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
283
|
+
* Independent reads reuse the result for this immutable config.
|
|
282
284
|
*
|
|
283
285
|
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
284
286
|
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
285
287
|
*/
|
|
286
288
|
function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
289
|
+
let cache;
|
|
290
|
+
if (seen.size === 0) {
|
|
291
|
+
cache = surfaces.get(config);
|
|
292
|
+
if (!cache) {
|
|
293
|
+
cache = /* @__PURE__ */ new Map();
|
|
294
|
+
surfaces.set(config, cache);
|
|
295
|
+
}
|
|
296
|
+
const cached = cache.get(componentPath);
|
|
297
|
+
if (cached) return cached;
|
|
298
|
+
}
|
|
287
299
|
const declared = resolveComponentProps(config, componentPath);
|
|
288
300
|
const layers = (Component.get(config, componentPath)?.toJSON())?.layers;
|
|
289
301
|
const props = [];
|
|
@@ -346,6 +358,7 @@ function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
|
346
358
|
required
|
|
347
359
|
}, when));
|
|
348
360
|
}
|
|
361
|
+
cache?.set(componentPath, props);
|
|
349
362
|
return props;
|
|
350
363
|
}
|
|
351
364
|
/**
|
|
@@ -206,22 +206,9 @@ declare function componentSpec(config: Config, path: string): ComponentSpec;
|
|
|
206
206
|
*/
|
|
207
207
|
declare function previewSpec(config: Config, path: string): RenderSpec | undefined;
|
|
208
208
|
interface ExpandOptions {
|
|
209
|
-
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* A component in this set is LEFT NAMED, deliberately: its emitted module is the real thing, with
|
|
214
|
-
* whatever its render closes over (a hook, a context, an event handler) intact, and re-deriving it
|
|
215
|
-
* from data would be a worse copy of something that already exists. Expansion is for what the
|
|
216
|
-
* registry CAN'T name — which is exactly a component whose structure is data and whose module was
|
|
217
|
-
* never built.
|
|
218
|
-
*
|
|
219
|
-
* Omitted, everything the config describes expands, which is what a test wants and what a caller
|
|
220
|
-
* with no registry to consult gets.
|
|
221
|
-
*
|
|
222
|
-
* Only `has` is asked, so a caller can answer from its registry directly instead of copying every
|
|
223
|
-
* key into a `Set` first.
|
|
224
|
-
*/
|
|
209
|
+
/** Membership lookup for types the renderer can draw. A Set or a registry-backed `has` works.
|
|
210
|
+
* Recognized components keep their compiled modules, including hooks and handlers.
|
|
211
|
+
* Omitted, everything the config describes expands. */
|
|
225
212
|
readonly rendered?: Pick<ReadonlySet<string>, 'has'>;
|
|
226
213
|
/** The functions `$computed` values call. Absent, a computed value stays on the element for the
|
|
227
214
|
* renderer, and a node repeated over a computed list emits once. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf, ref, refLeaf, splitRef } from "./utils/refs.js";
|
|
2
|
+
import { defaultsFor } from "./default-conditions.js";
|
|
2
3
|
import { renderedElement } from "../entities/system/element.js";
|
|
3
4
|
import { createSliceMemo } from "./memo.js";
|
|
4
5
|
import { componentStateDefaults, componentStates } from "./component-states.js";
|
|
@@ -1264,9 +1265,16 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1264
1265
|
for (const [from, fills] of Object.entries(instanceSlots ?? {})) if (fills.length > 0 && instanceProps[from] === void 0) filled[from] = true;
|
|
1265
1266
|
const declaredDefaults = declaredPropDefaults(body.props);
|
|
1266
1267
|
const pins = instanceProps["__udsForceStates"] ?? {};
|
|
1268
|
+
const defaults = defaultsFor({
|
|
1269
|
+
body,
|
|
1270
|
+
given: {
|
|
1271
|
+
...filled,
|
|
1272
|
+
...instanceProps
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1267
1275
|
const state = {
|
|
1268
1276
|
...declaredDefaults,
|
|
1269
|
-
...
|
|
1277
|
+
...defaults,
|
|
1270
1278
|
...componentStateDefaults(config, path),
|
|
1271
1279
|
...filled,
|
|
1272
1280
|
...instanceProps,
|
|
@@ -1283,7 +1291,7 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1283
1291
|
const forwardsClassName = [...valueRoutes.values()].some((routes) => routes.some((route) => route.from === "className"));
|
|
1284
1292
|
const supplied = {
|
|
1285
1293
|
...declaredDefaults,
|
|
1286
|
-
...
|
|
1294
|
+
...defaults,
|
|
1287
1295
|
...instanceProps
|
|
1288
1296
|
};
|
|
1289
1297
|
const stateNames = new Set(componentStates(config, path).map(({ name }) => name));
|
|
@@ -15,7 +15,7 @@ import { Patch, SerializedConfig } from "./Config.js";
|
|
|
15
15
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
16
16
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
17
17
|
*/
|
|
18
|
-
declare const CURRENT_SCHEMA_VERSION =
|
|
18
|
+
declare const CURRENT_SCHEMA_VERSION = 20261023152030;
|
|
19
19
|
/** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
|
|
20
20
|
* and a raw old-shape record both flow in without casts. */
|
|
21
21
|
interface VersionStamped {
|
|
@@ -13,7 +13,7 @@ import { ConfigFormatError } from "./rejection.js";
|
|
|
13
13
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
14
14
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
15
15
|
*/
|
|
16
|
-
const CURRENT_SCHEMA_VERSION =
|
|
16
|
+
const CURRENT_SCHEMA_VERSION = 20261023152030;
|
|
17
17
|
/** The mint that moved `options` into the `settings` kind — restated here, rather than imported
|
|
18
18
|
* from the migration that owns it, because that migration imports this module. */
|
|
19
19
|
const SETTINGS_AS_KIND_VERSION = 20260908171448;
|
|
@@ -45,7 +45,7 @@ function registerSchemaMigrations(...migrations) {
|
|
|
45
45
|
for (const migration of migrations) {
|
|
46
46
|
if (migration.version !== 1 && !isMintTimestamp(migration.version)) throw new Error(`Schema migration version ${migration.version} is not a mint timestamp — mint one with \`date +%Y%m%d%H%M%S\`, like a supabase migration.`);
|
|
47
47
|
if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
|
|
48
|
-
if (migration.version >
|
|
48
|
+
if (migration.version > 20261023152030) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
|
|
49
49
|
REGISTERED.set(migration.version, migration);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -102,7 +102,7 @@ function pendingFor(version, target, options) {
|
|
|
102
102
|
* Already-current input passes through untouched — same reference, so hot paths pay nothing.
|
|
103
103
|
*/
|
|
104
104
|
function upgradeSerializedConfig(json, options) {
|
|
105
|
-
const target = options?.target ??
|
|
105
|
+
const target = options?.target ?? 20261023152030;
|
|
106
106
|
const version = detectedWireVersion(json);
|
|
107
107
|
if (version > target) throw new SchemaVersionTooNew(version, target);
|
|
108
108
|
const raw = json;
|
|
@@ -160,7 +160,7 @@ function upgradedSources(json, options) {
|
|
|
160
160
|
* meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
|
|
161
161
|
*/
|
|
162
162
|
function upgradePatch(patch, writtenAt, options) {
|
|
163
|
-
const target = options?.target ??
|
|
163
|
+
const target = options?.target ?? 20261023152030;
|
|
164
164
|
if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
|
|
165
165
|
let current = patch;
|
|
166
166
|
for (const migration of pendingFor(writtenAt, target, options)) {
|
|
@@ -179,7 +179,7 @@ function upgradePatch(patch, writtenAt, options) {
|
|
|
179
179
|
* stamp would cause.
|
|
180
180
|
*/
|
|
181
181
|
function upgradeDraftEntries(draft, options) {
|
|
182
|
-
const target = options?.target ??
|
|
182
|
+
const target = options?.target ?? 20261023152030;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sectionDelta } from "./utils/field-path.js";
|
|
2
2
|
import { ref } from "./utils/refs.js";
|
|
3
|
+
import { reject } from "./rejection.js";
|
|
3
4
|
import { planDelete, planRename } from "./plan.js";
|
|
4
5
|
import { compileSchema } from "./utils/compiled-schema.js";
|
|
5
|
-
import { sectionDelta } from "./utils/field-path.js";
|
|
6
6
|
import { deriveCreateSchema, deriveMemberUpdateSchema, deriveUpdateSchema } from "./utils/field-schema.js";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
//#region src/framework/schemas.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { collectRefs, isExtendedRef, isRef, kindOf, memberOf, pathOf, sourceOf, splitRef } from "./utils/refs.js";
|
|
2
1
|
import { isPlainObject, setAtPath } from "./utils/field-path.js";
|
|
2
|
+
import { collectRefs, isExtendedRef, isRef, kindOf, memberOf, pathOf, sourceOf, splitRef } from "./utils/refs.js";
|
|
3
3
|
import { isComposedValue } from "../entities/system/composed-values.js";
|
|
4
4
|
import { modifierCategory } from "../entities/system/modifier-axis.js";
|
|
5
5
|
//#region src/framework/source-integrity.ts
|