@yahoo/uds-create-config 5.68.5 → 5.70.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.
Files changed (42) hide show
  1. package/dist/configs/react-native-system.d.ts +18 -0
  2. package/dist/configs/system.js +4 -0
  3. package/dist/entities/native/NativeSettings.d.ts +18 -0
  4. package/dist/entities/system/Component.js +19 -1
  5. package/dist/entities/system/LinkedSystem.d.ts +2 -0
  6. package/dist/entities/system/LinkedSystem.js +14 -4
  7. package/dist/entities/system/Settings.d.ts +72 -1
  8. package/dist/entities/system/Settings.js +58 -6
  9. package/dist/entities/system/link-plan.d.ts +34 -1
  10. package/dist/entities/system/link-plan.js +157 -2
  11. package/dist/framework/Config.d.ts +11 -1
  12. package/dist/framework/Config.js +31 -2
  13. package/dist/framework/class-names.d.ts +1 -1
  14. package/dist/framework/component-api-changes.d.ts +14 -1
  15. package/dist/framework/component-api-changes.js +22 -6
  16. package/dist/framework/component-states.d.ts +16 -1
  17. package/dist/framework/component-states.js +17 -1
  18. package/dist/framework/defineEntity.d.ts +2 -1
  19. package/dist/framework/defineEntity.js +1 -0
  20. package/dist/framework/plan.d.ts +5 -0
  21. package/dist/framework/plan.js +9 -2
  22. package/dist/framework/registry.d.ts +5 -0
  23. package/dist/framework/registry.js +2 -1
  24. package/dist/framework/schema-version.d.ts +1 -1
  25. package/dist/framework/schema-version.js +5 -5
  26. package/dist/index.d.ts +5 -5
  27. package/dist/index.js +4 -4
  28. package/dist/migrations/20261102143821_default_colors.d.ts +12 -0
  29. package/dist/migrations/20261102143821_default_colors.js +10 -0
  30. package/dist/migrations/20261102185610_link_replace.d.ts +7 -0
  31. package/dist/migrations/20261102185610_link_replace.js +8 -0
  32. package/dist/spec/bake.js +35 -2
  33. package/dist/spec/cell.js +11 -2
  34. package/dist/spec/index.d.ts +2 -2
  35. package/dist/spec/index.js +2 -2
  36. package/dist/spec/preview-content.js +3 -1
  37. package/dist/spec/preview-elements.d.ts +12 -4
  38. package/dist/spec/preview-elements.js +6 -1
  39. package/dist/spec/rewrite-refs.d.ts +14 -2
  40. package/dist/spec/rewrite-refs.js +30 -10
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +2 -2
@@ -76,6 +76,24 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
76
76
  reason: _$zod.ZodString;
77
77
  }, _$zod_v4_core0.$strict>>>;
78
78
  }, _$zod_v4_core0.$strict>>;
79
+ defaults: _$zod.ZodOptional<_$zod.ZodObject<{
80
+ background: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
81
+ __ref: _$zod.ZodString;
82
+ }, _$zod_v4_core0.$strip>]>, _$zod.ZodObject<{
83
+ value: _$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
84
+ __ref: _$zod.ZodString;
85
+ }, _$zod_v4_core0.$strip>]>;
86
+ output: _$zod.ZodOptional<_$zod.ZodBoolean>;
87
+ }, _$zod_v4_core0.$strict>]>>;
88
+ color: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
89
+ __ref: _$zod.ZodString;
90
+ }, _$zod_v4_core0.$strip>]>, _$zod.ZodObject<{
91
+ value: _$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
92
+ __ref: _$zod.ZodString;
93
+ }, _$zod_v4_core0.$strip>]>;
94
+ output: _$zod.ZodOptional<_$zod.ZodBoolean>;
95
+ }, _$zod_v4_core0.$strict>]>>;
96
+ }, _$zod_v4_core0.$strict>>;
79
97
  }, "css" | "playground" | "canvas"> & {
80
98
  canvas: _$zod.ZodOptional<_$zod.ZodObject<{
81
99
  packageAliases: _$zod.ZodOptional<_$zod.ZodRecord<_$zod.ZodString, _$zod.ZodString>>;
@@ -35,6 +35,8 @@ import { variantValuesListWithBodiesMigration } from "../migrations/202610271844
35
35
  import { lintIgnoreMigration } from "../migrations/20261027205147_lint_ignore.js";
36
36
  import { componentMapPropsMigration } from "../migrations/20261030134149_component_map_props.js";
37
37
  import { layerPrefixMigration } from "../migrations/20261030163028_layer_prefix.js";
38
+ import { defaultColorsMigration } from "../migrations/20261102143821_default_colors.js";
39
+ import { linkReplaceMigration } from "../migrations/20261102185610_link_replace.js";
38
40
  import { CanvasRole } from "../entities/system/CanvasRole.js";
39
41
  import { GlobalStyle } from "../entities/system/GlobalStyle.js";
40
42
  import { Guidance } from "../entities/system/Guidance.js";
@@ -203,5 +205,7 @@ if (!registeredSchemaMigrations().has(20261027184442)) registerSchemaMigrations(
203
205
  if (!registeredSchemaMigrations().has(20261027205147)) registerSchemaMigrations(lintIgnoreMigration);
204
206
  if (!registeredSchemaMigrations().has(20261030134149)) registerSchemaMigrations(componentMapPropsMigration);
205
207
  if (!registeredSchemaMigrations().has(20261030163028)) registerSchemaMigrations(layerPrefixMigration);
208
+ if (!registeredSchemaMigrations().has(20261102143821)) registerSchemaMigrations(defaultColorsMigration);
209
+ if (!registeredSchemaMigrations().has(20261102185610)) registerSchemaMigrations(linkReplaceMigration);
206
210
  //#endregion
207
211
  export { System };
@@ -65,6 +65,24 @@ declare const NativeSettings: EntityClass<z.ZodObject<Omit<{
65
65
  reason: z.ZodString;
66
66
  }, z.core.$strict>>>;
67
67
  }, z.core.$strict>>;
68
+ defaults: z.ZodOptional<z.ZodObject<{
69
+ background: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
70
+ __ref: z.ZodString;
71
+ }, z.core.$strip>]>, z.ZodObject<{
72
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
73
+ __ref: z.ZodString;
74
+ }, z.core.$strip>]>;
75
+ output: z.ZodOptional<z.ZodBoolean>;
76
+ }, z.core.$strict>]>>;
77
+ color: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
78
+ __ref: z.ZodString;
79
+ }, z.core.$strip>]>, z.ZodObject<{
80
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
81
+ __ref: z.ZodString;
82
+ }, z.core.$strip>]>;
83
+ output: z.ZodOptional<z.ZodBoolean>;
84
+ }, z.core.$strict>]>>;
85
+ }, z.core.$strict>>;
68
86
  }, "css" | "playground" | "canvas"> & {
69
87
  canvas: z.ZodOptional<z.ZodObject<{
70
88
  packageAliases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -152,6 +152,19 @@ function freeLayerKey(config, path, hint = "el") {
152
152
  return `${hint}${ordinal}`;
153
153
  }
154
154
  /**
155
+ * The name a duplicate of the layer `source` takes: its name without a trailing number, numbered
156
+ * from 2 past every name the component already holds, so `box` copies to `box2` and `box2` to
157
+ * `box3` rather than `box21`.
158
+ */
159
+ function duplicateLayerKey({ config, path, source }) {
160
+ const body = config.resolve("component", path)?.toJSON();
161
+ const taken = new Set([...Object.keys(body?.layers ?? {}), ...Object.keys(body?.anatomy ?? {})]);
162
+ const base = source.replace(/\d+$/, "") || source;
163
+ let ordinal = 2;
164
+ while (taken.has(`${base}${ordinal}`)) ordinal += 1;
165
+ return `${base}${ordinal}`;
166
+ }
167
+ /**
155
168
  * A `kind:path` marker string as the ref it means.
156
169
  *
157
170
  * A spec element stores its type as a marker (`component:primitives/Box`), and `element` accepts a
@@ -2026,6 +2039,7 @@ function withoutProps(conditions, names) {
2026
2039
  }
2027
2040
  const ComponentEntity = defineEntity({
2028
2041
  kind: "component",
2042
+ parts: true,
2029
2043
  rebaseLinkedBody: (args) => {
2030
2044
  const body = { ...translateLinkedStyleBags({
2031
2045
  ...args,
@@ -2427,7 +2441,11 @@ count: z.number().int().min(1).max(50).optional() }).prefault({})
2427
2441
  let next = config;
2428
2442
  let previous = source;
2429
2443
  for (let n = 0; n < count; n++) {
2430
- const key = freeLayerKey(next, path, source);
2444
+ const key = duplicateLayerKey({
2445
+ config: next,
2446
+ path,
2447
+ source
2448
+ });
2431
2449
  const siblings = (next.resolve("component", path)?.toJSON())?.anatomy?.[parent]?.children ?? [];
2432
2450
  const index = siblings.indexOf(previous) + 1;
2433
2451
  next = next.run([{
@@ -123,6 +123,7 @@ declare const LinkedSystemDefinition: EntityClass<z.ZodObject<{
123
123
  keep: "keep";
124
124
  take: "take";
125
125
  }>>;
126
+ replace: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>>;
126
127
  }, z.core.$strip>;
127
128
  };
128
129
  readonly 'link-plan': {
@@ -133,6 +134,7 @@ declare const LinkedSystemDefinition: EntityClass<z.ZodObject<{
133
134
  keep: "keep";
134
135
  take: "take";
135
136
  }>>;
137
+ replace: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>>;
136
138
  }, z.core.$strip>;
137
139
  };
138
140
  readonly unlink: {
@@ -171,7 +171,16 @@ const linkInput = z.object({
171
171
  data: z.union([z.literal("*"), z.record(z.string(), copyPaths)]),
172
172
  /** What to do at a path another linked system provides: `'take'` makes it follow this source,
173
173
  * `'keep'` leaves it where it comes from. Required when there is one; `link-plan` lists them. */
174
- onLinked: z.enum(["keep", "take"]).optional()
174
+ onLinked: z.enum(["keep", "take"]).optional(),
175
+ /**
176
+ * A component this config holds under one name, replaced with the source's of another name, keyed
177
+ * by accessor: `{ components: { SelectContent: 'SelectMenu' } }` replaces the `SelectContent` this
178
+ * config holds with the source's `SelectMenu`. Every ref to `SelectContent` is renamed to
179
+ * `SelectMenu`, so design files and code follow the way they follow a rename, and the system
180
+ * `SelectContent` came through stops deriving it unless its own rows still use it. Each source path
181
+ * is one `data` names; `link-plan` lists each in `replaced`. A take at the same name is `onLinked`.
182
+ */
183
+ replace: z.record(z.string(), z.record(z.string().min(1), z.string().min(1))).optional()
175
184
  });
176
185
  const unlinkInput = z.object({
177
186
  path: pathInput("linked-system"),
@@ -216,7 +225,8 @@ function linkPlanInputOf(input) {
216
225
  return {
217
226
  path: String(input.path),
218
227
  data: input.data,
219
- ...input.onLinked === void 0 ? {} : { onLinked: input.onLinked }
228
+ ...input.onLinked === void 0 ? {} : { onLinked: input.onLinked },
229
+ ...input.replace === void 0 ? {} : { replace: input.replace }
220
230
  };
221
231
  }
222
232
  /** A `link` or `unlink` example: one entity the source offers, under the accessor this config files it by. */
@@ -310,7 +320,7 @@ const LinkedSystemDefinition = defineEntity({
310
320
  input: linkInput,
311
321
  readOnly: false,
312
322
  label: "Link from",
313
- description: "Draw entities from a linked system, following the source: `data` names them by accessor — `{ tokens: ['color/brand', 'color'] }` takes an entity and a folder's members, `{ tokens: '*' }` every token, and `'*'` the whole system. What this config already holds at those paths is replaced by theirs, so run `linked-system/link-plan` with the same input first to see what that is. To hold their values as your own instead, `copy`.",
323
+ description: "Draw entities from a linked system, following the source: `data` names them by accessor — `{ tokens: ['color/brand', 'color'] }` takes an entity and a folder's members, `{ tokens: '*' }` every token, and `'*'` the whole system. What this config already holds at those paths is replaced by theirs, so run `linked-system/link-plan` with the same input first to see what that is. To replace something this config holds under another name (the `SelectContent` it has with the source's `SelectMenu`), name the pair in `replace` (`{ components: { SelectContent: 'SelectMenu' } }`): every reference to the old name moves to the new one, in design files and code too. To hold their values as your own instead, `copy`.",
314
324
  scope: "item",
315
325
  approval: "reference-change",
316
326
  title: (entity) => `Link something from ${entity}`,
@@ -333,7 +343,7 @@ const LinkedSystemDefinition = defineEntity({
333
343
  input: linkInput,
334
344
  readOnly: true,
335
345
  label: "Plan a link",
336
- 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), the `options` entries another linked system holds at what a take moves, which it removes since they would apply to nothing (`dropped`), members left alone because they are already here from the same origin, paths another linked system declares that the link reaches as a different entity (`settled`), whose row stays, and why the config would refuse the link (`blocked`), a collision it would leave among them. Writes nothing.",
346
+ 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), the `options` entries another linked system holds at what a take moves, which it removes since they would apply to nothing (`dropped`), members left alone because they are already here from the same origin, paths another linked system declares that the link reaches as a different entity (`settled`), whose row stays, what `replace` replaces under another name (`replaced`: each path, what replaces it, the pin it came through, and whether it is left out of that pin or kept because rows of that pin still use it), and why the config would refuse the link (`blocked`), a collision it would leave among them. Writes nothing.",
337
347
  scope: "item",
338
348
  title: (entity) => `Plan a link from ${entity}`,
339
349
  example: linkExample,
@@ -121,6 +121,59 @@ declare const LintSectionDefinition: SubEntityClass<z.ZodObject<{
121
121
  }, z.core.$strict>>;
122
122
  interface LintSectionClass extends Named<typeof LintSectionDefinition> {}
123
123
  declare const LintSection: LintSectionClass;
124
+ /** A default colour: a CSS colour as written, or a token, which follows the modes it is painted
125
+ * under. `refTo` rather than the `Token` class, which imports back into this module. */
126
+ declare const defaultColorValue: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
127
+ __ref: z.ZodString;
128
+ }, z.core.$strip>]>;
129
+ type DefaultColorValue = z.output<typeof defaultColorValue>;
130
+ /** A default colour on its own, or with `output` saying whether the stylesheet's body rule carries
131
+ * it. */
132
+ declare const defaultColor: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
133
+ __ref: z.ZodString;
134
+ }, z.core.$strip>]>, z.ZodObject<{
135
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
136
+ __ref: z.ZodString;
137
+ }, z.core.$strip>]>;
138
+ output: z.ZodOptional<z.ZodBoolean>;
139
+ }, z.core.$strict>]>;
140
+ /** The `defaults` section — the background and text colour a system's components sit on. */
141
+ declare const DefaultsSectionDefinition: SubEntityClass<z.ZodObject<{
142
+ background: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
143
+ __ref: z.ZodString;
144
+ }, z.core.$strip>]>, z.ZodObject<{
145
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
146
+ __ref: z.ZodString;
147
+ }, z.core.$strip>]>;
148
+ output: z.ZodOptional<z.ZodBoolean>;
149
+ }, z.core.$strict>]>>;
150
+ color: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
151
+ __ref: z.ZodString;
152
+ }, z.core.$strip>]>, z.ZodObject<{
153
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
154
+ __ref: z.ZodString;
155
+ }, z.core.$strip>]>;
156
+ output: z.ZodOptional<z.ZodBoolean>;
157
+ }, z.core.$strict>]>>;
158
+ }, z.core.$strict>>;
159
+ interface DefaultsSectionClass extends Named<typeof DefaultsSectionDefinition> {}
160
+ declare const DefaultsSection: DefaultsSectionClass;
161
+ /** One default colour in its long form: the value, and whether the body rule carries it. */
162
+ interface DefaultColor {
163
+ readonly value: DefaultColorValue;
164
+ readonly output: boolean;
165
+ }
166
+ /** A system's default colours, each in its long form; an unset one is absent. */
167
+ interface DefaultColors {
168
+ readonly background?: DefaultColor;
169
+ readonly color?: DefaultColor;
170
+ }
171
+ /** A default colour as authored: the value alone, or `{ value, output }`. */
172
+ type AuthoredDefaultColor = z.output<typeof defaultColor>;
173
+ /** One default colour in its long form, whichever form it was written in. */
174
+ declare function defaultColorOf(authored: AuthoredDefaultColor | undefined): DefaultColor | undefined;
175
+ /** The `defaults` section as every reader takes it, whichever form each colour was written in. */
176
+ declare function defaultColorsOf(config: Config): DefaultColors;
124
177
  /**
125
178
  * {@link derivedInputDir} over paths alone, for a build that has walked its source graph but not yet
126
179
  * written the `file` rows the computed `inputDir` reads. `components` are the config-relative paths
@@ -175,6 +228,24 @@ declare const SettingsDefinition: EntityClass<z.ZodObject<{
175
228
  reason: z.ZodString;
176
229
  }, z.core.$strict>>>;
177
230
  }, z.core.$strict>>;
231
+ defaults: z.ZodOptional<z.ZodObject<{
232
+ background: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
233
+ __ref: z.ZodString;
234
+ }, z.core.$strip>]>, z.ZodObject<{
235
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
236
+ __ref: z.ZodString;
237
+ }, z.core.$strip>]>;
238
+ output: z.ZodOptional<z.ZodBoolean>;
239
+ }, z.core.$strict>]>>;
240
+ color: z.ZodOptional<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
241
+ __ref: z.ZodString;
242
+ }, z.core.$strip>]>, z.ZodObject<{
243
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
244
+ __ref: z.ZodString;
245
+ }, z.core.$strip>]>;
246
+ output: z.ZodOptional<z.ZodBoolean>;
247
+ }, z.core.$strict>]>>;
248
+ }, z.core.$strict>>;
178
249
  }, z.core.$strict>, z.ZodObject<Record<never, never>, z.core.$strip>, "settings", {}, {
179
250
  /**
180
251
  * The directory this system's component files are laid out beneath, always defined:
@@ -189,4 +260,4 @@ declare const SettingsDefinition: EntityClass<z.ZodObject<{
189
260
  interface SettingsClass extends Named<typeof SettingsDefinition> {}
190
261
  declare const Settings: SettingsClass;
191
262
  //#endregion
192
- export { BuildSection, BuildSectionClass, CSS_DEFAULTS, CssPrefix, CssSection, CssSectionClass, LintSection, LintSectionClass, PLAYGROUND_DEFAULTS, PlaygroundSection, PlaygroundSectionClass, Settings, SettingsClass, SystemSection, SystemSectionClass, classPrefixOf, cssPrefixes, deriveInputDir, layerPrefixOf, prefixed, varPrefixOf };
263
+ export { AuthoredDefaultColor, BuildSection, BuildSectionClass, CSS_DEFAULTS, CssPrefix, CssSection, CssSectionClass, DefaultColor, DefaultColorValue, DefaultColors, DefaultsSection, DefaultsSectionClass, LintSection, LintSectionClass, PLAYGROUND_DEFAULTS, PlaygroundSection, PlaygroundSectionClass, Settings, SettingsClass, SystemSection, SystemSectionClass, classPrefixOf, cssPrefixes, defaultColorOf, defaultColorsOf, deriveInputDir, layerPrefixOf, prefixed, varPrefixOf };
@@ -1,4 +1,4 @@
1
- import { splitRef } from "../../framework/utils/refs.js";
1
+ import { refTo, splitRef } from "../../framework/utils/refs.js";
2
2
  import { defineEntity } from "../../framework/defineEntity.js";
3
3
  import { defineSubEntity } from "../../framework/defineSubEntity.js";
4
4
  import { createSliceMemo } from "../../framework/memo.js";
@@ -23,8 +23,9 @@ import { z } from "zod";
23
23
  * field, and a clone emits only what the system chose. The defaults are the `*_DEFAULTS` constants
24
24
  * beside each section, which the readers fall back to.
25
25
  *
26
- * Not borrowed and not refed today. `linkable: false` is a statement about this kind, not about
27
- * singletons: a consumer's `link: '*'` must not inherit a source's build directories or CSS prefix.
26
+ * Not borrowed and not refed. A `defaults` colour may ref a token, so renaming that token cascades
27
+ * into it. `linkable: false` is a statement about this kind, not about singletons: a consumer's
28
+ * `link: '*'` must not inherit a source's build directories or CSS prefix.
28
29
  */
29
30
  const systemFields = z.strictObject({
30
31
  /**
@@ -222,6 +223,55 @@ const LintSection = defineSubEntity({
222
223
  singleton: true,
223
224
  fields: lintFields
224
225
  });
226
+ /** A default colour: a CSS colour as written, or a token, which follows the modes it is painted
227
+ * under. `refTo` rather than the `Token` class, which imports back into this module. */
228
+ const defaultColorValue = z.union([z.string().min(1), refTo("token")]);
229
+ /** A default colour on its own, or with `output` saying whether the stylesheet's body rule carries
230
+ * it. */
231
+ const defaultColor = z.union([defaultColorValue, z.strictObject({
232
+ value: defaultColorValue,
233
+ output: z.boolean().optional()
234
+ })]);
235
+ const defaultsFields = z.strictObject({
236
+ background: defaultColor.meta({
237
+ title: "Background",
238
+ valueType: "color",
239
+ description: "The background this system's components sit on: a CSS colour (`#ffffff`) or a token (`Token.ref('color/surface')`). The stylesheet sets it on `body`, and Create paints it behind a component's matrix cells, under the modes picked there. `{ value, output: false }` keeps it out of the stylesheet. Unset, neither paints one."
240
+ }).optional(),
241
+ color: defaultColor.meta({
242
+ title: "Text color",
243
+ valueType: "color",
244
+ description: "The text colour this system's components inherit: a CSS colour or a token. The stylesheet sets it on `body`, and Create applies it to a component's matrix cells, under the modes picked there. `{ value, output: false }` keeps it out of the stylesheet. Unset, neither sets one."
245
+ }).optional()
246
+ });
247
+ const DefaultsSection = defineSubEntity({
248
+ name: "defaults",
249
+ label: "Defaults",
250
+ singleton: true,
251
+ fields: defaultsFields
252
+ });
253
+ /** One default colour in its long form, whichever form it was written in. */
254
+ function defaultColorOf(authored) {
255
+ if (authored === void 0) return void 0;
256
+ if (typeof authored === "object" && "value" in authored) return {
257
+ value: authored.value,
258
+ output: authored.output ?? true
259
+ };
260
+ return {
261
+ value: authored,
262
+ output: true
263
+ };
264
+ }
265
+ /** The `defaults` section as every reader takes it, whichever form each colour was written in. */
266
+ function defaultColorsOf(config) {
267
+ const defaults = Settings.get(config)?.defaults;
268
+ const background = defaultColorOf(defaults?.background);
269
+ const color = defaultColorOf(defaults?.color);
270
+ return {
271
+ ...background ? { background } : {},
272
+ ...color ? { color } : {}
273
+ };
274
+ }
225
275
  /** The folders of a path, file name dropped. */
226
276
  const foldersOf = (file) => file.split("/").slice(0, -1);
227
277
  /** The folders every one of `lists` starts with. */
@@ -322,14 +372,16 @@ const Settings = defineEntity({
322
372
  build: buildFields.meta({ title: "Build" }).optional(),
323
373
  css: cssFields.meta({ title: "CSS" }).optional(),
324
374
  playground: playgroundFields.meta({ title: "Playground" }).optional(),
325
- lint: lintFields.meta({ title: "Lint" }).optional()
375
+ lint: lintFields.meta({ title: "Lint" }).optional(),
376
+ defaults: defaultsFields.meta({ title: "Defaults" }).optional()
326
377
  }),
327
378
  subEntities: {
328
379
  system: SystemSection,
329
380
  build: BuildSection,
330
381
  css: CssSection,
331
382
  playground: PlaygroundSection,
332
- lint: LintSection
383
+ lint: LintSection,
384
+ defaults: DefaultsSection
333
385
  },
334
386
  computed: {
335
387
  /**
@@ -340,4 +392,4 @@ const Settings = defineEntity({
340
392
  inputDir: ({ member, config }) => resolveInputDir(member.build) ?? derivedInputDir(config) }
341
393
  });
342
394
  //#endregion
343
- export { BuildSection, CSS_DEFAULTS, CssSection, LintSection, PLAYGROUND_DEFAULTS, PlaygroundSection, Settings, SystemSection, classPrefixOf, cssPrefixes, deriveInputDir, layerPrefixOf, prefixed, varPrefixOf };
395
+ export { BuildSection, CSS_DEFAULTS, CssSection, DefaultsSection, LintSection, PLAYGROUND_DEFAULTS, PlaygroundSection, Settings, SystemSection, classPrefixOf, cssPrefixes, defaultColorOf, defaultColorsOf, deriveInputDir, layerPrefixOf, prefixed, varPrefixOf };
@@ -9,12 +9,22 @@ type LinkPaths = '*' | Readonly<Record<string, '*' | readonly string[]>>;
9
9
  /** What a link does at a path held through another linked system: `'take'` makes the row follow this
10
10
  * source, `'keep'` leaves it with the system it comes from. */
11
11
  type OnLinked = 'keep' | 'take';
12
+ /** Per accessor, a path this config holds → the source's path that replaces it under another name. */
13
+ type LinkReplacements = Readonly<Record<string, Readonly<Record<string, string>>>>;
12
14
  interface LinkPlanInput {
13
15
  /** The pin's slug. */
14
16
  readonly path: string;
15
17
  readonly data: LinkPaths;
16
18
  /** Planned as `'take'` when omitted; the `link` op refuses without it while `linked` is not empty. */
17
19
  readonly onLinked?: OnLinked;
20
+ /**
21
+ * What this config holds under one name that the source's entity replaces under another:
22
+ * `{ components: { SelectContent: 'SelectMenu' } }` replaces the `SelectContent` this config holds
23
+ * with the source's `SelectMenu`, and everything that pointed at `SelectContent` points at
24
+ * `SelectMenu` after it. Each source path is one `data` names. A take at the same path is
25
+ * `onLinked: 'take'`, not this.
26
+ */
27
+ readonly replace?: LinkReplacements;
18
28
  }
19
29
  /** A path the link reaches that another linked system provides, or declares under a row of this
20
30
  * config's own. */
@@ -40,6 +50,22 @@ interface StrandedDirective extends DroppedDirective {
40
50
  interface LinkArrival extends EntityAddress {
41
51
  readonly named: boolean;
42
52
  }
53
+ /** A row this config held that a `replace` entry replaces with the source's entity of another name.
54
+ * `path` is the row's; every ref to it is renamed to `with`. */
55
+ interface LinkReplacement extends EntityAddress {
56
+ /** The source's path that replaces it, which is where the row lands. */
57
+ readonly with: string;
58
+ /** The slug of the pin the replaced row came through; absent for a row of this config's own. */
59
+ readonly from?: string;
60
+ /** Whether the replaced path was left out of that pin, so it no longer derives here. */
61
+ readonly excluded: boolean;
62
+ /** That pin's own rows still drawing on the replaced path, which keep it held. */
63
+ readonly keptFor?: readonly EntityAddress[];
64
+ /** Why the replaced path couldn't be left out of that pin, when it couldn't. */
65
+ readonly keptBecause?: string;
66
+ /** That pin's `options` entries at the replaced path, removed with it. */
67
+ readonly dropped: readonly EntityAddress[];
68
+ }
43
69
  interface LinkPlan {
44
70
  /** The pin's `link` once the op has run. */
45
71
  readonly declared: LinkDeclaration | undefined;
@@ -53,6 +79,8 @@ interface LinkPlan {
53
79
  readonly linked: readonly LinkedElsewhere[];
54
80
  /** Rows held through another pin, turned into extensions through this one. */
55
81
  readonly extended: readonly EntityAddress[];
82
+ /** What `replace` replaces, each with the source's entity it's replaced with. */
83
+ readonly replaced: readonly LinkReplacement[];
56
84
  /** The other pins' `options` entries at what the take moves, removed with it: they adjust only the
57
85
  * rows their pin derives, and the row there follows this one now. Not carried onto the taken row,
58
86
  * since an entry corrects what that pin brings rather than stating a value of this config's own. */
@@ -156,6 +184,11 @@ interface SourceRowState {
156
184
  * that leaves a referrer dangling until the declaration covers the path. A member
157
185
  * already here from the source's own origin is left alone and kept out of the declaration, so a
158
186
  * folder that holds one is declared by its other members.
187
+ *
188
+ * A `replace` entry replaces a row this config holds with the source's entity of another name: that
189
+ * row becomes an extension of the source's, is renamed to the source's path so every ref follows
190
+ * (`replacementTakes`), and is left out of the pin it came through unless that pin's own rows still
191
+ * draw on it.
159
192
  */
160
193
  declare function planLink({
161
194
  config,
@@ -214,4 +247,4 @@ declare function sourceRowStates({
214
247
  readonly slug: string;
215
248
  }): SourceRowState[];
216
249
  //#endregion
217
- export { BreakOutcome, BreakPlan, BreakPlanInput, BreakPlanRow, BreakReach, DroppedDirective, LinkArrival, LinkPaths, LinkPlan, LinkPlanInput, LinkedElsewhere, OnLinked, SourceRowState, UnlinkPlan, UnlinkPlanInput, planBreak, planLink, planUnlink, sourceRowStates };
250
+ export { BreakOutcome, BreakPlan, BreakPlanInput, BreakPlanRow, BreakReach, DroppedDirective, LinkArrival, LinkPaths, LinkPlan, LinkPlanInput, LinkReplacement, LinkReplacements, LinkedElsewhere, OnLinked, SourceRowState, UnlinkPlan, UnlinkPlanInput, planBreak, planLink, planUnlink, sourceRowStates };
@@ -71,6 +71,11 @@ function declaredElsewhere({ config, slug, kind, path }) {
71
71
  * that leaves a referrer dangling until the declaration covers the path. A member
72
72
  * already here from the source's own origin is left alone and kept out of the declaration, so a
73
73
  * folder that holds one is declared by its other members.
74
+ *
75
+ * A `replace` entry replaces a row this config holds with the source's entity of another name: that
76
+ * row becomes an extension of the source's, is renamed to the source's path so every ref follows
77
+ * (`replacementTakes`), and is left out of the pin it came through unless that pin's own rows still
78
+ * draw on it.
74
79
  */
75
80
  function planLink({ config, input }) {
76
81
  return planLinkApplied({
@@ -116,7 +121,15 @@ function planLinkApplied({ config, input }) {
116
121
  /** Per accessor, what the declaration gains: the kind whole, or paths. */
117
122
  const gains = /* @__PURE__ */ new Map();
118
123
  let leftAnywhere = false;
124
+ const replacements = replacementTakes({
125
+ config,
126
+ slug,
127
+ source,
128
+ input
129
+ });
130
+ const landing = new Set(replacements.entries.map(({ kind, path }) => `${kind}:${path}`));
119
131
  const shadow = (kind, path) => {
132
+ if (landing.has(`${kind}:${path}`)) return true;
120
133
  const held = config.resolve(kind, path);
121
134
  if (!held || held.borrowedFrom === slug) return true;
122
135
  if (sharedWithOrigin({
@@ -261,12 +274,13 @@ function planLinkApplied({ config, input }) {
261
274
  declared = Object.keys(next).length === 0 ? current : next;
262
275
  }
263
276
  const planned = [
277
+ ...replacements.patches,
264
278
  ...takes,
265
279
  ...declares,
266
280
  ...shadows
267
281
  ];
268
282
  let result = planned.length > 0 ? applied(config, planned) : void 0;
269
- if (takes.length > 0 && result && "failed" in result) throw result.failed;
283
+ if ((takes.length > 0 || replacements.patches.length > 0) && result && "failed" in result) throw result.failed;
270
284
  const { dropped, stranded, patches: drops } = takes.length > 0 && result && "config" in result ? directivesTakenFrom({
271
285
  config,
272
286
  slug,
@@ -277,7 +291,74 @@ function planLinkApplied({ config, input }) {
277
291
  patches: []
278
292
  };
279
293
  if (drops.length > 0 && result && "config" in result) result = applied(result.config, drops);
280
- const patches = [...planned, ...drops];
294
+ const taken = [];
295
+ const leaves = [];
296
+ for (const entry of replacements.entries) {
297
+ const { kind, accessor, path, replaces, from } = entry;
298
+ if (from === void 0 || !result || !("config" in result)) {
299
+ taken.push({
300
+ kind,
301
+ path: replaces,
302
+ with: path,
303
+ ...from ? { from } : {},
304
+ excluded: false,
305
+ dropped: []
306
+ });
307
+ continue;
308
+ }
309
+ const leftOut = { [accessor]: [replaces] };
310
+ const keptFor = linkedDependents({
311
+ config: result.config,
312
+ slug: from,
313
+ data: leftOut
314
+ });
315
+ if (keptFor.length > 0) {
316
+ taken.push({
317
+ kind,
318
+ path: replaces,
319
+ with: path,
320
+ from,
321
+ excluded: false,
322
+ keptFor,
323
+ dropped: []
324
+ });
325
+ continue;
326
+ }
327
+ const exclusion = planExclude({
328
+ config: result.config,
329
+ input: {
330
+ path: from,
331
+ data: leftOut
332
+ }
333
+ });
334
+ if (exclusion.blocked !== void 0) {
335
+ taken.push({
336
+ kind,
337
+ path: replaces,
338
+ with: path,
339
+ from,
340
+ excluded: false,
341
+ keptBecause: exclusion.blocked,
342
+ dropped: []
343
+ });
344
+ continue;
345
+ }
346
+ leaves.push(...exclusion.patches);
347
+ result = applied(result.config, exclusion.patches);
348
+ taken.push({
349
+ kind,
350
+ path: replaces,
351
+ with: path,
352
+ from,
353
+ excluded: true,
354
+ dropped: exclusion.dropped
355
+ });
356
+ }
357
+ const patches = [
358
+ ...planned,
359
+ ...drops,
360
+ ...leaves
361
+ ];
281
362
  return {
282
363
  plan: {
283
364
  declared,
@@ -291,6 +372,7 @@ function planLinkApplied({ config, input }) {
291
372
  addresses,
292
373
  linked,
293
374
  extended,
375
+ replaced: taken,
294
376
  dropped,
295
377
  shared,
296
378
  patches,
@@ -303,6 +385,79 @@ function planLinkApplied({ config, input }) {
303
385
  };
304
386
  }
305
387
  /**
388
+ * The edits that take each `replace` entry: the replaced row becomes this config's own extension of
389
+ * the source's entity, still at the old path, and is then renamed to the source's path. A rename is
390
+ * the edit that moves every ref, and the one design files and code follow, so the replaced name's
391
+ * instances arrive on the taken entity the way a rename's would. The config refuses to rename a row
392
+ * held under its source's own name, so the extension comes first: what it holds is then a name this
393
+ * config gave.
394
+ */
395
+ function replacementTakes({ config, slug, source, input }) {
396
+ const entries = [];
397
+ const patches = [];
398
+ const accessors = config.accessors();
399
+ const landing = /* @__PURE__ */ new Map();
400
+ for (const [accessor, pairs] of Object.entries(input.replace ?? {})) {
401
+ const kind = accessors[accessor]?.kind;
402
+ if (!kind) rejectData(`Cannot replace anything through "${slug}" — this system has no "${accessor}".`, ["replace", accessor]);
403
+ for (const [replaces, path] of Object.entries(pairs)) {
404
+ const at = [
405
+ "replace",
406
+ accessor,
407
+ replaces
408
+ ];
409
+ if (input.data !== "*" && !covers({
410
+ declared: input.data,
411
+ accessor,
412
+ path
413
+ })) rejectData(`Cannot replace "${replaces}" with "${path}" — \`data\` doesn't link "${path}" through "${slug}". Name it there too.`, at);
414
+ if (!source.resolve(kind, path)) rejectData(`Cannot replace "${replaces}" with "${path}" — "${slug}" has no ${kind} "${path}".`, at);
415
+ if (path === replaces) rejectData(`Cannot replace "${path}" with itself — taking the source's "${path}" over it is \`onLinked: 'take'\`.`, at);
416
+ const twice = landing.get(`${kind}:${path}`);
417
+ if (twice !== void 0) rejectData(`Cannot replace both "${twice}" and "${replaces}" with "${path}".`, at);
418
+ const held = config.resolve(kind, replaces);
419
+ if (!held) rejectData(`Cannot replace "${replaces}" — this system has no ${kind} "${replaces}".`, at);
420
+ if (held.borrowedFrom === slug) rejectData(`Cannot replace "${replaces}" with "${path}" — "${replaces}" already comes from "${slug}".`, at);
421
+ const occupied = config.storedBody(kind, path);
422
+ if (occupied !== void 0 && !isMintedRow(occupied)) rejectData(`Cannot replace "${replaces}" with "${path}" — this system already has a ${kind} of its own at "${path}".`, at);
423
+ landing.set(`${kind}:${path}`, replaces);
424
+ const from = held.borrowedFrom ?? declaredElsewhere({
425
+ config,
426
+ slug,
427
+ kind,
428
+ path: replaces
429
+ });
430
+ const stored = config.storedBody(kind, replaces);
431
+ const minted = stored !== void 0 && isMintedRow(stored);
432
+ entries.push({
433
+ kind,
434
+ accessor,
435
+ path,
436
+ replaces,
437
+ ...from ? { from } : {}
438
+ });
439
+ patches.push({
440
+ kind,
441
+ operation: minted ? "create" : "replace",
442
+ path: replaces,
443
+ data: {
444
+ ...ref(kind, path, slug),
445
+ extend: {}
446
+ }
447
+ }, {
448
+ kind,
449
+ operation: "rename",
450
+ path: replaces,
451
+ to: path
452
+ });
453
+ }
454
+ }
455
+ return {
456
+ entries,
457
+ patches
458
+ };
459
+ }
460
+ /**
306
461
  * The other pins' `options` entries a take leaves applying to nothing, and the pin edits that remove
307
462
  * them.
308
463
  *