@yahoo/uds-create-config 4.12.0 → 4.12.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.
@@ -1442,6 +1442,10 @@ declare const ReactNativeSystem: ConfigClass<{
1442
1442
  }, _$zod_v4_core0.$strip>;
1443
1443
  default: _$zod.ZodOptional<_$zod.ZodBoolean>;
1444
1444
  defaultProps: _$zod.ZodOptional<_$zod.ZodRecord<_$zod.ZodString, _$zod.ZodUnknown>>;
1445
+ props: _$zod.ZodOptional<_$zod.ZodObject<{
1446
+ glyph: _$zod.ZodString;
1447
+ axes: _$zod.ZodOptional<_$zod.ZodArray<_$zod.ZodString>>;
1448
+ }, _$zod_v4_core0.$strip>>;
1445
1449
  }, _$zod_v4_core0.$strip>>;
1446
1450
  }, _$zod_v4_core0.$strip>, _$zod.ZodObject<Record<never, never>, _$zod_v4_core0.$strip>, "canvas-role", {
1447
1451
  readonly create: {
@@ -3268,6 +3272,10 @@ declare const ReactNativeSystem: ConfigClass<{
3268
3272
  }, _$zod_v4_core0.$strip>;
3269
3273
  default: _$zod.ZodOptional<_$zod.ZodBoolean>;
3270
3274
  defaultProps: _$zod.ZodOptional<_$zod.ZodRecord<_$zod.ZodString, _$zod.ZodUnknown>>;
3275
+ props: _$zod.ZodOptional<_$zod.ZodObject<{
3276
+ glyph: _$zod.ZodString;
3277
+ axes: _$zod.ZodOptional<_$zod.ZodArray<_$zod.ZodString>>;
3278
+ }, _$zod_v4_core0.$strip>>;
3271
3279
  }, _$zod_v4_core0.$strip>>;
3272
3280
  }, _$zod_v4_core0.$strip>, _$zod.ZodObject<Record<never, never>, _$zod_v4_core0.$strip>, "canvas-role", {
3273
3281
  readonly create: {
@@ -1296,6 +1296,10 @@ declare const System: ConfigClass<{
1296
1296
  }, _$zod_v4_core0.$strip>;
1297
1297
  default: _$zod.ZodOptional<_$zod.ZodBoolean>;
1298
1298
  defaultProps: _$zod.ZodOptional<_$zod.ZodRecord<_$zod.ZodString, _$zod.ZodUnknown>>;
1299
+ props: _$zod.ZodOptional<_$zod.ZodObject<{
1300
+ glyph: _$zod.ZodString;
1301
+ axes: _$zod.ZodOptional<_$zod.ZodArray<_$zod.ZodString>>;
1302
+ }, _$zod_v4_core0.$strip>>;
1299
1303
  }, _$zod_v4_core0.$strip>>;
1300
1304
  }, _$zod_v4_core0.$strip>, _$zod.ZodObject<Record<never, never>, _$zod_v4_core0.$strip>, "canvas-role", {
1301
1305
  readonly create: {
@@ -2994,6 +2998,10 @@ declare const System: ConfigClass<{
2994
2998
  }, _$zod_v4_core0.$strip>;
2995
2999
  default: _$zod.ZodOptional<_$zod.ZodBoolean>;
2996
3000
  defaultProps: _$zod.ZodOptional<_$zod.ZodRecord<_$zod.ZodString, _$zod.ZodUnknown>>;
3001
+ props: _$zod.ZodOptional<_$zod.ZodObject<{
3002
+ glyph: _$zod.ZodString;
3003
+ axes: _$zod.ZodOptional<_$zod.ZodArray<_$zod.ZodString>>;
3004
+ }, _$zod_v4_core0.$strip>>;
2997
3005
  }, _$zod_v4_core0.$strip>>;
2998
3006
  }, _$zod_v4_core0.$strip>, _$zod.ZodObject<Record<never, never>, _$zod_v4_core0.$strip>, "canvas-role", {
2999
3007
  readonly create: {
@@ -35,6 +35,7 @@ import { previewConditionsKeyedMigration } from "../migrations/20260920004019_pr
35
35
  import { prefixedTokenGroupMigration } from "../migrations/20260920161309_prefixed_token_group.js";
36
36
  import { iconLibraryWithoutComponentMigration } from "../migrations/20260921044042_icon_library_without_component.js";
37
37
  import { iconLibrariesMigration } from "../migrations/20260922013625_icon_libraries.js";
38
+ import { iconCanvasToolMigration } from "../migrations/20260923005318_icon_canvas_tool.js";
38
39
  //#region src/configs/system.ts
39
40
  /**
40
41
  * `System` — the design-system config TYPE. Declares the exact kinds a design system owns (tokens,
@@ -90,5 +91,6 @@ if (!registeredSchemaMigrations().has(20260920004019)) registerSchemaMigrations(
90
91
  if (!registeredSchemaMigrations().has(20260920161309)) registerSchemaMigrations(prefixedTokenGroupMigration);
91
92
  if (!registeredSchemaMigrations().has(20260921044042)) registerSchemaMigrations(iconLibraryWithoutComponentMigration);
92
93
  if (!registeredSchemaMigrations().has(20260922013625)) registerSchemaMigrations(iconLibrariesMigration);
94
+ if (!registeredSchemaMigrations().has(20260923005318)) registerSchemaMigrations(iconCanvasToolMigration);
93
95
  //#endregion
94
96
  export { System };
@@ -15,7 +15,7 @@ import { z } from "zod";
15
15
  * one ("mirrors `@yahoo/uds-create-config`'s `CanvasRole` union without importing it") — a second
16
16
  * source of truth wearing a comment admitting it.
17
17
  */
18
- declare const CANVAS_ROLES: readonly ["frame", "text", "image"];
18
+ declare const CANVAS_ROLES: readonly ["frame", "text", "image", "icon"];
19
19
  type CanvasRoleName = (typeof CANVAS_ROLES)[number];
20
20
  declare const CanvasRole: EntityClass<z.ZodObject<{
21
21
  entries: z.ZodArray<z.ZodObject<{
@@ -24,6 +24,10 @@ declare const CanvasRole: EntityClass<z.ZodObject<{
24
24
  }, z.core.$strip>;
25
25
  default: z.ZodOptional<z.ZodBoolean>;
26
26
  defaultProps: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
27
+ props: z.ZodOptional<z.ZodObject<{
28
+ glyph: z.ZodString;
29
+ axes: z.ZodOptional<z.ZodArray<z.ZodString>>;
30
+ }, z.core.$strip>>;
27
31
  }, z.core.$strip>>;
28
32
  }, z.core.$strip>, z.ZodObject<Record<never, never>, z.core.$strip>, "canvas-role", {
29
33
  readonly create: {
@@ -30,14 +30,19 @@ import { z } from "zod";
30
30
  const CANVAS_ROLES = [
31
31
  "frame",
32
32
  "text",
33
- "image"
33
+ "image",
34
+ "icon"
34
35
  ];
35
36
  const CanvasRole = defineEntity({
36
37
  kind: "canvas-role",
37
38
  fields: z.object({ entries: z.array(z.object({
38
39
  component: Component.describe("The component this tool inserts, as a ref: `{ \"__ref\": \"component:<path>\" }`."),
39
40
  default: z.boolean().optional().describe("The entry the tool inserts when none is chosen; mark one."),
40
- defaultProps: z.record(z.string(), z.unknown()).optional().describe("Props the inserted component starts with, keyed by prop name.")
41
+ defaultProps: z.record(z.string(), z.unknown()).optional().describe("Props the inserted component starts with, keyed by prop name."),
42
+ props: z.object({
43
+ glyph: z.string().describe("The prop that takes the glyph: one whose domain is an icon library (`name: { type: \"variant\", value: Icon.ref(\"icons\") }`). Its libraries are what the picker offers."),
44
+ axes: z.array(z.string()).optional().describe("The props the picker offers as axes (`variant`, `size`), each with the values the prop itself declares.")
45
+ }).optional().describe("What the tool exposes of the component. Read by the `icon` role: the picker draws every glyph through this component and offers the named props as its axes.")
41
46
  })).describe(`The components a canvas insert tool draws with. The entity's path is the tool: one of ${CANVAS_ROLES.map((role) => `\`${role}\``).join(", ")}. A role with no entity registered has its tool disabled.`) }),
42
47
  schemas: { create: { description: `Register a canvas insert tool for this system. \`path\` is the role, one of ${CANVAS_ROLES.map((role) => `\`${role}\``).join(", ")}; \`data.entries\` names the components that tool inserts, one marked \`default\`. A system whose roles are unregistered has those canvas tools disabled, so register \`frame\` and \`text\` once a layout primitive and a text primitive exist.` } }
43
48
  });
@@ -12,11 +12,13 @@ import { z } from "zod";
12
12
  * - `{ export: { filled: '{name}Filled' } }`: a variant is another export, named by the template
13
13
  * with `{name}` replaced by the member's name; a variant not listed draws the bare export (Tabler).
14
14
  */
15
+ /** @deprecated With the group's `variantAs`; see there. */
15
16
  declare const iconVariantAs: z.ZodUnion<readonly [z.ZodObject<{
16
17
  prop: z.ZodString;
17
18
  }, z.core.$strict>, z.ZodObject<{
18
19
  export: z.ZodRecord<z.ZodString, z.ZodString>;
19
20
  }, z.core.$strict>]>;
21
+ /** @deprecated With the group's `variantAs`; see there. */
20
22
  type IconVariantAs = z.infer<typeof iconVariantAs>;
21
23
  /**
22
24
  * Icon (`icons/AcornIcon`) — one glyph in an icon library. The library (`icons`) is an EMERGENT group
@@ -14,6 +14,7 @@ import { z } from "zod";
14
14
  * - `{ export: { filled: '{name}Filled' } }`: a variant is another export, named by the template
15
15
  * with `{name}` replaced by the member's name; a variant not listed draws the bare export (Tabler).
16
16
  */
17
+ /** @deprecated With the group's `variantAs`; see there. */
17
18
  const iconVariantAs = z.union([z.strictObject({ prop: z.string().min(1) }), z.strictObject({ export: z.record(z.string().min(1), z.string().min(1)) })]);
18
19
  /**
19
20
  * Icon (`icons/AcornIcon`) — one glyph in an icon library. The library (`icons`) is an EMERGENT group
@@ -44,12 +45,17 @@ const Icon = defineEntity({
44
45
  /** Where member metadata comes from and how to read it — `{ from, format }`. The build resolves
45
46
  * the source and bakes each member's fields; see `icon-metadata.ts`. */
46
47
  metadata: iconMetadataDeclaration.optional(),
47
- /** Named sizes the set ships (`sm: 16`). */
48
+ /** Named sizes the set ships (`sm: 16`).
49
+ * @deprecated How a glyph is sized is the icon tool's component's business: the icon tool's component declares its own `size` and `variant` props, and every surface reads those. TODO: remove with a migration once no surface reads the library's copy. */
48
50
  sizes: z.record(z.string(), z.number()).optional(),
49
- /** Weights/styles the set ships (`regular`, `fill`). */
51
+ /** Weights/styles the set ships (`regular`, `fill`).
52
+ * @deprecated Which styles a glyph takes is the icon tool's component's business: the icon tool's component declares its own `size` and `variant` props, and every surface reads those. TODO: remove with a migration once no surface reads the library's copy. */
50
53
  variants: z.array(z.string()).optional(),
51
54
  /** How a variant reaches the glyph; see {@link iconVariantAs}. Absent, a variant is dropped at
52
- * render. */
55
+ * render.
56
+ * @deprecated Only the framework's raw-draw path read it; the icon tool's component passes a
57
+ * variant the way its package wants, and a set whose styles are separate exports lists them as
58
+ * members. TODO: remove with `sizes` and `variants`. */
53
59
  variantAs: iconVariantAs.optional()
54
60
  }),
55
61
  groupComputed: {
@@ -247,10 +247,13 @@ type ValueOf<D> = D extends readonly (infer Member)[] ? Member : D extends {
247
247
  /**
248
248
  * A glyph as a value: the component an icon library exports. Its `displayName` is the member it is,
249
249
  * which is what register stores (`icon:phosphor/XIcon`) and what the renderer resolves back to the
250
- * component. Sizing is the placing component's business, so the one prop every glyph takes is `size`.
250
+ * component. Sizing is the placing component's business, and the vocabulary of `size` is the
251
+ * library's own (one package takes pixels, another a named bucket), so the type states nothing about
252
+ * it: with the default any glyph fits, and a component that knows its library narrows
253
+ * (`GlyphComponent<number>`).
251
254
  */
252
- type GlyphComponent = ComponentType<{
253
- size?: number;
255
+ type GlyphComponent<Size extends string | number = never> = ComponentType<{
256
+ size?: Size;
254
257
  }>;
255
258
  /**
256
259
  * The members a ref-delegated domain offers, read off the registered paths: a variant whose domain
@@ -5,24 +5,30 @@ import { Icon, IconVariantAs } from "./Icon.js";
5
5
  /**
6
6
  * An icon library as its group node reads: the path, the stored set facts (`sizes`, `variants`,
7
7
  * `package`, `variantAs`, `metadata`) and the computeds the entity declares (`members`, `module`,
8
- * `version`), plus the per-member and drawer-side facts this projection derives. Typed off
8
+ * `version`), plus the per-member and component-side facts this projection derives. Typed off
9
9
  * `Icon.groups`, so a field added on the entity is visible here without a second declaration.
10
10
  */
11
11
  type IconLibrary = {
12
12
  readonly path: string;
13
13
  } & Undefinable<Omit<ReturnType<typeof Icon.groups>[number]['meta'], 'items' | 'sizes' | 'variants'>> & {
14
+ /** @deprecated The library's copy of what the icon tool's component declares as `size`. TODO: remove
15
+ * with the group field. */
14
16
  readonly sizes: Readonly<Record<string, number>>;
17
+ /** @deprecated The library's copy of what the icon tool's component declares as `variant`. TODO:
18
+ * remove with the group field. */
15
19
  readonly variants: readonly string[];
16
20
  /** For a ragged set, the members whose own `variants` differ from the set's, by leaf. A member
17
21
  * listing exactly the set's variants is left out, so the map stays as sparse as the
18
22
  * raggedness. */
19
23
  readonly memberVariants?: Readonly<Record<string, readonly string[]>>;
20
- /** The variant the library's drawer declares in its `defaultProps` — what a picker seeds when nothing is
24
+ /** The variant the component bound to the library declares in its `defaultProps` — what a picker seeds when nothing is
21
25
  * stored. Passed through as declared; a policy read validates it against {@link variants}
22
- * before trusting it. */
26
+ * before trusting it.
27
+ * @deprecated The icon tool's entry carries `defaultProps`; read them through `iconToolOf`. */
23
28
  readonly defaultVariant?: string;
24
- /** The size bucket the library's drawer declares in its `defaultProps`. Same contract as
25
- * {@link defaultVariant}: declared, not validated. */
29
+ /** The size bucket the component bound to the library declares in its `defaultProps`. Same contract as
30
+ * {@link defaultVariant}: declared, not validated.
31
+ * @deprecated As {@link defaultVariant}. */
26
32
  readonly defaultSizeKey?: string;
27
33
  };
28
34
  /** A field that may hold `undefined` may be left out: a computed's `string | undefined` reads as an
@@ -39,6 +45,8 @@ declare function iconLibrary(config: Config | null | undefined, path: string): I
39
45
  * With `variants`, the member's own list, only the templates for variants it ships are added: a
40
46
  * ragged set's member has no export for the rest, and naming one fails the module's bundle.
41
47
  */
48
+ /** @deprecated Reads `variantAs`, which goes with it; a set whose styles are separate exports lists
49
+ * them as members, and codegen imports members. */
42
50
  declare function glyphExportNames({
43
51
  variantAs,
44
52
  name,
@@ -85,6 +93,11 @@ declare function resolveIconLibraries({
85
93
  * binds nothing — `glyphLibrariesOf` is the one reading of the edge, shared with
86
94
  * {@link glyphComponentOf}.
87
95
  */
96
+ /**
97
+ * The libraries the canvas's icon tool offers: those its component's glyph prop is bound to. Empty
98
+ * when the `icon` canvas role is unregistered, which is also when the tool is disabled.
99
+ */
100
+ declare function iconToolLibraries(config: Config | null | undefined): IconLibrary[];
88
101
  declare function librariesBoundBy({
89
102
  config,
90
103
  component
@@ -112,6 +125,8 @@ declare function iconCategories(config: Config | null | undefined, libraryPath:
112
125
  * same across glyphs. A member listing only variants the set doesn't ship falls back to the set's,
113
126
  * so the axis is never empty for a set that ships one.
114
127
  */
128
+ /** @deprecated The axis is the icon tool's (`iconToolAxisOptions`); a member's own `variants` stay
129
+ * metadata to narrow it by. TODO: rewrite the callers over the tool and remove. */
115
130
  declare function memberVariantOptions(library: IconLibrary, member: string): readonly string[];
116
131
  /**
117
132
  * Whether an element type declares a prop that may survive layer-style projection. A placed
@@ -120,4 +135,4 @@ declare function memberVariantOptions(library: IconLibrary, member: string): rea
120
135
  */
121
136
  declare function isDeclaredElementProp(config: Config | null | undefined, elementType: string, propName: string): boolean;
122
137
  //#endregion
123
- export { IconLibrary, glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
138
+ export { IconLibrary, glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, iconToolLibraries, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
@@ -1,5 +1,5 @@
1
1
  import { createSliceMemo } from "../../framework/memo.js";
2
- import { glyphComponentOf, glyphLibrariesOf, resolveComponentProps } from "../../framework/projections.js";
2
+ import { glyphComponentOf, glyphLibrariesOf, iconToolOf, resolveComponentProps } from "../../framework/projections.js";
3
3
  import { Component } from "./Component.js";
4
4
  import { parseGlyphType } from "../../spec/glyph-jsx.js";
5
5
  import { Icon } from "./Icon.js";
@@ -17,7 +17,7 @@ import { Icon } from "./Icon.js";
17
17
  *
18
18
  * This is the one home for the question "what icon sets does this system have" — Studio owns only
19
19
  * UI policy on top (picker state, grid geometry, recents, search ranking). A library is cached on
20
- * the slices it reads — the set (`icon`), its drawer's defaults (`component`) and the package row
20
+ * the slices it reads — the set (`icon`), its component's defaults (`component`) and the package row
21
21
  * its version comes from (`package`) — so it is reference-stable across calls on one config and
22
22
  * safe in a dep array.
23
23
  */
@@ -40,7 +40,7 @@ function iconLibrary(config, path) {
40
40
  }
41
41
  /** Per-config cache of {@link iconLibrary} answers. `package` is in the key because the set's
42
42
  * `version` resolves through the package row, not off the group node. The member walk underneath
43
- * keys on the icon slice alone, so a component write re-reads only each library's drawer defaults. */
43
+ * keys on the icon slice alone, so a component write re-reads only each library's component defaults. */
44
44
  const librariesOf = createSliceMemo({
45
45
  kinds: [
46
46
  "icon",
@@ -65,21 +65,24 @@ function readIconLibrary(config, path) {
65
65
  sizes: sizes ?? EMPTY_SIZES,
66
66
  variants: variants ?? EMPTY_VARIANTS,
67
67
  ...set.memberVariants ? { memberVariants: set.memberVariants } : {},
68
- ...drawerDefaults({
68
+ ...componentDefaults({
69
69
  config,
70
70
  library: path
71
71
  })
72
72
  };
73
73
  }
74
74
  /**
75
- * The defaults the set's drawer declares: the component whose own variant prop names this library
75
+ * The defaults the set's component declares: the component whose own variant prop names this library
76
76
  * carries "what a bare glyph looks like", read back here so every picker seeds from that one
77
77
  * declaration rather than its own literal. A library no component draws from has no defaults.
78
+ *
79
+ * @deprecated The icon tool's entry carries `defaultProps`. TODO: remove with `defaultVariant` and
80
+ * `defaultSizeKey`.
78
81
  */
79
- function drawerDefaults({ config, library }) {
80
- const drawer = glyphComponentOf(config, library);
81
- if (!drawer) return {};
82
- const defaults = Component.get(config, drawer.path)?.defaultProps;
82
+ function componentDefaults({ config, library }) {
83
+ const bound = glyphComponentOf(config, library);
84
+ if (!bound) return {};
85
+ const defaults = Component.get(config, bound.path)?.defaultProps;
83
86
  const variant = defaults?.variant;
84
87
  const size = defaults?.size;
85
88
  return {
@@ -133,6 +136,8 @@ function sameVariants({ own, declared }) {
133
136
  * With `variants`, the member's own list, only the templates for variants it ships are added: a
134
137
  * ragged set's member has no export for the rest, and naming one fails the module's bundle.
135
138
  */
139
+ /** @deprecated Reads `variantAs`, which goes with it; a set whose styles are separate exports lists
140
+ * them as members, and codegen imports members. */
136
141
  function glyphExportNames({ variantAs, name, variants }) {
137
142
  const names = new Set([name]);
138
143
  if (variantAs && "export" in variantAs) for (const [variant, template] of Object.entries(variantAs.export)) {
@@ -151,15 +156,18 @@ function glyphExportNames({ variantAs, name, variants }) {
151
156
  */
152
157
  function placedGlyphElement(config, glyph, props = {}) {
153
158
  const parsed = parseGlyphType(glyph);
154
- const drawer = parsed && config ? glyphComponentOf(config, parsed.slug) : void 0;
155
- if (!parsed || !drawer) return {
159
+ const bound = parsed && config ? glyphComponentOf(config, parsed.slug) : void 0;
160
+ if (!parsed || !bound || !config) return {
156
161
  type: glyph,
157
162
  props
158
163
  };
164
+ const tool = iconToolOf(config);
165
+ const defaults = tool && tool.component === bound.path ? tool.defaultProps : {};
159
166
  return {
160
- type: `component:${drawer.path}`,
167
+ type: `component:${bound.path}`,
161
168
  props: {
162
- [drawer.prop]: parsed.member,
169
+ ...defaults,
170
+ [bound.prop]: parsed.member,
163
171
  ...props
164
172
  }
165
173
  };
@@ -197,6 +205,17 @@ function resolveIconLibraries({ config, hints }) {
197
205
  * binds nothing — `glyphLibrariesOf` is the one reading of the edge, shared with
198
206
  * {@link glyphComponentOf}.
199
207
  */
208
+ /**
209
+ * The libraries the canvas's icon tool offers: those its component's glyph prop is bound to. Empty
210
+ * when the `icon` canvas role is unregistered, which is also when the tool is disabled.
211
+ */
212
+ function iconToolLibraries(config) {
213
+ if (!config) return NO_LIBRARIES;
214
+ const tool = iconToolOf(config);
215
+ if (!tool) return NO_LIBRARIES;
216
+ const declaration = resolveComponentProps(config, tool.component)[tool.glyph];
217
+ return glyphLibrariesOf(declaration?.value).map((path) => iconLibrary(config, path)).filter((library) => library !== void 0);
218
+ }
200
219
  function librariesBoundBy({ config, component }) {
201
220
  if (!config) return NO_LIBRARIES;
202
221
  const cache = boundLibrariesOf(config);
@@ -253,6 +272,8 @@ function iconCategories(config, libraryPath) {
253
272
  * same across glyphs. A member listing only variants the set doesn't ship falls back to the set's,
254
273
  * so the axis is never empty for a set that ships one.
255
274
  */
275
+ /** @deprecated The axis is the icon tool's (`iconToolAxisOptions`); a member's own `variants` stay
276
+ * metadata to narrow it by. TODO: rewrite the callers over the tool and remove. */
256
277
  function memberVariantOptions(library, member) {
257
278
  const own = library.memberVariants?.[member];
258
279
  if (!own || own.length === 0) return library.variants;
@@ -281,4 +302,4 @@ function isDeclaredElementProp(config, elementType, propName) {
281
302
  return false;
282
303
  }
283
304
  //#endregion
284
- export { glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
305
+ export { glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, iconToolLibraries, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
@@ -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 = 20260922013625;
75
+ declare const SERIALIZED_CONFIG_VERSION = 20260923005318;
76
76
  interface SerializedConfig {
77
77
  /** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
78
78
  readonly version: number;
@@ -4836,7 +4836,7 @@ var Config = class Config {
4836
4836
  * links from the provided sources. A declared `linkedKind` with no provided source throws. */
4837
4837
  hydrateFrom(stored, options) {
4838
4838
  const claimed = schemaVersionOf(stored);
4839
- if (claimed > 20260922013625) throw new SchemaVersionTooNew(claimed);
4839
+ if (claimed > 20260923005318) throw new SchemaVersionTooNew(claimed);
4840
4840
  const wire = upgradeSerializedConfig(stored);
4841
4841
  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\`.`);
4842
4842
  const leftover = wire.options;
@@ -431,13 +431,31 @@ declare function glyphLibrariesOf(domain: unknown): string[];
431
431
  */
432
432
  declare function glyphPropsOf(config: Config, path: string, seen?: ReadonlySet<string>): Record<string, readonly string[]>;
433
433
  /**
434
- * The component that draws a library's glyphs on their own — the one whose own prop declares the
435
- * library as its domain (`name: { type: 'variant', value: Icon.ref('phosphor') }`, or a list of
436
- * libraries that includes it), with that prop. Derived from the components, never declared on the
437
- * set: the edge runs from the component to the library. `undefined` when no component draws from
438
- * it, in which case a placed glyph is the member drawn raw.
439
- *
440
- * Asked per library, so a system may have one drawer binding several libraries or one drawer per
434
+ * The canvas's icon tool: the `icon` canvas role's entry, as the component it inserts, the prop that
435
+ * takes the glyph, the props the picker offers as axes, and the props an inserted instance starts
436
+ * with. The default entry, else the first; `undefined` when the role is unregistered or its entry
437
+ * names no glyph prop, which disables the tool.
438
+ */
439
+ interface IconTool {
440
+ readonly component: string;
441
+ readonly glyph: string;
442
+ readonly axes: readonly string[];
443
+ readonly defaultProps: Readonly<Record<string, unknown>>;
444
+ }
445
+ declare function iconToolOf(config: Config): IconTool | undefined;
446
+ /** The values an icon tool's axis offers: the leaves of that prop's own domain on the tool's
447
+ * component, whether it enumerates them or delegates to a library's facet. */
448
+ declare function iconToolAxisOptions(config: Config, tool: IconTool, axis: string): string[];
449
+ /**
450
+ * The component that draws a library's glyphs on their own, with the prop that takes the glyph. The
451
+ * icon tool's component when the `icon` canvas role names one whose glyph prop is bound to the
452
+ * library; otherwise the component whose own prop declares the library as its domain
453
+ * (`name: { type: 'variant', value: Icon.ref('phosphor') }`, or a list of libraries that includes
454
+ * it). Derived from the components, never declared on the set: the edge runs from the component to
455
+ * the library. `undefined` when no component draws from it, in which case a placed glyph is the
456
+ * member drawn raw.
457
+ *
458
+ * Asked per library, so a system may have one component binding several libraries or one per
441
459
  * library. Two components binding the same library resolve to the first in registration order.
442
460
  */
443
461
  declare function glyphComponentOf(config: Config, library: string): {
@@ -482,6 +500,7 @@ declare function validateComponentProps(config: Config, componentPath: string, p
482
500
  declare function previewDefaults(config: Config, path: string,
483
501
  /** The cell's own prop values. Given, every `preview({ when })` entry that holds for the cell —
484
502
  * tested against the defaults under these values, as a rule's `when` is — adds its props. */
503
+
485
504
  cell?: Record<string, unknown>): Record<string, unknown>;
486
505
  /**
487
506
  * Only what the `preview({ when })` entries add for a cell — the props of every condition that holds
@@ -556,4 +575,4 @@ declare function propValueFromAxis(config: Config, path: string, prop: string, v
556
575
  /** The `value` a string, number or boolean prop declares as its default, per prop. */
557
576
  declare function declaredPropDefaults(props: Record<string, unknown> | undefined): Record<string, unknown>;
558
577
  //#endregion
559
- export { IndexedPreviewCondition, PreviewMatrix, PropDeclaration, StylePropEntry, StylePropertyItem, authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, holdingPreviewConditions, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
578
+ export { IconTool, IndexedPreviewCondition, PreviewMatrix, PropDeclaration, StylePropEntry, StylePropertyItem, authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, holdingPreviewConditions, iconToolAxisOptions, iconToolOf, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
@@ -944,17 +944,46 @@ function glyphPropsOfBody({ config, body, seen = /* @__PURE__ */ new Set() }) {
944
944
  }
945
945
  return out;
946
946
  }
947
+ function iconToolOf(config) {
948
+ const entries = (config.resolve("canvas-role", "icon")?.toJSON())?.entries ?? [];
949
+ const entry = entries.find((candidate) => candidate.default) ?? entries[0];
950
+ const glyph = entry?.props?.glyph;
951
+ if (!entry || !glyph || !isRef(entry.component)) return void 0;
952
+ return {
953
+ component: pathOf(entry.component),
954
+ glyph,
955
+ axes: entry.props?.axes ?? [],
956
+ defaultProps: entry.defaultProps ?? {}
957
+ };
958
+ }
959
+ /** The values an icon tool's axis offers: the leaves of that prop's own domain on the tool's
960
+ * component, whether it enumerates them or delegates to a library's facet. */
961
+ function iconToolAxisOptions(config, tool, axis) {
962
+ const declaration = resolveComponentProps(config, tool.component)[axis];
963
+ if (!declaration) return [];
964
+ return propValueDomain(config, declaration)?.leaves ?? [];
965
+ }
947
966
  /**
948
- * The component that draws a library's glyphs on their own — the one whose own prop declares the
949
- * library as its domain (`name: { type: 'variant', value: Icon.ref('phosphor') }`, or a list of
950
- * libraries that includes it), with that prop. Derived from the components, never declared on the
951
- * set: the edge runs from the component to the library. `undefined` when no component draws from
952
- * it, in which case a placed glyph is the member drawn raw.
967
+ * The component that draws a library's glyphs on their own, with the prop that takes the glyph. The
968
+ * icon tool's component when the `icon` canvas role names one whose glyph prop is bound to the
969
+ * library; otherwise the component whose own prop declares the library as its domain
970
+ * (`name: { type: 'variant', value: Icon.ref('phosphor') }`, or a list of libraries that includes
971
+ * it). Derived from the components, never declared on the set: the edge runs from the component to
972
+ * the library. `undefined` when no component draws from it, in which case a placed glyph is the
973
+ * member drawn raw.
953
974
  *
954
- * Asked per library, so a system may have one drawer binding several libraries or one drawer per
975
+ * Asked per library, so a system may have one component binding several libraries or one per
955
976
  * library. Two components binding the same library resolve to the first in registration order.
956
977
  */
957
978
  function glyphComponentOf(config, library) {
979
+ const tool = iconToolOf(config);
980
+ if (tool) {
981
+ const declaration = resolveComponentProps(config, tool.component)[tool.glyph];
982
+ if (declaration && glyphLibrariesOf(declaration.value).includes(library)) return {
983
+ path: tool.component,
984
+ prop: tool.glyph
985
+ };
986
+ }
958
987
  for (const component of config.list("component")) {
959
988
  const { props = {} } = component.toJSON();
960
989
  for (const [prop, declaration] of Object.entries(props)) {
@@ -1181,4 +1210,4 @@ function declaredPropDefaults(props) {
1181
1210
  return out;
1182
1211
  }
1183
1212
  //#endregion
1184
- export { authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, glyphPropsOfBody, holdingPreviewConditions, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
1213
+ export { authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declaredPropDefaults, declaredPropRouting, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, glyphPropsOfBody, holdingPreviewConditions, iconToolAxisOptions, iconToolOf, keyedPreviewConditions, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, validateComponentProps };
@@ -15,7 +15,7 @@ import { Patch, SerializedConfig } from "./Config.js";
15
15
  * sets this constant to its own older timestamp; the merge ref then carries a registered migration
16
16
  * newer than the constant, and the assertion fails until the author re-mints.
17
17
  */
18
- declare const CURRENT_SCHEMA_VERSION = 20260922013625;
18
+ declare const CURRENT_SCHEMA_VERSION = 20260923005318;
19
19
  /** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
20
20
  * and a raw old-shape record both flow in without casts. */
21
21
  interface VersionStamped {
@@ -13,7 +13,7 @@ import { ConfigFormatError } from "./rejection.js";
13
13
  * sets this constant to its own older timestamp; the merge ref then carries a registered migration
14
14
  * newer than the constant, and the assertion fails until the author re-mints.
15
15
  */
16
- const CURRENT_SCHEMA_VERSION = 20260922013625;
16
+ const CURRENT_SCHEMA_VERSION = 20260923005318;
17
17
  /** The mint that moved `options` into the `settings` kind — restated here, rather than imported
18
18
  * from the migration that owns it, because that migration imports this module. */
19
19
  const SETTINGS_AS_KIND_VERSION = 20260908171448;
@@ -45,7 +45,7 @@ function registerSchemaMigrations(...migrations) {
45
45
  for (const migration of migrations) {
46
46
  if (migration.version !== 1 && !isMintTimestamp(migration.version)) throw new Error(`Schema migration version ${migration.version} is not a mint timestamp — mint one with \`date +%Y%m%d%H%M%S\`, like a supabase migration.`);
47
47
  if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
48
- if (migration.version > 20260922013625) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
48
+ if (migration.version > 20260923005318) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
49
49
  REGISTERED.set(migration.version, migration);
50
50
  }
51
51
  }
@@ -102,7 +102,7 @@ function pendingFor(version, target, options) {
102
102
  * Already-current input passes through untouched — same reference, so hot paths pay nothing.
103
103
  */
104
104
  function upgradeSerializedConfig(json, options) {
105
- const target = options?.target ?? 20260922013625;
105
+ const target = options?.target ?? 20260923005318;
106
106
  const version = detectedWireVersion(json);
107
107
  if (version > target) throw new SchemaVersionTooNew(version, target);
108
108
  const raw = json;
@@ -160,7 +160,7 @@ function upgradedSources(json, options) {
160
160
  * meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
161
161
  */
162
162
  function upgradePatch(patch, writtenAt, options) {
163
- const target = options?.target ?? 20260922013625;
163
+ const target = options?.target ?? 20260923005318;
164
164
  if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
165
165
  let current = patch;
166
166
  for (const migration of pendingFor(writtenAt, target, options)) {
@@ -179,7 +179,7 @@ function upgradePatch(patch, writtenAt, options) {
179
179
  * stamp would cause.
180
180
  */
181
181
  function upgradeDraftEntries(draft, options) {
182
- const target = options?.target ?? 20260922013625;
182
+ const target = options?.target ?? 20260923005318;
183
183
  const entries = [];
184
184
  const held = [];
185
185
  const retired = [];