@yahoo/uds-create-config 4.5.2 → 4.7.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/configs/CanvasConfig.d.ts +900 -80
- package/dist/configs/react-native-system.d.ts +603 -55
- package/dist/configs/system.d.ts +603 -55
- package/dist/configs/system.js +7 -1
- package/dist/entities/system/Component.d.ts +480 -39
- package/dist/entities/system/Component.js +264 -93
- package/dist/entities/system/File.d.ts +1 -1
- package/dist/entities/system/LinkedSystem.d.ts +2 -2
- package/dist/entities/system/Operation.d.ts +1 -1
- package/dist/entities/system/StyleProperty.d.ts +8 -0
- package/dist/entities/system/StyleProperty.js +12 -1
- package/dist/entities/system/Tool.d.ts +1 -1
- package/dist/entities/system/component-module.js +1 -1
- package/dist/entities/system/defineComponent.d.ts +45 -7
- package/dist/entities/system/defineComponent.js +52 -25
- package/dist/framework/Config.d.ts +8 -2
- package/dist/framework/Config.js +97 -23
- package/dist/framework/class-names.d.ts +4 -2
- package/dist/framework/class-names.js +56 -17
- package/dist/framework/defineDerivedEntity.d.ts +1 -1
- package/dist/framework/defineEntity.d.ts +2 -2
- package/dist/framework/defineSubEntity.d.ts +3 -2
- package/dist/framework/preview-store.d.ts +19 -0
- package/dist/framework/preview-store.js +18 -0
- package/dist/framework/projections.d.ts +28 -8
- package/dist/framework/projections.js +50 -16
- package/dist/framework/prop-surface.d.ts +21 -1
- package/dist/framework/prop-surface.js +99 -21
- package/dist/framework/render-spec.d.ts +103 -3
- package/dist/framework/render-spec.js +285 -37
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/source-integrity.d.ts +14 -1
- package/dist/framework/utils/refs.js +10 -1
- package/dist/framework/validate-spec.d.ts +2 -0
- package/dist/framework/validate-spec.js +13 -0
- package/dist/index.d.ts +15 -12
- package/dist/index.js +7 -6
- package/dist/migrations/2.0.0/v1-artifact.d.ts +305 -29
- package/dist/migrations/20260919051027_prop_conditions_and_anatomy_positions_at_rest.d.ts +22 -0
- package/dist/migrations/20260919051027_prop_conditions_and_anatomy_positions_at_rest.js +10 -0
- package/dist/migrations/20260920004019_preview_conditions_keyed.d.ts +27 -0
- package/dist/migrations/20260920004019_preview_conditions_keyed.js +148 -0
- package/dist/migrations/20260920161309_prefixed_token_group.d.ts +12 -0
- package/dist/migrations/20260920161309_prefixed_token_group.js +10 -0
- package/dist/renderer/wrapRegistry.js +8 -2
- package/dist/renderer/wrappers/component-refs.d.ts +14 -0
- package/dist/renderer/wrappers/component-refs.js +79 -0
- package/dist/renderer/wrappers/hex-normalize.d.ts +5 -7
- package/dist/renderer/wrappers/hex-normalize.js +11 -10
- package/dist/spec/cell.d.ts +171 -0
- package/dist/spec/cell.js +361 -0
- package/dist/spec/detach.d.ts +125 -0
- package/dist/spec/detach.js +511 -0
- package/dist/spec/empty-node-slots.d.ts +11 -23
- package/dist/spec/empty-node-slots.js +12 -39
- package/dist/spec/index.d.ts +5 -3
- package/dist/spec/index.js +3 -3
- package/dist/spec/instance.d.ts +77 -0
- package/dist/spec/instance.js +80 -0
- package/dist/spec/preview-content.d.ts +95 -0
- package/dist/spec/preview-content.js +149 -0
- package/dist/spec/preview-elements.d.ts +54 -15
- package/dist/spec/preview-elements.js +109 -29
- package/dist/spec/prop-conditions.d.ts +28 -0
- package/dist/spec/prop-conditions.js +39 -0
- package/dist/spec/slot.d.ts +206 -0
- package/dist/spec/slot.js +542 -0
- package/dist/spec/visibility.d.ts +82 -0
- package/dist/spec/visibility.js +109 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -2
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { isRef, kindOf, pathOf, refLeaf } from "./utils/refs.js";
|
|
2
|
-
import { rootLayerOf } from "../entities/system/element.js";
|
|
1
|
+
import { isRef, kindOf, memberOf, pathOf, refLeaf } from "./utils/refs.js";
|
|
2
|
+
import { forwardsOf, rootLayerOf } from "../entities/system/element.js";
|
|
3
3
|
import { classPrefixOf } from "../entities/system/Settings.js";
|
|
4
4
|
import { createSliceMemo } from "./memo.js";
|
|
5
|
+
import { storedPreview } from "./preview-store.js";
|
|
5
6
|
import { authoredValue, className, negatedCssValue, renderStyleValue, resolveComponentProps, stylePropLeafForToken, stylePropValueLeaves, stylePropertyPathFor } from "./projections.js";
|
|
6
7
|
import { ruleApplies } from "./layer-styles.js";
|
|
7
8
|
//#region src/framework/class-names.ts
|
|
@@ -295,38 +296,74 @@ function componentMotionClasses(config, path) {
|
|
|
295
296
|
function componentPropClasses(config, path, state = {}) {
|
|
296
297
|
const declared = compositePropsOf(config, path);
|
|
297
298
|
if (!declared) return {};
|
|
298
|
-
const {
|
|
299
|
+
const { groups, defaultProps } = declared;
|
|
299
300
|
if (groups.length === 0) return {};
|
|
300
301
|
const resolved = {
|
|
301
302
|
...defaultProps,
|
|
302
303
|
...state
|
|
303
304
|
};
|
|
304
|
-
const
|
|
305
|
-
for (const [prop, group] of groups) {
|
|
305
|
+
const out = {};
|
|
306
|
+
for (const [prop, group, layer] of groups) {
|
|
306
307
|
const value = resolved[prop];
|
|
307
308
|
const target = memberNamed(group, value);
|
|
308
309
|
if (target === void 0) continue;
|
|
309
310
|
if (!config.resolve("composite", target)) continue;
|
|
311
|
+
const classes = out[layer] ?? [];
|
|
310
312
|
classes.push(className(config, "composite", target));
|
|
313
|
+
out[layer] = classes;
|
|
311
314
|
}
|
|
312
|
-
return
|
|
315
|
+
return out;
|
|
313
316
|
}
|
|
314
317
|
/** The part of {@link componentPropClasses} that depends on the component alone, once per slice:
|
|
315
318
|
* an expansion asks it for every instance it paints. `undefined` for a path no component answers. */
|
|
316
|
-
function compositePropsOf(config, path) {
|
|
319
|
+
function compositePropsOf(config, path, seen = /* @__PURE__ */ new Set()) {
|
|
317
320
|
const cache = compositePropsCache(config);
|
|
318
321
|
if (cache.has(path)) return cache.get(path);
|
|
319
322
|
const component = config.resolve("component", path);
|
|
320
323
|
let declared;
|
|
321
324
|
if (component) {
|
|
322
|
-
const
|
|
325
|
+
const body = component.toJSON();
|
|
326
|
+
const { layers = {}, props = {} } = body;
|
|
323
327
|
const [root] = rootLayerOf(layers);
|
|
324
328
|
const groups = [];
|
|
329
|
+
let defaultProps = {};
|
|
325
330
|
for (const [prop, decl] of Object.entries(props)) {
|
|
326
331
|
if (decl?.type !== "composite") continue;
|
|
327
332
|
const group = isRef(decl.value) ? decl.value.__ref : void 0;
|
|
328
|
-
if (group) groups.push([
|
|
333
|
+
if (group) groups.push([
|
|
334
|
+
prop,
|
|
335
|
+
group,
|
|
336
|
+
root
|
|
337
|
+
]);
|
|
329
338
|
}
|
|
339
|
+
const inner = new Set([...seen, path]);
|
|
340
|
+
for (const [layer, entry] of Object.entries(forwardsOf(body))) {
|
|
341
|
+
const element = layers[layer];
|
|
342
|
+
if (!isRef(element) || kindOf(element.__ref) !== "component") continue;
|
|
343
|
+
const from = pathOf(element.__ref);
|
|
344
|
+
if (inner.has(from)) continue;
|
|
345
|
+
const exposed = compositePropsOf(config, from, inner);
|
|
346
|
+
if (!exposed) continue;
|
|
347
|
+
const names = Array.isArray(entry) ? new Set(entry.flatMap((r) => isRef(r) ? [memberOf(r.__ref)?.split("/").pop()] : [])) : void 0;
|
|
348
|
+
for (const [prop, group, at] of exposed.groups) {
|
|
349
|
+
if (at !== exposed.root) continue;
|
|
350
|
+
if (prop in props) continue;
|
|
351
|
+
if (entry !== "*" && !names?.has(prop)) continue;
|
|
352
|
+
groups.push([
|
|
353
|
+
prop,
|
|
354
|
+
group,
|
|
355
|
+
layer
|
|
356
|
+
]);
|
|
357
|
+
}
|
|
358
|
+
defaultProps = {
|
|
359
|
+
...exposed.defaultProps,
|
|
360
|
+
...defaultProps
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
defaultProps = {
|
|
364
|
+
...defaultProps,
|
|
365
|
+
...body.defaultProps
|
|
366
|
+
};
|
|
330
367
|
declared = {
|
|
331
368
|
root,
|
|
332
369
|
groups,
|
|
@@ -349,8 +386,10 @@ const compositePropsCache = createSliceMemo({
|
|
|
349
386
|
* travels to it as one, whether or not the element declares it: a composite (`variant` on a
|
|
350
387
|
* `Text`-backed layer, which the receiver resolves to its own class), the receiver's own variant or
|
|
351
388
|
* scalar prop (`size: 'sm'` on an Icon layer), or an attribute of a plain element (`as: 'div'`,
|
|
352
|
-
* `type: 'button'`, `aria-hidden`)
|
|
353
|
-
*
|
|
389
|
+
* `type: 'button'`, `aria-hidden`), or a value the rule hands a receiver's forward or slot
|
|
390
|
+
* (`children: 'AI'` on a badge layer, `icon: 'XIcon'` on a button layer), which the emitted module
|
|
391
|
+
* routes the same way. A style property under another name and motion stay out, since the
|
|
392
|
+
* stylesheet and the motion classes already carry them.
|
|
354
393
|
*
|
|
355
394
|
* Forwarding rather than resolving is what makes a layer's styling live-editable at all: a class only
|
|
356
395
|
* exists once a build has emitted the stylesheet, so an edit that makes a NEW style rule paints
|
|
@@ -377,7 +416,7 @@ function layerRoutedProps(config, path, state = {}) {
|
|
|
377
416
|
}) ?? prop;
|
|
378
417
|
if (config.resolve("style-property", styleKey)) continue;
|
|
379
418
|
const decl = declared[prop];
|
|
380
|
-
if (decl?.type === "styleProperty" || decl?.type === "
|
|
419
|
+
if (decl?.type === "styleProperty" || decl?.type === "motion") continue;
|
|
381
420
|
out[layer] ??= {};
|
|
382
421
|
out[layer][prop] = authoredValue(config, prop, value);
|
|
383
422
|
}
|
|
@@ -598,7 +637,7 @@ function modifierUtilitiesUsed(config) {
|
|
|
598
637
|
/**
|
|
599
638
|
* Every style bag a COMPONENT states it wants, each with the definitions its keys resolve against.
|
|
600
639
|
*
|
|
601
|
-
* Not uniform, which is the whole reason it travels with the bag. `defaultProps` and `
|
|
640
|
+
* Not uniform, which is the whole reason it travels with the bag. `defaultProps` and a preview entry's `props`
|
|
602
641
|
* are the component's OWN props, and nothing else has a claim. A style rule's per-layer bag and an
|
|
603
642
|
* anatomy node's props are set on a LAYER'S ELEMENT, so that element answers too — after the
|
|
604
643
|
* component itself, whose own declaration of a name is what that name means throughout its
|
|
@@ -606,14 +645,14 @@ function modifierUtilitiesUsed(config) {
|
|
|
606
645
|
*/
|
|
607
646
|
function componentBags(entity) {
|
|
608
647
|
const { path } = entity;
|
|
609
|
-
const { defaultProps,
|
|
648
|
+
const { defaultProps, styles, anatomy, layers } = entity.toJSON();
|
|
610
649
|
const bags = [{
|
|
611
650
|
bag: defaultProps,
|
|
612
651
|
through: [path]
|
|
613
|
-
}, {
|
|
614
|
-
bag:
|
|
652
|
+
}, ...Object.values(storedPreview(entity.toJSON())).map((entry) => ({
|
|
653
|
+
bag: entry?.props,
|
|
615
654
|
through: [path]
|
|
616
|
-
}];
|
|
655
|
+
}))];
|
|
617
656
|
for (const rule of Object.values(styles ?? {})) for (const [layer, bag] of Object.entries(rule?.layers ?? {})) bags.push({
|
|
618
657
|
bag,
|
|
619
658
|
through: [path, componentElementOf(layers?.[layer])]
|
|
@@ -2,8 +2,8 @@ import { Entity } from "./Entity.js";
|
|
|
2
2
|
import { Ref } from "./utils/refs.js";
|
|
3
3
|
import { TraverseOptions } from "./ref-graph.js";
|
|
4
4
|
import { FieldsSchema } from "./utils/field-schema.js";
|
|
5
|
-
import { Config } from "./Config.js";
|
|
6
5
|
import { ComputedInput, EntityKind } from "./registry.js";
|
|
6
|
+
import { Config } from "./Config.js";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
//#region src/framework/defineDerivedEntity.d.ts
|
|
@@ -4,11 +4,11 @@ import { TraverseOptions } from "./ref-graph.js";
|
|
|
4
4
|
import { CreateInput, FieldsSchema } from "./utils/field-schema.js";
|
|
5
5
|
import { FieldsCtx, UserSchemas } from "./schemas.js";
|
|
6
6
|
import { SubEntityClass } from "./defineSubEntity.js";
|
|
7
|
-
import { PathOf } from "./registered.js";
|
|
8
7
|
import { BulkOverlayWrite, BulkQuery, SourceOverlay, SourceResolutionSchemas } from "./sources.js";
|
|
8
|
+
import { ComputedFields, EntityKind, Linkable } from "./registry.js";
|
|
9
|
+
import { PathOf } from "./registered.js";
|
|
9
10
|
import { GroupBody } from "./utils/group.js";
|
|
10
11
|
import { Config, ListOptions, TreeNode } from "./Config.js";
|
|
11
|
-
import { ComputedFields, EntityKind, Linkable } from "./registry.js";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
14
14
|
//#region src/framework/defineEntity.d.ts
|
|
@@ -71,7 +71,8 @@ type SubEntityClass<F extends z.ZodTypeAny = z.ZodTypeAny> = CollectionSchema<F>
|
|
|
71
71
|
readonly subEntities?: Readonly<Record<string, SubEntityClass>>;
|
|
72
72
|
/**
|
|
73
73
|
* Fields of the OWNING ENTITY that hold this member's NAME as a VALUE, keyed by the member's
|
|
74
|
-
* owner — a component's `defaultProps` and `
|
|
74
|
+
* owner — a component's `defaultProps` and each `preview` entry's `props` are `{ [prop]: value }`.
|
|
75
|
+
* A field is a `/` path; `*` stands for every key at that level.
|
|
75
76
|
*
|
|
76
77
|
* The mirror of {@link namesMembersOf}, which covers a name held as a record KEY. Neither is
|
|
77
78
|
* reachable by a ref rewrite, and both leave the same kind of wreckage: a default naming a
|
|
@@ -81,7 +82,7 @@ type SubEntityClass<F extends z.ZodTypeAny = z.ZodTypeAny> = CollectionSchema<F>
|
|
|
81
82
|
readonly namedValuesIn?: readonly string[];
|
|
82
83
|
/**
|
|
83
84
|
* Fields of the OWNING ENTITY that are KEYED by this member's name — a component's
|
|
84
|
-
* `defaultProps` and `
|
|
85
|
+
* `defaultProps` and each `preview` entry's `props` are `{ [prop]: value }`, so the prop's name is the key
|
|
85
86
|
* rather than the value.
|
|
86
87
|
*
|
|
87
88
|
* The other half of {@link namedValuesIn}, which covers the same two fields from the value side
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/framework/preview-store.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A component's stored `preview` collection, read off a body with nothing else in scope: the render
|
|
4
|
+
* spec builder and the class scanner read it without reaching the projections module.
|
|
5
|
+
*/
|
|
6
|
+
/** One `preview` entry as stored: the condition it holds under, `null` for the `*` entry every
|
|
7
|
+
* cell reads, and the props the matching cells preview with. */
|
|
8
|
+
interface StoredPreviewCondition {
|
|
9
|
+
readonly when: Record<string, unknown> | null;
|
|
10
|
+
readonly props: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
/** The `*` entry the `preview` collection stores — see `preview({ defaultProps })`. */
|
|
13
|
+
declare const UNCONDITIONAL_PREVIEW_KEY = "*";
|
|
14
|
+
/** Every `preview` entry a body stores, keyed as stored. Empty for a body that stores none. */
|
|
15
|
+
declare function storedPreview(body: unknown): Readonly<Record<string, StoredPreviewCondition>>;
|
|
16
|
+
/** The props the `*` entry previews with, `undefined` when the body stores no such entry. */
|
|
17
|
+
declare function unconditionalPreviewProps(body: unknown): Record<string, unknown> | undefined;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { StoredPreviewCondition, UNCONDITIONAL_PREVIEW_KEY, storedPreview, unconditionalPreviewProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/framework/preview-store.ts
|
|
2
|
+
/** The `*` entry the `preview` collection stores — see `preview({ defaultProps })`. */
|
|
3
|
+
const UNCONDITIONAL_PREVIEW_KEY = "*";
|
|
4
|
+
/** Every `preview` entry a body stores, keyed as stored. Empty for a body that stores none. */
|
|
5
|
+
function storedPreview(body) {
|
|
6
|
+
const preview = body?.preview;
|
|
7
|
+
return preview && typeof preview === "object" && !Array.isArray(preview) ? preview : {};
|
|
8
|
+
}
|
|
9
|
+
/** The props the `*` entry previews with, `undefined` when the body stores no such entry. */
|
|
10
|
+
function unconditionalPreviewProps(body) {
|
|
11
|
+
return storedPreview(body)["*"]?.props;
|
|
12
|
+
}
|
|
13
|
+
/** Whether an entry holds under a condition rather than for every cell. */
|
|
14
|
+
function isConditionalPreview(entry) {
|
|
15
|
+
return entry.when !== null && Object.keys(entry.when).length > 0;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { UNCONDITIONAL_PREVIEW_KEY, isConditionalPreview, storedPreview, unconditionalPreviewProps };
|
|
@@ -2,6 +2,7 @@ import { Ref } from "./utils/refs.js";
|
|
|
2
2
|
import { ItemOf } from "./defineEntity.js";
|
|
3
3
|
import { Config } from "./Config.js";
|
|
4
4
|
import { StylePropLeaf, StyleProperty } from "../entities/system/StyleProperty.js";
|
|
5
|
+
import { StoredPreviewCondition, UNCONDITIONAL_PREVIEW_KEY, storedPreview, unconditionalPreviewProps } from "./preview-store.js";
|
|
5
6
|
|
|
6
7
|
//#region src/framework/projections.d.ts
|
|
7
8
|
/**
|
|
@@ -410,10 +411,10 @@ declare function propValueDomain(config: Config, decl: PropDeclaration): {
|
|
|
410
411
|
* `component/validate` op's truth is config-defined and the pipeline only renders it. */
|
|
411
412
|
declare function validateComponentProps(config: Config, componentPath: string, props: Record<string, unknown>): string[];
|
|
412
413
|
/**
|
|
413
|
-
* The props one preview tile starts from: the component's `defaultProps` with its
|
|
414
|
+
* The props one preview tile starts from: the component's `defaultProps` with its `*` preview entry
|
|
414
415
|
* over the top.
|
|
415
416
|
*
|
|
416
|
-
* Preview wins, and that direction is the whole reason this exists once.
|
|
417
|
+
* Preview wins, and that direction is the whole reason this exists once. The `*` entry is the state
|
|
417
418
|
* a person chose to show a component in — Button's `variant`, an Icon prop's example glyph — so a
|
|
418
419
|
* surface showing that tile has to agree with it, while `defaultProps` remains the baseline for every
|
|
419
420
|
* prop the tile doesn't pin. Get the order backwards and the panel reports a value the canvas isn't
|
|
@@ -421,7 +422,7 @@ declare function validateComponentProps(config: Config, componentPath: string, p
|
|
|
421
422
|
*
|
|
422
423
|
* THE PRECEDENCE RULE, stated once: only a RENDER surface — a preview tile, the catalogue card, slot
|
|
423
424
|
* text seeding — reads this merge. An EDIT surface reads and writes the single field it owns
|
|
424
|
-
* (`defaultProps` OR
|
|
425
|
+
* (`defaultProps` OR the `*` entry, never the merge), and anything that SEEDS committed data — a
|
|
425
426
|
* prop binding, a forward's re-seed, a stored instance prop, a default-value form — reads raw
|
|
426
427
|
* `defaultProps`. A preview value that reaches any of those stops being staging and becomes a real
|
|
427
428
|
* default the moment it is saved, which is exactly the leak UDS-3514 closed. Before adding a caller,
|
|
@@ -451,16 +452,33 @@ cell?: Record<string, unknown>): Record<string, unknown>;
|
|
|
451
452
|
* without restating defaults that would shadow an edit.
|
|
452
453
|
*/
|
|
453
454
|
declare function previewConditionalProps(config: Config, path: string, cell: Record<string, unknown>): Record<string, unknown>;
|
|
454
|
-
/** One preview
|
|
455
|
-
interface
|
|
456
|
-
readonly
|
|
457
|
-
readonly
|
|
455
|
+
/** One conditional `preview` entry with the key it is stored under, which is how a write addresses it. */
|
|
456
|
+
interface IndexedPreviewCondition {
|
|
457
|
+
readonly key: string;
|
|
458
|
+
readonly condition: StoredPreviewCondition;
|
|
458
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* The conditional `preview` entries that hold for a cell, in stored order: every prop a condition names
|
|
462
|
+
* holds the value it asks for in the defaults under the cell's own values. The same test
|
|
463
|
+
* `ruleApplies` makes for a style rule, kept here because `layer-styles` imports this module.
|
|
464
|
+
*/
|
|
465
|
+
declare function holdingPreviewConditions({
|
|
466
|
+
config,
|
|
467
|
+
path,
|
|
468
|
+
cell
|
|
469
|
+
}: {
|
|
470
|
+
config: Config;
|
|
471
|
+
path: string;
|
|
472
|
+
cell: Readonly<Record<string, unknown>>;
|
|
473
|
+
}): IndexedPreviewCondition[];
|
|
459
474
|
/**
|
|
460
475
|
* A component's conditional preview props, in authored order. Empty for a component that declares
|
|
461
476
|
* none, or a path that names no component.
|
|
462
477
|
*/
|
|
463
478
|
declare function previewConditions(config: Config, path: string): readonly StoredPreviewCondition[];
|
|
479
|
+
/** The conditional entries under the keys they are stored at, the `*` entry left out. Empty for a
|
|
480
|
+
* component that declares none. */
|
|
481
|
+
declare function keyedPreviewConditions(config: Config, path: string): Readonly<Record<string, StoredPreviewCondition>>;
|
|
464
482
|
/** A preview grid, derived. Rows sweep a prop's declared values; columns are the states the
|
|
465
483
|
* Component actually styles for. */
|
|
466
484
|
interface PreviewMatrix {
|
|
@@ -497,5 +515,7 @@ declare function previewMatrix(config: Config, path: string): PreviewMatrix;
|
|
|
497
515
|
* stored as the string `'true'` and never equals the `true` an author writes.
|
|
498
516
|
*/
|
|
499
517
|
declare function propValueFromAxis(config: Config, path: string, prop: string, value: string): unknown;
|
|
518
|
+
/** The `value` a string, number or boolean prop declares as its default, per prop. */
|
|
519
|
+
declare function declaredPropDefaults(props: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
500
520
|
//#endregion
|
|
501
|
-
export { PreviewMatrix, PropDeclaration,
|
|
521
|
+
export { IndexedPreviewCondition, PreviewMatrix, PropDeclaration, StylePropEntry, StylePropertyItem, authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, holdingPreviewConditions, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
|
|
@@ -7,6 +7,7 @@ import { modifierCategory } from "../entities/system/Modifier.js";
|
|
|
7
7
|
import { classPrefixOf, varPrefixOf } from "../entities/system/Settings.js";
|
|
8
8
|
import { StyleProperty, leavesOfStylePropValue } from "../entities/system/StyleProperty.js";
|
|
9
9
|
import { createSliceMemo } from "./memo.js";
|
|
10
|
+
import { isConditionalPreview, storedPreview, unconditionalPreviewProps } from "./preview-store.js";
|
|
10
11
|
//#region src/framework/projections.ts
|
|
11
12
|
/**
|
|
12
13
|
* Expanded value domains, cached per config instance.
|
|
@@ -903,10 +904,10 @@ function validateComponentProps(config, componentPath, props) {
|
|
|
903
904
|
return errors;
|
|
904
905
|
}
|
|
905
906
|
/**
|
|
906
|
-
* The props one preview tile starts from: the component's `defaultProps` with its
|
|
907
|
+
* The props one preview tile starts from: the component's `defaultProps` with its `*` preview entry
|
|
907
908
|
* over the top.
|
|
908
909
|
*
|
|
909
|
-
* Preview wins, and that direction is the whole reason this exists once.
|
|
910
|
+
* Preview wins, and that direction is the whole reason this exists once. The `*` entry is the state
|
|
910
911
|
* a person chose to show a component in — Button's `variant`, an Icon prop's example glyph — so a
|
|
911
912
|
* surface showing that tile has to agree with it, while `defaultProps` remains the baseline for every
|
|
912
913
|
* prop the tile doesn't pin. Get the order backwards and the panel reports a value the canvas isn't
|
|
@@ -914,7 +915,7 @@ function validateComponentProps(config, componentPath, props) {
|
|
|
914
915
|
*
|
|
915
916
|
* THE PRECEDENCE RULE, stated once: only a RENDER surface — a preview tile, the catalogue card, slot
|
|
916
917
|
* text seeding — reads this merge. An EDIT surface reads and writes the single field it owns
|
|
917
|
-
* (`defaultProps` OR
|
|
918
|
+
* (`defaultProps` OR the `*` entry, never the merge), and anything that SEEDS committed data — a
|
|
918
919
|
* prop binding, a forward's re-seed, a stored instance prop, a default-value form — reads raw
|
|
919
920
|
* `defaultProps`. A preview value that reaches any of those stops being staging and becomes a real
|
|
920
921
|
* default the moment it is saved, which is exactly the leak UDS-3514 closed. Before adding a caller,
|
|
@@ -935,8 +936,10 @@ function validateComponentProps(config, componentPath, props) {
|
|
|
935
936
|
function previewDefaults(config, path, cell) {
|
|
936
937
|
const component = config.resolve("component", path);
|
|
937
938
|
if (!component) return {};
|
|
938
|
-
const {
|
|
939
|
+
const { props, defaultProps } = component.body;
|
|
940
|
+
const previewProps = unconditionalPreviewProps(component.body);
|
|
939
941
|
const base = {
|
|
942
|
+
...declaredPropDefaults(props),
|
|
940
943
|
...defaultProps,
|
|
941
944
|
...previewProps
|
|
942
945
|
};
|
|
@@ -953,28 +956,48 @@ function previewDefaults(config, path, cell) {
|
|
|
953
956
|
* without restating defaults that would shadow an edit.
|
|
954
957
|
*/
|
|
955
958
|
function previewConditionalProps(config, path, cell) {
|
|
959
|
+
const conditional = {};
|
|
960
|
+
for (const { condition } of holdingPreviewConditions({
|
|
961
|
+
config,
|
|
962
|
+
path,
|
|
963
|
+
cell
|
|
964
|
+
})) Object.assign(conditional, condition.props);
|
|
965
|
+
return conditional;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* The conditional `preview` entries that hold for a cell, in stored order: every prop a condition names
|
|
969
|
+
* holds the value it asks for in the defaults under the cell's own values. The same test
|
|
970
|
+
* `ruleApplies` makes for a style rule, kept here because `layer-styles` imports this module.
|
|
971
|
+
*/
|
|
972
|
+
function holdingPreviewConditions({ config, path, cell }) {
|
|
956
973
|
const component = config.resolve("component", path);
|
|
957
|
-
if (!component) return
|
|
958
|
-
const { defaultProps
|
|
974
|
+
if (!component) return [];
|
|
975
|
+
const { defaultProps } = component.body;
|
|
959
976
|
const state = {
|
|
960
977
|
...defaultProps,
|
|
961
|
-
...
|
|
978
|
+
...unconditionalPreviewProps(component.body),
|
|
962
979
|
...cell
|
|
963
980
|
};
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
981
|
+
return Object.entries(keyedPreviewConditions(config, path)).flatMap(([key, condition]) => {
|
|
982
|
+
return Object.entries(condition.when ?? {}).every(([prop, value]) => String(state[prop]) === String(refLeaf(value))) ? [{
|
|
983
|
+
key,
|
|
984
|
+
condition
|
|
985
|
+
}] : [];
|
|
986
|
+
});
|
|
968
987
|
}
|
|
969
988
|
/**
|
|
970
989
|
* A component's conditional preview props, in authored order. Empty for a component that declares
|
|
971
990
|
* none, or a path that names no component.
|
|
972
991
|
*/
|
|
973
992
|
function previewConditions(config, path) {
|
|
993
|
+
return Object.values(keyedPreviewConditions(config, path));
|
|
994
|
+
}
|
|
995
|
+
/** The conditional entries under the keys they are stored at, the `*` entry left out. Empty for a
|
|
996
|
+
* component that declares none. */
|
|
997
|
+
function keyedPreviewConditions(config, path) {
|
|
974
998
|
const component = config.resolve("component", path);
|
|
975
|
-
if (!component) return
|
|
976
|
-
|
|
977
|
-
return Array.isArray(previewWhen) ? previewWhen : [];
|
|
999
|
+
if (!component) return {};
|
|
1000
|
+
return Object.fromEntries(Object.entries(storedPreview(component.body)).filter(([, entry]) => isConditionalPreview(entry)));
|
|
978
1001
|
}
|
|
979
1002
|
/**
|
|
980
1003
|
* The preview grid a component implies.
|
|
@@ -1014,7 +1037,7 @@ function previewMatrix(config, path) {
|
|
|
1014
1037
|
if (modifierCategory(config, key.slice(1)) === "state") modifiers.add(key);
|
|
1015
1038
|
}
|
|
1016
1039
|
}
|
|
1017
|
-
for (const { when } of previewConditions(config, path)) for (const [prop, stored] of Object.entries(when)) nameAxisPoint(prop, stored);
|
|
1040
|
+
for (const { when } of previewConditions(config, path)) for (const [prop, stored] of Object.entries(when ?? {})) nameAxisPoint(prop, stored);
|
|
1018
1041
|
for (const [name, decl] of Object.entries(declared)) {
|
|
1019
1042
|
if (decl?.type === "composite" && isRef(decl.value)) {
|
|
1020
1043
|
const values = declaredFirst([...memberLeaves(config, decl.value)], props[name] ?? []);
|
|
@@ -1052,5 +1075,16 @@ function propValueFromAxis(config, path, prop, value) {
|
|
|
1052
1075
|
}
|
|
1053
1076
|
return value;
|
|
1054
1077
|
}
|
|
1078
|
+
/** The `value` a string, number or boolean prop declares as its default, per prop. */
|
|
1079
|
+
function declaredPropDefaults(props) {
|
|
1080
|
+
const out = {};
|
|
1081
|
+
for (const [name, decl] of Object.entries(props ?? {})) {
|
|
1082
|
+
if (!decl || typeof decl !== "object") continue;
|
|
1083
|
+
const { type, value } = decl;
|
|
1084
|
+
if (type !== "string" && type !== "number" && type !== "boolean") continue;
|
|
1085
|
+
if (value !== void 0) out[name] = value;
|
|
1086
|
+
}
|
|
1087
|
+
return out;
|
|
1088
|
+
}
|
|
1055
1089
|
//#endregion
|
|
1056
|
-
export { authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropRouting, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
|
|
1090
|
+
export { authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, holdingPreviewConditions, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
|
|
@@ -3,9 +3,14 @@ import { Config } from "./Config.js";
|
|
|
3
3
|
//#region src/framework/prop-surface.d.ts
|
|
4
4
|
/** What a prop IS — the config's own prop types, and nothing invented. */
|
|
5
5
|
type SurfacePropKind = 'variant' | 'styleProperty' | 'composite' | 'motion' | 'slot' | 'string' | 'number' | 'boolean';
|
|
6
|
+
/** When a prop applies, as leaves: each key a sibling prop, each value the leaves it must hold one
|
|
7
|
+
* of. What a control compares the values in force against — see {@link propApplies}. */
|
|
8
|
+
type SurfacePropCondition = Readonly<Record<string, readonly unknown[]>>;
|
|
6
9
|
interface SurfacePropBase {
|
|
7
10
|
readonly name: string;
|
|
8
11
|
readonly required: boolean;
|
|
12
|
+
/** Absent when the prop always applies. */
|
|
13
|
+
readonly when?: SurfacePropCondition;
|
|
9
14
|
}
|
|
10
15
|
interface SurfaceVariantProp extends SurfacePropBase {
|
|
11
16
|
readonly kind: 'variant';
|
|
@@ -62,7 +67,16 @@ interface PropDecl extends Record<string, unknown> {
|
|
|
62
67
|
into?: string;
|
|
63
68
|
text?: boolean;
|
|
64
69
|
accepts?: unknown;
|
|
70
|
+
when?: unknown;
|
|
65
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Whether a prop applies under the values in force — every prop its condition names holds one of the
|
|
74
|
+
* leaves listed for it. A prop with no condition always applies; an unset prop satisfies nothing.
|
|
75
|
+
* Compared as strings, since a control hands back what it displays.
|
|
76
|
+
*/
|
|
77
|
+
declare function propApplies(prop: {
|
|
78
|
+
readonly when?: SurfacePropCondition;
|
|
79
|
+
}, values: Readonly<Record<string, unknown>>): boolean;
|
|
66
80
|
/**
|
|
67
81
|
* The prop a slot routes INTO, resolved through the layer it targets: the layer's element is a
|
|
68
82
|
* component, and `into` names one of that component's props. `undefined` when the slot targets
|
|
@@ -110,6 +124,12 @@ declare function surfaceProps(config: Config, componentPath: string, /** Forward
|
|
|
110
124
|
seen?: ReadonlySet<string>): SurfaceProp[];
|
|
111
125
|
/** One prop by name, or `undefined` when the component doesn't expose it. */
|
|
112
126
|
declare function surfaceProp(config: Config, componentPath: string, name: string): SurfaceProp | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* The registry entity a prop writes through, as a path: its composite, its style property, or the
|
|
129
|
+
* ref a variant's values come from. Resolved through a route, so a prop forwarded into a layer's
|
|
130
|
+
* composite names that composite. `undefined` for a prop with none.
|
|
131
|
+
*/
|
|
132
|
+
declare function propRegistryRef(config: Config, componentPath: string, name: string): string | undefined;
|
|
113
133
|
/**
|
|
114
134
|
* Each non-root layer a component forwards to, and the sorted prop names each one receives — the
|
|
115
135
|
* emitter's view, which writes a literal key set per layer. Root is absent on purpose: it takes
|
|
@@ -129,4 +149,4 @@ interface ForwardClaims {
|
|
|
129
149
|
}
|
|
130
150
|
declare function forwardClaims(config: Config, componentPath: string): ForwardClaims;
|
|
131
151
|
//#endregion
|
|
132
|
-
export { ForwardClaims, SurfaceCompositeProp, SurfaceProp, SurfacePropKind, SurfaceScalarProp, SurfaceSlotProp, SurfaceStylePropertyProp, SurfaceVariantProp, forwardClaims, forwardedLayers, intoName, routedProp, routedPropIn, routesContent, surfaceProp, surfaceProps };
|
|
152
|
+
export { ForwardClaims, SurfaceCompositeProp, SurfaceProp, SurfacePropCondition, SurfacePropKind, SurfaceScalarProp, SurfaceSlotProp, SurfaceStylePropertyProp, SurfaceVariantProp, forwardClaims, forwardedLayers, intoName, propApplies, propRegistryRef, routedProp, routedPropIn, routesContent, surfaceProp, surfaceProps };
|