@yahoo/uds-create-config 4.36.1 → 4.37.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/configs/system.js +4 -0
- package/dist/entities/system/Component.d.ts +31 -2
- package/dist/entities/system/Component.js +10 -1
- package/dist/entities/system/LinkedSystem.d.ts +8 -0
- package/dist/entities/system/LinkedSystem.js +22 -12
- package/dist/entities/system/copy-plan.js +1 -2
- package/dist/entities/system/defineComponent.d.ts +3 -0
- package/dist/entities/system/link-plan.d.ts +24 -5
- package/dist/entities/system/link-plan.js +70 -15
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +1 -1
- package/dist/framework/class-names.d.ts +46 -7
- package/dist/framework/class-names.js +137 -24
- package/dist/framework/render-spec.js +1 -0
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/migrations/20260928180801_link_on_linked.d.ts +10 -0
- package/dist/migrations/20260928180801_link_on_linked.js +8 -0
- package/dist/migrations/20260928215509_composite_prop_layer.d.ts +12 -0
- package/dist/migrations/20260928215509_composite_prop_layer.js +8 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/configs/system.js
CHANGED
|
@@ -42,6 +42,8 @@ import { renderTokenRefsMigration } from "../migrations/20260923160425_render_to
|
|
|
42
42
|
import { globalStyleDerivedColorsMigration } from "../migrations/20260923163604_global_style_derived_colors.js";
|
|
43
43
|
import { slotCodeFormsMigration } from "../migrations/20260924044539_slot_code_forms.js";
|
|
44
44
|
import { canvasRoleSlotMigration } from "../migrations/20260925143319_canvas_role_slot.js";
|
|
45
|
+
import { linkOnLinkedMigration } from "../migrations/20260928180801_link_on_linked.js";
|
|
46
|
+
import { compositePropLayerMigration } from "../migrations/20260928215509_composite_prop_layer.js";
|
|
45
47
|
const System = defineConfig({
|
|
46
48
|
name: WEB_CONFIG_NAME,
|
|
47
49
|
description: "A design system: the values, primitives and compositions an app is built from. A ref is written `{ \"__ref\": \"<kind>:<path>\" }`, so a token is `{ \"__ref\": \"token:<group>/<name>\" }` and a token group is `{ \"__ref\": \"token:<group>\" }`. Build it in this order. Tokens first, in groups by purpose (colors, spacing, radii, type sizes), since everything else names them. Then style properties, each with `values` holding one ref to the token group whose members it accepts (`{ \"__ref\": \"token:color\" }`), so a prop takes token names rather than raw CSS; add a string keyword only for a value no token holds. A style rule's bag holds a prop's values (`\"padding\": \"4\"`, `\"bg\": \"brand\"`), never raw CSS. Then a few primitive components, one layer each, whose props are style properties (a box for layout and surface, a text for type, a pressable for interaction). Then every other component composed from those primitives: its layers name a primitive or an element, its anatomy places them (a node renders a layer, a tag or `Slot` where a slot prop's content lands; `children` is the edge list; `visible` is `{ \"$state\": \"<prop>\" }`; a prop shown in a nested layer is a `forward` route, and `$state` never sits in a node's props), and its style rules set style-property values per layer, keyed by prop values when a variant changes them. Modes (a dark mode is `{ type: \"selector\", value: \".dark\" }`) change token values through a token's `overrides`, so a component never restyles for a mode; modifiers (hover, focus, disabled) name a state, and a style rule applies under one as a `_hover` block inside a layer bag. Composites bundle style values that recur. Last, register canvas roles: the canvas draws with them, one entity per tool (`frame` for the layout primitive, `text` for the text primitive, `image`) whose entries name the components that tool inserts, and a tool whose role is unregistered is disabled. Give each component a `preview` entry under `*` so it shows content, and never write a CSS property name where a style-property name belongs.",
|
|
@@ -95,5 +97,7 @@ if (!registeredSchemaMigrations().has(20260923160425)) registerSchemaMigrations(
|
|
|
95
97
|
if (!registeredSchemaMigrations().has(20260923163604)) registerSchemaMigrations(globalStyleDerivedColorsMigration);
|
|
96
98
|
if (!registeredSchemaMigrations().has(20260924044539)) registerSchemaMigrations(slotCodeFormsMigration);
|
|
97
99
|
if (!registeredSchemaMigrations().has(20260925143319)) registerSchemaMigrations(canvasRoleSlotMigration);
|
|
100
|
+
if (!registeredSchemaMigrations().has(20260928180801)) registerSchemaMigrations(linkOnLinkedMigration);
|
|
101
|
+
if (!registeredSchemaMigrations().has(20260928215509)) registerSchemaMigrations(compositePropLayerMigration);
|
|
98
102
|
//#endregion
|
|
99
103
|
export { System };
|
|
@@ -176,17 +176,46 @@ declare const propShapeDefinition: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
176
176
|
}, z.core.$strip>]>, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{
|
|
177
177
|
__ref: z.ZodString;
|
|
178
178
|
}, z.core.$strip>]>>]>>>;
|
|
179
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
179
|
+
}, z.core.$strict>, z.ZodPipe<z.ZodObject<{
|
|
180
180
|
type: z.ZodLiteral<"composite">;
|
|
181
181
|
value: z.ZodObject<{
|
|
182
182
|
__ref: z.ZodString;
|
|
183
183
|
}, z.core.$strip>;
|
|
184
|
+
layer: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
185
|
+
__ref: z.ZodString;
|
|
186
|
+
}, z.core.$strip>]>>;
|
|
184
187
|
when: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{
|
|
185
188
|
__ref: z.ZodString;
|
|
186
189
|
}, z.core.$strip>]>, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{
|
|
187
190
|
__ref: z.ZodString;
|
|
188
191
|
}, z.core.$strip>]>>]>>>;
|
|
189
|
-
}, z.core.$strict>, z.
|
|
192
|
+
}, z.core.$strict>, z.ZodTransform<{
|
|
193
|
+
type: "composite";
|
|
194
|
+
value: {
|
|
195
|
+
__ref: string;
|
|
196
|
+
};
|
|
197
|
+
layer?: string | {
|
|
198
|
+
__ref: string;
|
|
199
|
+
} | undefined;
|
|
200
|
+
when?: Record<string, string | number | boolean | {
|
|
201
|
+
__ref: string;
|
|
202
|
+
} | (string | number | boolean | {
|
|
203
|
+
__ref: string;
|
|
204
|
+
})[]> | undefined;
|
|
205
|
+
}, {
|
|
206
|
+
type: "composite";
|
|
207
|
+
value: {
|
|
208
|
+
__ref: string;
|
|
209
|
+
};
|
|
210
|
+
layer?: string | {
|
|
211
|
+
__ref: string;
|
|
212
|
+
} | undefined;
|
|
213
|
+
when?: Record<string, string | number | boolean | {
|
|
214
|
+
__ref: string;
|
|
215
|
+
} | (string | number | boolean | {
|
|
216
|
+
__ref: string;
|
|
217
|
+
})[]> | undefined;
|
|
218
|
+
}>>, z.ZodObject<{
|
|
190
219
|
type: z.ZodLiteral<"motion">;
|
|
191
220
|
value: z.ZodDefault<z.ZodObject<{
|
|
192
221
|
__ref: z.ZodString;
|
|
@@ -360,6 +360,14 @@ function routedTarget(decl) {
|
|
|
360
360
|
into: decl.target.slice(separator + 1)
|
|
361
361
|
};
|
|
362
362
|
}
|
|
363
|
+
/** A composite prop's authored `layer` name as the layer ref it is stored as — see {@link routedTarget}
|
|
364
|
+
* for why the coercion lives in the schema. */
|
|
365
|
+
function layerAsRef(decl) {
|
|
366
|
+
return typeof decl.layer === "string" ? {
|
|
367
|
+
...decl,
|
|
368
|
+
layer: layerRef(decl.layer)
|
|
369
|
+
} : decl;
|
|
370
|
+
}
|
|
363
371
|
/** A prop that applies only under a condition on its siblings — the record a style rule's `when`
|
|
364
372
|
* holds. Open here, where no owner is known; `propSchemaFor` narrows it to the owner's props. */
|
|
365
373
|
const conditionLeaf = z.union([
|
|
@@ -415,8 +423,9 @@ function propShapeWith(when) {
|
|
|
415
423
|
z.strictObject({
|
|
416
424
|
type: z.literal("composite"),
|
|
417
425
|
value: refSchema,
|
|
426
|
+
layer: z.union([z.string().min(1), refSchema]).optional(),
|
|
418
427
|
when
|
|
419
|
-
}),
|
|
428
|
+
}).transform(layerAsRef),
|
|
420
429
|
z.strictObject({
|
|
421
430
|
type: z.literal("motion"),
|
|
422
431
|
value: refSchema.default({ __ref: "motion:" }),
|
|
@@ -107,12 +107,20 @@ declare const LinkedSystemDefinition: EntityClass<z.ZodObject<{
|
|
|
107
107
|
readonly input: z.ZodObject<{
|
|
108
108
|
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
109
109
|
data: z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodArray<z.ZodString>]>>]>;
|
|
110
|
+
onLinked: z.ZodOptional<z.ZodEnum<{
|
|
111
|
+
keep: "keep";
|
|
112
|
+
take: "take";
|
|
113
|
+
}>>;
|
|
110
114
|
}, z.core.$strip>;
|
|
111
115
|
};
|
|
112
116
|
readonly 'link-plan': {
|
|
113
117
|
readonly input: z.ZodObject<{
|
|
114
118
|
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
115
119
|
data: z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodArray<z.ZodString>]>>]>;
|
|
120
|
+
onLinked: z.ZodOptional<z.ZodEnum<{
|
|
121
|
+
keep: "keep";
|
|
122
|
+
take: "take";
|
|
123
|
+
}>>;
|
|
116
124
|
}, z.core.$strip>;
|
|
117
125
|
};
|
|
118
126
|
readonly unlink: {
|
|
@@ -146,7 +146,10 @@ const linkInput = z.object({
|
|
|
146
146
|
path: pathInput("linked-system"),
|
|
147
147
|
/** What to draw, keyed by accessor the way the pin's `link` is, or `'*'` for everything the source
|
|
148
148
|
* offers. A path that names a folder in the source covers its members. */
|
|
149
|
-
data: z.union([z.literal("*"), z.record(z.string(), copyPaths)])
|
|
149
|
+
data: z.union([z.literal("*"), z.record(z.string(), copyPaths)]),
|
|
150
|
+
/** What to do at a path another linked system provides: `'take'` makes it follow this source,
|
|
151
|
+
* `'keep'` leaves it where it comes from. Required when there is one; `link-plan` lists them. */
|
|
152
|
+
onLinked: z.enum(["keep", "take"]).optional()
|
|
150
153
|
});
|
|
151
154
|
const unlinkInput = z.object({
|
|
152
155
|
path: pathInput("linked-system"),
|
|
@@ -173,6 +176,14 @@ function copyInputOf(input) {
|
|
|
173
176
|
...input.onConflict === void 0 ? {} : { onConflict: input.onConflict }
|
|
174
177
|
};
|
|
175
178
|
}
|
|
179
|
+
/** The parsed `link` input as the plan takes it. */
|
|
180
|
+
function linkPlanInputOf(input) {
|
|
181
|
+
return {
|
|
182
|
+
path: String(input.path),
|
|
183
|
+
data: input.data,
|
|
184
|
+
...input.onLinked === void 0 ? {} : { onLinked: input.onLinked }
|
|
185
|
+
};
|
|
186
|
+
}
|
|
176
187
|
/** A `link` or `unlink` example: one entity the source offers, under the accessor this config files it by. */
|
|
177
188
|
function linkExample({ config, path }) {
|
|
178
189
|
const target = exampleBorrowable(config, path);
|
|
@@ -243,7 +254,8 @@ const LinkedSystem = defineEntity({
|
|
|
243
254
|
* Draw entities from a linked system: the pin's `link` declaration grows to cover them and the
|
|
244
255
|
* build mints a pointer row per entity, in this one op. A row of this config's own at a covered
|
|
245
256
|
* path is deleted so theirs shows through; a row held through another pin becomes an extension
|
|
246
|
-
* through this one
|
|
257
|
+
* through this one when `onLinked` is `'take'`. `link-plan` says what that replaces before anything
|
|
258
|
+
* is written.
|
|
247
259
|
*/
|
|
248
260
|
link: {
|
|
249
261
|
input: linkInput,
|
|
@@ -255,13 +267,14 @@ const LinkedSystem = defineEntity({
|
|
|
255
267
|
title: (entity) => `Link something from ${entity}`,
|
|
256
268
|
example: linkExample,
|
|
257
269
|
handler: (input, config) => {
|
|
258
|
-
const { patches } = planLink({
|
|
270
|
+
const { linked, patches } = planLink({
|
|
259
271
|
config,
|
|
260
|
-
input:
|
|
261
|
-
path: String(input.path),
|
|
262
|
-
data: input.data
|
|
263
|
-
}
|
|
272
|
+
input: linkPlanInputOf(input)
|
|
264
273
|
});
|
|
274
|
+
if (linked.length > 0 && input.onLinked === void 0) {
|
|
275
|
+
const named = linked.map((at) => `${at.path} (from ${at.from})`);
|
|
276
|
+
rejectData(`Linking through "${String(input.path)}" reaches what another linked system provides: ${named.join(", ")}. Say whether to take them (\`onLinked: 'take'\`) or keep them where they come from (\`onLinked: 'keep'\`).`, ["onLinked"]);
|
|
277
|
+
}
|
|
265
278
|
if (patches.length === 0) return config;
|
|
266
279
|
return config.applyAll(patches).withDerivedRows();
|
|
267
280
|
}
|
|
@@ -270,17 +283,14 @@ const LinkedSystem = defineEntity({
|
|
|
270
283
|
input: linkInput,
|
|
271
284
|
readOnly: true,
|
|
272
285
|
label: "Plan a link",
|
|
273
|
-
description: "What `link` with the same input replaces — rows of yours deleted so the source shows through,
|
|
286
|
+
description: "What `link` with the same input replaces — rows of yours deleted so the source shows through, every path another linked system provides (`linked`, turned into extensions when `onLinked` says take), and members left alone because they are already here from the same origin. Writes nothing.",
|
|
274
287
|
scope: "item",
|
|
275
288
|
title: (entity) => `Plan a link from ${entity}`,
|
|
276
289
|
example: linkExample,
|
|
277
290
|
handler: (input, config) => {
|
|
278
291
|
const { patches: _patches, ...plan } = planLink({
|
|
279
292
|
config,
|
|
280
|
-
input:
|
|
281
|
-
path: String(input.path),
|
|
282
|
-
data: input.data
|
|
283
|
-
}
|
|
293
|
+
input: linkPlanInputOf(input)
|
|
284
294
|
});
|
|
285
295
|
return plan;
|
|
286
296
|
}
|
|
@@ -413,8 +413,7 @@ function planCopy({ config, input }) {
|
|
|
413
413
|
const removal = /* @__PURE__ */ new Map();
|
|
414
414
|
for (const { kind, at, named } of taking) {
|
|
415
415
|
if (!named) continue;
|
|
416
|
-
|
|
417
|
-
if (!stored || !isMintedRow(stored)) continue;
|
|
416
|
+
if (config.storedBody(kind, at) === void 0) continue;
|
|
418
417
|
if (config.resolve(kind, at)?.borrowedFrom !== slug) continue;
|
|
419
418
|
const accessor = config.accessorOf(kind) ?? kind;
|
|
420
419
|
if (!covers({
|
|
@@ -189,6 +189,9 @@ type PropDecl<Path extends string = string> = SlotDecl | ForwardDecl<Path> | {
|
|
|
189
189
|
} | {
|
|
190
190
|
type: 'composite';
|
|
191
191
|
value: Ref$1;
|
|
192
|
+
/** The layer the chosen member styles; the root by default. Authored as its name, stored as a
|
|
193
|
+
* layer ref. */
|
|
194
|
+
layer?: string | Ref$1;
|
|
192
195
|
required?: boolean;
|
|
193
196
|
when?: PropCondition;
|
|
194
197
|
} | {
|
|
@@ -6,10 +6,21 @@ import { Config, Patch, TreeNode } from "../../framework/Config.js";
|
|
|
6
6
|
/** What one op names, keyed by accessor the way the pin's `link` is: every entry of the kind, or the
|
|
7
7
|
* source's paths, where a folder names its members. `'*'` alone is every kind the source offers. */
|
|
8
8
|
type LinkPaths = '*' | Readonly<Record<string, '*' | readonly string[]>>;
|
|
9
|
+
/** What a link does at a path held through another linked system: `'take'` makes the row follow this
|
|
10
|
+
* source, `'keep'` leaves it with the system it comes from. */
|
|
11
|
+
type OnLinked = 'keep' | 'take';
|
|
9
12
|
interface LinkPlanInput {
|
|
10
13
|
/** The pin's slug. */
|
|
11
14
|
readonly path: string;
|
|
12
15
|
readonly data: LinkPaths;
|
|
16
|
+
/** Planned as `'take'` when omitted; the `link` op refuses without it while `linked` is not empty. */
|
|
17
|
+
readonly onLinked?: OnLinked;
|
|
18
|
+
}
|
|
19
|
+
/** A path the link reaches that another linked system provides, or declares under a row of this
|
|
20
|
+
* config's own. */
|
|
21
|
+
interface LinkedElsewhere extends EntityAddress {
|
|
22
|
+
/** The slug of the pin it comes through. */
|
|
23
|
+
readonly from: string;
|
|
13
24
|
}
|
|
14
25
|
/** One row a link mints. `named` when a path the call named covers it; otherwise it comes along
|
|
15
26
|
* because something linked points at it. */
|
|
@@ -25,6 +36,8 @@ interface LinkPlan {
|
|
|
25
36
|
readonly replaces: number;
|
|
26
37
|
/** Rows of this config's own deleted so the source's row shows through at the path. */
|
|
27
38
|
readonly addresses: readonly EntityAddress[];
|
|
39
|
+
/** Every path the link reaches that another linked system provides, whatever `onLinked` says. */
|
|
40
|
+
readonly linked: readonly LinkedElsewhere[];
|
|
28
41
|
/** Rows held through another pin, turned into extensions through this one. */
|
|
29
42
|
readonly extended: readonly EntityAddress[];
|
|
30
43
|
/** Members already here from the source's own origin, left alone and kept out of the declaration. */
|
|
@@ -85,6 +98,11 @@ interface SourceRowState {
|
|
|
85
98
|
readonly linked: boolean;
|
|
86
99
|
/** Rows of this config's own a `link` would write over. */
|
|
87
100
|
readonly replaces: number;
|
|
101
|
+
/** Members another linked system provides or also declares, which a `link` asks about through
|
|
102
|
+
* `onLinked`. */
|
|
103
|
+
readonly linkedElsewhere: number;
|
|
104
|
+
/** The slugs of the pins those come through. */
|
|
105
|
+
readonly linkedFrom: readonly string[];
|
|
88
106
|
/** Members already here from the source's own origin, through another pin. */
|
|
89
107
|
readonly shared: number;
|
|
90
108
|
/** That origin's name, when `shared` is above zero. */
|
|
@@ -97,10 +115,11 @@ interface SourceRowState {
|
|
|
97
115
|
* The declaration goes first. A row of this config's own that other rows point at can only be deleted
|
|
98
116
|
* once the declaration covers the path, since the config refuses a delete that leaves a referrer
|
|
99
117
|
* dangling. A row held through another pin is not deleted — that pin's declaration would mint it
|
|
100
|
-
* again, and declaring one path on two pins is a collision nothing derives
|
|
101
|
-
* extension through this pin: a row of this config's own that shadows the other pin's and
|
|
102
|
-
* source.
|
|
103
|
-
*
|
|
118
|
+
* again, and declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it
|
|
119
|
+
* becomes an extension through this pin: a row of this config's own that shadows the other pin's and
|
|
120
|
+
* follows this source. With `'keep'` it stays with the other pin and out of the declaration. A member
|
|
121
|
+
* already here from the source's own origin is left alone and kept out of the declaration, so a
|
|
122
|
+
* folder that holds one is declared by its other members.
|
|
104
123
|
*/
|
|
105
124
|
declare function planLink({
|
|
106
125
|
config,
|
|
@@ -159,4 +178,4 @@ declare function sourceRowStates({
|
|
|
159
178
|
readonly slug: string;
|
|
160
179
|
}): SourceRowState[];
|
|
161
180
|
//#endregion
|
|
162
|
-
export { BreakOutcome, BreakPlan, BreakPlanInput, BreakPlanRow, BreakReach, LinkArrival, LinkPaths, LinkPlan, LinkPlanInput, SourceRowState, UnlinkPlan, UnlinkPlanInput, planBreak, planLink, planUnlink, sourceRowStates };
|
|
181
|
+
export { BreakOutcome, BreakPlan, BreakPlanInput, BreakPlanRow, BreakReach, LinkArrival, LinkPaths, LinkPlan, LinkPlanInput, LinkedElsewhere, OnLinked, SourceRowState, UnlinkPlan, UnlinkPlanInput, planBreak, planLink, planUnlink, sourceRowStates };
|
|
@@ -42,6 +42,20 @@ function sharedWithOrigin({ config, source, slug, kind, path }) {
|
|
|
42
42
|
if (!theirs || !mine || theirs.key !== mine.key) return void 0;
|
|
43
43
|
return theirs.pin.displayName ?? theirs.key;
|
|
44
44
|
}
|
|
45
|
+
/** Another pin whose declaration covers the path and whose source has it: the pin the path would
|
|
46
|
+
* derive from if this config held nothing there. */
|
|
47
|
+
function declaredElsewhere({ config, slug, kind, path }) {
|
|
48
|
+
const accessor = config.accessorOf(kind) ?? kind;
|
|
49
|
+
for (const pin of config.list(PIN_KIND)) {
|
|
50
|
+
if (pin.path === slug) continue;
|
|
51
|
+
if (!covers({
|
|
52
|
+
declared: declarationOf(config, pin.path),
|
|
53
|
+
accessor,
|
|
54
|
+
path
|
|
55
|
+
})) continue;
|
|
56
|
+
if (config.sourceFor(pin.path)?.resolve(kind, path)) return pin.path;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
45
59
|
/**
|
|
46
60
|
* Link paths of a source: the declaration that mints them, then the edits that let them show through
|
|
47
61
|
* where this config already holds something.
|
|
@@ -49,10 +63,11 @@ function sharedWithOrigin({ config, source, slug, kind, path }) {
|
|
|
49
63
|
* The declaration goes first. A row of this config's own that other rows point at can only be deleted
|
|
50
64
|
* once the declaration covers the path, since the config refuses a delete that leaves a referrer
|
|
51
65
|
* dangling. A row held through another pin is not deleted — that pin's declaration would mint it
|
|
52
|
-
* again, and declaring one path on two pins is a collision nothing derives
|
|
53
|
-
* extension through this pin: a row of this config's own that shadows the other pin's and
|
|
54
|
-
* source.
|
|
55
|
-
*
|
|
66
|
+
* again, and declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it
|
|
67
|
+
* becomes an extension through this pin: a row of this config's own that shadows the other pin's and
|
|
68
|
+
* follows this source. With `'keep'` it stays with the other pin and out of the declaration. A member
|
|
69
|
+
* already here from the source's own origin is left alone and kept out of the declaration, so a
|
|
70
|
+
* folder that holds one is declared by its other members.
|
|
56
71
|
*/
|
|
57
72
|
function planLink({ config, input }) {
|
|
58
73
|
const { path: slug } = input;
|
|
@@ -66,12 +81,13 @@ function planLink({ config, input }) {
|
|
|
66
81
|
verb: "link"
|
|
67
82
|
});
|
|
68
83
|
const addresses = [];
|
|
84
|
+
const linked = [];
|
|
69
85
|
const extended = [];
|
|
70
86
|
const shared = [];
|
|
71
87
|
const shadows = [];
|
|
72
88
|
/** Per accessor, what the declaration gains: the kind whole, or paths. */
|
|
73
89
|
const gains = /* @__PURE__ */ new Map();
|
|
74
|
-
let
|
|
90
|
+
let leftAnywhere = false;
|
|
75
91
|
const shadow = (kind, path) => {
|
|
76
92
|
const held = config.resolve(kind, path);
|
|
77
93
|
if (!held || held.borrowedFrom === slug) return true;
|
|
@@ -86,10 +102,16 @@ function planLink({ config, input }) {
|
|
|
86
102
|
kind,
|
|
87
103
|
path
|
|
88
104
|
});
|
|
89
|
-
|
|
105
|
+
leftAnywhere = true;
|
|
90
106
|
return false;
|
|
91
107
|
}
|
|
92
|
-
|
|
108
|
+
const from = held.borrowedFrom ?? declaredElsewhere({
|
|
109
|
+
config,
|
|
110
|
+
slug,
|
|
111
|
+
kind,
|
|
112
|
+
path
|
|
113
|
+
});
|
|
114
|
+
if (from === void 0) {
|
|
93
115
|
addresses.push({
|
|
94
116
|
kind,
|
|
95
117
|
path
|
|
@@ -101,6 +123,20 @@ function planLink({ config, input }) {
|
|
|
101
123
|
});
|
|
102
124
|
return true;
|
|
103
125
|
}
|
|
126
|
+
linked.push({
|
|
127
|
+
kind,
|
|
128
|
+
path,
|
|
129
|
+
from
|
|
130
|
+
});
|
|
131
|
+
if (input.onLinked === "keep") {
|
|
132
|
+
if (held.borrowedFrom === void 0) shadows.push({
|
|
133
|
+
kind,
|
|
134
|
+
operation: "delete",
|
|
135
|
+
path
|
|
136
|
+
});
|
|
137
|
+
leftAnywhere = true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
104
140
|
const stored = config.storedBody(kind, path);
|
|
105
141
|
const minted = stored !== void 0 && isMintedRow(stored);
|
|
106
142
|
extended.push({
|
|
@@ -145,7 +181,7 @@ function planLink({ config, input }) {
|
|
|
145
181
|
}
|
|
146
182
|
const declares = [];
|
|
147
183
|
let declared = current;
|
|
148
|
-
if (current !== "*") if (input.data === "*" && !
|
|
184
|
+
if (current !== "*") if (input.data === "*" && !leftAnywhere) {
|
|
149
185
|
declared = "*";
|
|
150
186
|
declares.push({
|
|
151
187
|
kind: PIN_KIND,
|
|
@@ -192,6 +228,7 @@ function planLink({ config, input }) {
|
|
|
192
228
|
}),
|
|
193
229
|
replaces: addresses.length,
|
|
194
230
|
addresses,
|
|
231
|
+
linked,
|
|
195
232
|
extended,
|
|
196
233
|
shared,
|
|
197
234
|
patches
|
|
@@ -485,7 +522,7 @@ function planBreak({ config, input }) {
|
|
|
485
522
|
const pointing = /* @__PURE__ */ new Map();
|
|
486
523
|
/** Folders drawn through the pin by a pointer of this config's own, released once their members are copied. */
|
|
487
524
|
const pointedFolders = [];
|
|
488
|
-
const reach = ({ kind, path, reach }) => {
|
|
525
|
+
const reach = ({ kind, path, reach: how }) => {
|
|
489
526
|
const held = config.resolve(kind, path);
|
|
490
527
|
if (held?.borrowedFrom === slug) {
|
|
491
528
|
copying.path(kind, path);
|
|
@@ -495,7 +532,7 @@ function planBreak({ config, input }) {
|
|
|
495
532
|
folder: false,
|
|
496
533
|
refs: [ref(kind, path, slug).__ref],
|
|
497
534
|
outcome: "copied",
|
|
498
|
-
reach
|
|
535
|
+
reach: how
|
|
499
536
|
});
|
|
500
537
|
return;
|
|
501
538
|
}
|
|
@@ -516,9 +553,15 @@ function planBreak({ config, input }) {
|
|
|
516
553
|
folder: true,
|
|
517
554
|
refs: [ref(kind, path, slug).__ref],
|
|
518
555
|
outcome: "copied",
|
|
519
|
-
reach
|
|
556
|
+
reach: how
|
|
520
557
|
});
|
|
558
|
+
return;
|
|
521
559
|
}
|
|
560
|
+
for (const member of config.members(kind, path)) if (member.borrowedFrom === slug) reach({
|
|
561
|
+
kind,
|
|
562
|
+
path: member.path,
|
|
563
|
+
reach: "taken"
|
|
564
|
+
});
|
|
522
565
|
return;
|
|
523
566
|
}
|
|
524
567
|
const refs = drawnThroughPin({
|
|
@@ -534,7 +577,7 @@ function planBreak({ config, input }) {
|
|
|
534
577
|
}
|
|
535
578
|
pointing.set(`${kind}:${path}`, {
|
|
536
579
|
refs,
|
|
537
|
-
reach
|
|
580
|
+
reach: how
|
|
538
581
|
});
|
|
539
582
|
};
|
|
540
583
|
if (scoped) for (const { kind, accessor, paths } of wantedKinds({
|
|
@@ -730,6 +773,8 @@ function sourceRowStates({ config, slug }) {
|
|
|
730
773
|
if (members.length === 0) continue;
|
|
731
774
|
let linked = 0;
|
|
732
775
|
let local = 0;
|
|
776
|
+
let elsewhere = 0;
|
|
777
|
+
const linkedFrom = /* @__PURE__ */ new Set();
|
|
733
778
|
let shared = 0;
|
|
734
779
|
let sharedOrigin;
|
|
735
780
|
for (const leaf of members) {
|
|
@@ -739,7 +784,6 @@ function sourceRowStates({ config, slug }) {
|
|
|
739
784
|
linked += 1;
|
|
740
785
|
continue;
|
|
741
786
|
}
|
|
742
|
-
local += 1;
|
|
743
787
|
const origin = sharedWithOrigin({
|
|
744
788
|
config: derived,
|
|
745
789
|
source,
|
|
@@ -747,10 +791,19 @@ function sourceRowStates({ config, slug }) {
|
|
|
747
791
|
kind,
|
|
748
792
|
path: leaf.path
|
|
749
793
|
});
|
|
794
|
+
const from = origin === void 0 ? held.borrowedFrom ?? declaredElsewhere({
|
|
795
|
+
config: derived,
|
|
796
|
+
slug,
|
|
797
|
+
kind,
|
|
798
|
+
path: leaf.path
|
|
799
|
+
}) : void 0;
|
|
750
800
|
if (origin !== void 0) {
|
|
751
801
|
shared += 1;
|
|
752
802
|
sharedOrigin ??= origin;
|
|
753
|
-
}
|
|
803
|
+
} else if (from !== void 0) {
|
|
804
|
+
elsewhere += 1;
|
|
805
|
+
linkedFrom.add(from);
|
|
806
|
+
} else local += 1;
|
|
754
807
|
}
|
|
755
808
|
rows.push({
|
|
756
809
|
kind,
|
|
@@ -760,7 +813,9 @@ function sourceRowStates({ config, slug }) {
|
|
|
760
813
|
members: members.length,
|
|
761
814
|
held: linked,
|
|
762
815
|
linked: linked === members.length,
|
|
763
|
-
replaces: local
|
|
816
|
+
replaces: local,
|
|
817
|
+
linkedElsewhere: elsewhere,
|
|
818
|
+
linkedFrom: [...linkedFrom],
|
|
764
819
|
shared,
|
|
765
820
|
...sharedOrigin === void 0 ? {} : { sharedOrigin }
|
|
766
821
|
});
|
|
@@ -72,7 +72,7 @@ interface RecordedSource {
|
|
|
72
72
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
73
73
|
* that replaced it (see `detectedWireVersion`).
|
|
74
74
|
*/
|
|
75
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
75
|
+
declare const SERIALIZED_CONFIG_VERSION = 20260928215509;
|
|
76
76
|
interface SerializedConfig {
|
|
77
77
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
78
78
|
readonly version: number;
|
package/dist/framework/Config.js
CHANGED
|
@@ -5135,7 +5135,7 @@ var Config = class Config {
|
|
|
5135
5135
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
5136
5136
|
hydrateFrom(stored, options) {
|
|
5137
5137
|
const claimed = schemaVersionOf(stored);
|
|
5138
|
-
if (claimed >
|
|
5138
|
+
if (claimed > 20260928215509) throw new SchemaVersionTooNew(claimed);
|
|
5139
5139
|
const wire = upgradeSerializedConfig(stored);
|
|
5140
5140
|
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, or port the repo once with \`uds migrate\`.`);
|
|
5141
5141
|
const leftover = wire.options;
|
|
@@ -84,6 +84,9 @@ interface ComponentRuleClass {
|
|
|
84
84
|
* emitted module tests it with `=== true`. */
|
|
85
85
|
readonly when: Record<string, unknown>;
|
|
86
86
|
readonly className: string;
|
|
87
|
+
/** Set when the class comes from a composite PROP rather than a style rule: the member whose bag
|
|
88
|
+
* the class paints. See {@link compositePropRuleClasses}. */
|
|
89
|
+
readonly composite?: string;
|
|
87
90
|
}
|
|
88
91
|
/**
|
|
89
92
|
* Every conditional class a component's style rules produce.
|
|
@@ -137,23 +140,59 @@ declare function componentMotionClasses(config: Config, path: string): Component
|
|
|
137
140
|
* defaults, because a value the caller didn't set has to read the default — the same rule
|
|
138
141
|
* {@link layerStyles} follows.
|
|
139
142
|
*
|
|
140
|
-
* Keyed by layer
|
|
141
|
-
*
|
|
143
|
+
* Keyed by layer: a prop lands on the layer it names (the root by default), or on the layer that
|
|
144
|
+
* forwards it. Each member contributes two classes, the composite's own and the component's rule
|
|
145
|
+
* class for it; {@link componentRuleClasses} lists the second too, for the module and the sheet, so
|
|
146
|
+
* a projection reading both skips its `composite` entries.
|
|
142
147
|
*/
|
|
143
148
|
declare function componentPropClasses(config: Config, path: string, state?: Record<string, unknown>): Record<string, string[]>;
|
|
149
|
+
/** One composite an instance's props pick, and where it lands. */
|
|
150
|
+
interface PickedComposite {
|
|
151
|
+
readonly prop: string;
|
|
152
|
+
readonly layer: string;
|
|
153
|
+
/** The member's path (`textVariant/title1/emphasized`). */
|
|
154
|
+
readonly member: string;
|
|
155
|
+
/** The value as a caller writes it, the member's path under its group (`title1/emphasized`). */
|
|
156
|
+
readonly value: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The composites an instance's props pick, resolved over the component's defaults: each one beats
|
|
160
|
+
* the component's own rules on its layer (see {@link compositePropRuleClasses}).
|
|
161
|
+
*
|
|
162
|
+
* A projection that paints a component's rule declarations as props, as the component editor's cells
|
|
163
|
+
* do, needs this to hold that precedence: a rule's `fontSize` painted as a prop would otherwise beat
|
|
164
|
+
* the member a caller picked, where the stylesheet has the member win.
|
|
165
|
+
*/
|
|
166
|
+
declare function componentPropComposites(config: Config, path: string, state?: Record<string, unknown>): PickedComposite[];
|
|
167
|
+
/**
|
|
168
|
+
* A style rule's bag with each composite it names written out in place: the member's styles first,
|
|
169
|
+
* the bag's own keys over them, and the composite's marker (`--<prefix>-composite-<group>`), so
|
|
170
|
+
* `_on<Group><Member>` still finds it.
|
|
171
|
+
*
|
|
172
|
+
* A composite a component's OWN rule names is part of that layer's defaults, the same as a
|
|
173
|
+
* `fontSize` beside it: the layer's element beats it with its variants, and a key the bag spells
|
|
174
|
+
* next to it overrides it (`{ textVariant: 'ui6', lineHeight: 'tight' }`). Forwarded to the element
|
|
175
|
+
* as a prop instead, it arrived as a caller's pick, and a caller's pick beats the element's
|
|
176
|
+
* variants (see {@link compositePropRuleClasses}), so FormInput's own `ui6` beat the `size="xs"`
|
|
177
|
+
* it renders its Input at. Only a composite passed as a prop at a call site takes that route.
|
|
178
|
+
*
|
|
179
|
+
* `element` is the layer's element. A key is a composite when the element declares it as one, so a
|
|
180
|
+
* plain-tag layer (which declares nothing) and a key naming no member are left as they are.
|
|
181
|
+
*/
|
|
182
|
+
declare function inlineRuleComposites(config: Config, element: unknown, bag: Record<string, unknown>): Record<string, unknown>;
|
|
144
183
|
/**
|
|
145
184
|
* The props a style rule's bag sends to each layer's ELEMENT rather than to the stylesheet, for one
|
|
146
185
|
* instance. The same split the emitted module makes when it builds a layer's routed bundle.
|
|
147
186
|
*
|
|
148
187
|
* What makes a bag key CSS is that a style property claims it: that value lives in the stylesheet
|
|
149
188
|
* under the rule's condition class. Everything else in the bag is a prop of the layer's element and
|
|
150
|
-
* travels to it as one, whether or not the element declares it:
|
|
151
|
-
* `Text`-backed layer, which the receiver resolves to its own class), the receiver's own variant or
|
|
189
|
+
* travels to it as one, whether or not the element declares it: the receiver's own variant or
|
|
152
190
|
* scalar prop (`size: 'sm'` on an Icon layer), or an attribute of a plain element (`as: 'div'`,
|
|
153
191
|
* `type: 'button'`, `aria-hidden`), or a value the rule hands a receiver's forward or slot
|
|
154
192
|
* (`children: 'AI'` on a badge layer, `icon: 'XIcon'` on a button layer), which the emitted module
|
|
155
|
-
* routes the same way. A style property under another name
|
|
156
|
-
*
|
|
193
|
+
* routes the same way. A style property under another name, a composite (written into the rule's
|
|
194
|
+
* declarations, {@link inlineRuleComposites}) and motion stay out, since the stylesheet and the
|
|
195
|
+
* motion classes already carry them.
|
|
157
196
|
*
|
|
158
197
|
* Forwarding rather than resolving is what makes a layer's styling live-editable at all: a class only
|
|
159
198
|
* exists once a build has emitted the stylesheet, so an edit that makes a NEW style rule paints
|
|
@@ -258,4 +297,4 @@ declare function stylePropClasses(config: Config, path: string): Map<string, str
|
|
|
258
297
|
*/
|
|
259
298
|
declare function modifierUtilitiesUsed(config: Config): Set<string>;
|
|
260
299
|
//#endregion
|
|
261
|
-
export { ComponentRuleClass, SplitStyleProps, componentClassBase, componentCompositeClasses, componentLayerClass, componentMotionClasses, componentPropClasses, componentRuleClasses, forceModeAttribute, forceModeAttributeOf, forceModeProp, forceModePropGroup, forceModePropValue, forceModeProps, forceStateAttribute, isForceModeProp, kebabComponent, layerRoutedProps, modifierUtilitiesUsed, motionClassName, ruleCondition, splitStyleProps, stylePropClassBase, stylePropClassName, stylePropClasses, styleRuleMotionClasses };
|
|
300
|
+
export { ComponentRuleClass, PickedComposite, SplitStyleProps, componentClassBase, componentCompositeClasses, componentLayerClass, componentMotionClasses, componentPropClasses, componentPropComposites, componentRuleClasses, forceModeAttribute, forceModeAttributeOf, forceModeProp, forceModePropGroup, forceModePropValue, forceModeProps, forceStateAttribute, inlineRuleComposites, isForceModeProp, kebabComponent, layerRoutedProps, modifierUtilitiesUsed, motionClassName, ruleCondition, splitStyleProps, stylePropClassBase, stylePropClassName, stylePropClasses, styleRuleMotionClasses };
|