@yahoo/uds-create-config 4.28.3 → 4.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configs/CanvasConfig.d.ts +9 -3
- package/dist/configs/react-native-system.d.ts +6 -2
- package/dist/configs/react-native-system.js +1 -1
- package/dist/configs/system.d.ts +6 -2
- package/dist/configs/system.js +1 -1
- package/dist/entities/system/CanvasRole.js +3 -1
- package/dist/entities/system/Component.js +2 -2
- package/dist/entities/system/Icon.d.ts +10 -6
- package/dist/entities/system/Icon.js +20 -8
- package/dist/entities/system/defineComponent.d.ts +1 -1
- package/dist/entities/system/glyph-identity.js +25 -1
- package/dist/entities/system/icon-domain-invariants.d.ts +7 -6
- package/dist/entities/system/icon-domain-invariants.js +49 -8
- package/dist/entities/system/icon-library.d.ts +3 -2
- package/dist/entities/system/icon-library.js +8 -9
- package/dist/entities/system/icon-metadata.d.ts +33 -1
- package/dist/entities/system/icon-metadata.js +69 -10
- package/dist/entities/system/runtime-modules.d.ts +3 -0
- package/dist/entities/system/runtime-modules.js +18 -8
- package/dist/framework/Config.d.ts +17 -4
- package/dist/framework/Config.js +80 -19
- package/dist/framework/defineEntity.js +8 -5
- package/dist/framework/projections.d.ts +26 -7
- package/dist/framework/projections.js +65 -21
- package/dist/framework/prop-surface.d.ts +5 -5
- package/dist/framework/prop-surface.js +2 -2
- package/dist/framework/utils/group.d.ts +3 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/migrations/2.0.0/v1-artifact.d.ts +3 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1631,7 +1631,9 @@ declare const Node: EntityClass<z.ZodObject<{
|
|
|
1631
1631
|
}: {
|
|
1632
1632
|
input: GlyphNamespace;
|
|
1633
1633
|
body: Readonly<Record<string, unknown>>;
|
|
1634
|
-
}) =>
|
|
1634
|
+
}) => {
|
|
1635
|
+
items: Record<string, unknown>;
|
|
1636
|
+
};
|
|
1635
1637
|
}>, EntityClass<z.ZodObject<{
|
|
1636
1638
|
version: z.ZodOptional<z.ZodString>;
|
|
1637
1639
|
exports: z.ZodOptional<SubEntityClass<z.ZodObject<{}, z.core.$strict>>>;
|
|
@@ -3195,7 +3197,9 @@ declare const CanvasConfig: ConfigClass<{
|
|
|
3195
3197
|
}: {
|
|
3196
3198
|
input: GlyphNamespace;
|
|
3197
3199
|
body: Readonly<Record<string, unknown>>;
|
|
3198
|
-
}) =>
|
|
3200
|
+
}) => {
|
|
3201
|
+
items: Record<string, unknown>;
|
|
3202
|
+
};
|
|
3199
3203
|
}>, EntityClass<z.ZodObject<{
|
|
3200
3204
|
version: z.ZodOptional<z.ZodString>;
|
|
3201
3205
|
exports: z.ZodOptional<SubEntityClass<z.ZodObject<{}, z.core.$strict>>>;
|
|
@@ -5024,7 +5028,9 @@ declare function createCanvasConfig(system: AnySystemConfig): ConfigInstance<{
|
|
|
5024
5028
|
}: {
|
|
5025
5029
|
input: GlyphNamespace;
|
|
5026
5030
|
body: Readonly<Record<string, unknown>>;
|
|
5027
|
-
}) =>
|
|
5031
|
+
}) => {
|
|
5032
|
+
items: Record<string, unknown>;
|
|
5033
|
+
};
|
|
5028
5034
|
}>, EntityClass<z.ZodObject<{
|
|
5029
5035
|
version: z.ZodOptional<z.ZodString>;
|
|
5030
5036
|
exports: z.ZodOptional<SubEntityClass<z.ZodObject<{}, z.core.$strict>>>;
|
|
@@ -1781,7 +1781,9 @@ declare const ReactNativeSystem: ConfigClass<{
|
|
|
1781
1781
|
}: {
|
|
1782
1782
|
input: GlyphNamespace;
|
|
1783
1783
|
body: Readonly<Record<string, unknown>>;
|
|
1784
|
-
}) =>
|
|
1784
|
+
}) => {
|
|
1785
|
+
items: Record<string, unknown>;
|
|
1786
|
+
};
|
|
1785
1787
|
}>;
|
|
1786
1788
|
packages: EntityClass<_$zod.ZodObject<{
|
|
1787
1789
|
version: _$zod.ZodOptional<_$zod.ZodString>;
|
|
@@ -3988,7 +3990,9 @@ declare const ReactNativeSystem: ConfigClass<{
|
|
|
3988
3990
|
}: {
|
|
3989
3991
|
input: GlyphNamespace;
|
|
3990
3992
|
body: Readonly<Record<string, unknown>>;
|
|
3991
|
-
}) =>
|
|
3993
|
+
}) => {
|
|
3994
|
+
items: Record<string, unknown>;
|
|
3995
|
+
};
|
|
3992
3996
|
}>;
|
|
3993
3997
|
packages: EntityClass<_$zod.ZodObject<{
|
|
3994
3998
|
version: _$zod.ZodOptional<_$zod.ZodString>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Font } from "../entities/system/Font.js";
|
|
2
|
-
import { Composite } from "../entities/system/Composite.js";
|
|
3
2
|
import { Package } from "../entities/system/Package.js";
|
|
3
|
+
import { Composite } from "../entities/system/Composite.js";
|
|
4
4
|
import { File } from "../entities/system/File.js";
|
|
5
5
|
import { Component } from "../entities/system/Component.js";
|
|
6
6
|
import { Icon } from "../entities/system/Icon.js";
|
package/dist/configs/system.d.ts
CHANGED
|
@@ -1634,7 +1634,9 @@ declare const System: ConfigClass<{
|
|
|
1634
1634
|
}: {
|
|
1635
1635
|
input: GlyphNamespace;
|
|
1636
1636
|
body: Readonly<Record<string, unknown>>;
|
|
1637
|
-
}) =>
|
|
1637
|
+
}) => {
|
|
1638
|
+
items: Record<string, unknown>;
|
|
1639
|
+
};
|
|
1638
1640
|
}>;
|
|
1639
1641
|
packages: EntityClass<_$zod.ZodObject<{
|
|
1640
1642
|
version: _$zod.ZodOptional<_$zod.ZodString>;
|
|
@@ -3716,7 +3718,9 @@ declare const System: ConfigClass<{
|
|
|
3716
3718
|
}: {
|
|
3717
3719
|
input: GlyphNamespace;
|
|
3718
3720
|
body: Readonly<Record<string, unknown>>;
|
|
3719
|
-
}) =>
|
|
3721
|
+
}) => {
|
|
3722
|
+
items: Record<string, unknown>;
|
|
3723
|
+
};
|
|
3720
3724
|
}>;
|
|
3721
3725
|
packages: EntityClass<_$zod.ZodObject<{
|
|
3722
3726
|
version: _$zod.ZodOptional<_$zod.ZodString>;
|
package/dist/configs/system.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Font } from "../entities/system/Font.js";
|
|
2
|
+
import { Package } from "../entities/system/Package.js";
|
|
2
3
|
import { Composite } from "../entities/system/Composite.js";
|
|
3
4
|
import { Modifier } from "../entities/system/Modifier.js";
|
|
4
5
|
import { Settings } from "../entities/system/Settings.js";
|
|
5
6
|
import { StyleProperty } from "../entities/system/StyleProperty.js";
|
|
6
|
-
import { Package } from "../entities/system/Package.js";
|
|
7
7
|
import { File } from "../entities/system/File.js";
|
|
8
8
|
import { Token } from "../entities/system/Token.js";
|
|
9
9
|
import { Component } from "../entities/system/Component.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
2
|
+
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
2
3
|
import { Component } from "./Component.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/entities/system/CanvasRole.ts
|
|
@@ -40,7 +41,8 @@ const CanvasRole = defineEntity({
|
|
|
40
41
|
axes: z.array(z.string()).optional().describe("The props the picker offers as axes (`variant`, `size`), each with the values the prop itself declares.")
|
|
41
42
|
}).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.")
|
|
42
43
|
})).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.`) }),
|
|
43
|
-
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.` } }
|
|
44
|
+
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.` } },
|
|
45
|
+
invariants: (config) => iconDomainInvariants(config)
|
|
44
46
|
});
|
|
45
47
|
//#endregion
|
|
46
48
|
export { CANVAS_ROLES, CanvasRole };
|
|
@@ -8,6 +8,7 @@ import { derivedColor, gradient } from "./color.js";
|
|
|
8
8
|
import { childrenPolicy, forwardedPropName } from "./element.js";
|
|
9
9
|
import { listedIn } from "../../framework/utils/enumerated.js";
|
|
10
10
|
import { valueSchemaOf } from "../../framework/value-domain.js";
|
|
11
|
+
import { Package } from "./Package.js";
|
|
11
12
|
import { bindPreviewGlyphs, glyphLeafOf } from "./glyph-identity.js";
|
|
12
13
|
import { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName, bindBagTokens, collectBag, isPlainRecord, openBag, styleValue } from "./style-bag.js";
|
|
13
14
|
import { storedPreview } from "../../framework/preview-store.js";
|
|
@@ -17,7 +18,6 @@ import { slotAnatomyPropOf, slotTargetsOf, withoutTruthyTerm } from "../../frame
|
|
|
17
18
|
import { listSlots, namedSlots, slotHostedBy, slotOf } from "../../spec/slot.js";
|
|
18
19
|
import { cellAt } from "../../spec/cell.js";
|
|
19
20
|
import { instanceAt } from "../../spec/instance.js";
|
|
20
|
-
import { Package } from "./Package.js";
|
|
21
21
|
import { File } from "./File.js";
|
|
22
22
|
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
23
23
|
import { rootLayerInvariants } from "./root-layer-invariants.js";
|
|
@@ -505,7 +505,7 @@ function propSchemaFor(config, owner) {
|
|
|
505
505
|
code: "custom",
|
|
506
506
|
input: decl,
|
|
507
507
|
path: ["accepts"],
|
|
508
|
-
message: routed ? `\`accepts\` says what may FILL a content hole — an icon set, so any glyph it registers can be dropped in (\`
|
|
508
|
+
message: routed ? `\`accepts\` says what may FILL a content hole — an icon set, so any glyph it registers can be dropped in (\`EmptyState.icon\` accepts \`Icon.ref('phosphor')\`), or a component. \`${layer}/${prop}\` is a ${routed.type} prop, so it takes a value rather than content. Remove \`accepts\`, or point \`target\` at a prop declared \`{ type: 'slot' }\`.` : `\`accepts\` says what may FILL a content hole — an icon set, or a component. The \`${layer}\` layer is a plain tag, and \`children\` is the only prop a tag carries content through — so either target \`${layer}/children\`, or remove \`accepts\`.`
|
|
509
509
|
});
|
|
510
510
|
});
|
|
511
511
|
}
|
|
@@ -82,11 +82,13 @@ declare const Icon: EntityClass<z.ZodObject<{
|
|
|
82
82
|
}: GroupComputedInput) => string | undefined;
|
|
83
83
|
}, {
|
|
84
84
|
/**
|
|
85
|
-
* The package's module namespace
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
85
|
+
* The package's module namespace. The set's members are its glyph exports, named by the rule
|
|
86
|
+
* the metadata format declares (`glyphExportRule`), so an alias pair is one member and the
|
|
87
|
+
* package's infrastructure exports are none; `items` lays facts over members that exist, and a
|
|
88
|
+
* key naming no member is refused so a typo cannot invent a glyph. Each member's identity is
|
|
89
|
+
* recorded by reference, so an authored glyph (`name={StarIcon}`) is matched to its member by
|
|
90
|
+
* the object rather than by anything the component says about itself, and an alias resolves to
|
|
91
|
+
* the member it is. Read once while the config file is evaluated and never stored.
|
|
90
92
|
*/
|
|
91
93
|
readonly glyphs: ({
|
|
92
94
|
input,
|
|
@@ -94,7 +96,9 @@ declare const Icon: EntityClass<z.ZodObject<{
|
|
|
94
96
|
}: {
|
|
95
97
|
input: GlyphNamespace;
|
|
96
98
|
body: Readonly<Record<string, unknown>>;
|
|
97
|
-
}) =>
|
|
99
|
+
}) => {
|
|
100
|
+
items: Record<string, unknown>;
|
|
101
|
+
};
|
|
98
102
|
}>;
|
|
99
103
|
//#endregion
|
|
100
104
|
export { Icon, IconVariantAs, iconVariantAs };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { isRef, pathOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
3
|
-
import {
|
|
3
|
+
import { spellValues } from "../../framework/value-domain.js";
|
|
4
4
|
import { Package } from "./Package.js";
|
|
5
|
+
import { iconMemberMetadata, iconMetadataDeclaration, iconMetadataFormat } from "./icon-metadata.js";
|
|
6
|
+
import { glyphMembersOf, glyphOfLibrary, libraryGlyphFacts, recordGlyphIdentities } from "./glyph-identity.js";
|
|
5
7
|
import { iconDomainInvariants } from "./icon-domain-invariants.js";
|
|
6
|
-
import { iconMemberMetadata, iconMetadataDeclaration } from "./icon-metadata.js";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
//#region src/entities/system/Icon.ts
|
|
9
10
|
/**
|
|
@@ -74,19 +75,30 @@ const Icon = defineEntity({
|
|
|
74
75
|
},
|
|
75
76
|
groupInputs: {
|
|
76
77
|
/**
|
|
77
|
-
* The package's module namespace
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
78
|
+
* The package's module namespace. The set's members are its glyph exports, named by the rule
|
|
79
|
+
* the metadata format declares (`glyphExportRule`), so an alias pair is one member and the
|
|
80
|
+
* package's infrastructure exports are none; `items` lays facts over members that exist, and a
|
|
81
|
+
* key naming no member is refused so a typo cannot invent a glyph. Each member's identity is
|
|
82
|
+
* recorded by reference, so an authored glyph (`name={StarIcon}`) is matched to its member by
|
|
83
|
+
* the object rather than by anything the component says about itself, and an alias resolves to
|
|
84
|
+
* the member it is. Read once while the config file is evaluated and never stored.
|
|
82
85
|
*/
|
|
83
86
|
glyphs: ({ input, body }) => {
|
|
84
87
|
if (!isRef(body.package)) throw new Error("Icon.group: `glyphs` needs `package` on the same group, since a glyph is identified as an export of that module.");
|
|
88
|
+
const format = iconMetadataFormat.safeParse(body.metadata?.format);
|
|
89
|
+
const members = glyphMembersOf({
|
|
90
|
+
namespace: input,
|
|
91
|
+
format: format.success ? format.data : void 0
|
|
92
|
+
});
|
|
93
|
+
const overlay = body.items ?? {};
|
|
94
|
+
const unknown = Object.keys(overlay).filter((name) => !members.includes(name));
|
|
95
|
+
if (unknown.length > 0) throw new Error(`Icon.group: \`items\` names ${spellValues(unknown)}, which ${unknown.length === 1 ? "is not a glyph export" : "are not glyph exports"} of \`glyphs\`${members.length === 0 ? " (the namespace has no glyph components; the package may not be installed)" : ""}. \`items\` lays facts over the members the package exports; it cannot add one.`);
|
|
85
96
|
recordGlyphIdentities({
|
|
86
97
|
namespace: input,
|
|
87
|
-
names:
|
|
98
|
+
names: members,
|
|
88
99
|
specifier: pathOf(body.package)
|
|
89
100
|
});
|
|
101
|
+
return { items: Object.fromEntries(members.map((name) => [name, overlay[name] ?? {}])) };
|
|
90
102
|
} },
|
|
91
103
|
/**
|
|
92
104
|
* A value bound to a library may be the glyph component itself, or the `package:` export ref the
|
|
@@ -87,7 +87,7 @@ interface SlotDecl {
|
|
|
87
87
|
/**
|
|
88
88
|
* What may FILL this hole, as refs. Two shapes, both in this repo:
|
|
89
89
|
*
|
|
90
|
-
* - an icon LIBRARY — `
|
|
90
|
+
* - an icon LIBRARY — `EmptyState.icon` accepts `Icon.ref('phosphor')`, so any glyph that library
|
|
91
91
|
* registers can be dropped in
|
|
92
92
|
* - a COMPONENT — `PanelSegment` accepts `Component.ref('studio/PanelSegment/PanelSegmentCell')`
|
|
93
93
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { spellValues } from "../../framework/value-domain.js";
|
|
3
|
+
import { glyphExportRule } from "./icon-metadata.js";
|
|
3
4
|
import { memberLeaves } from "../../framework/projections.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
//#region src/entities/system/glyph-identity.ts
|
|
@@ -19,6 +20,29 @@ function isComponentType(value) {
|
|
|
19
20
|
return typeof value === "object" && value !== null && "$$typeof" in value && !("props" in value);
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
23
|
+
* The members a package namespace stands for: its component exports that the format's rule calls
|
|
24
|
+
* glyphs, each under the name the rule makes canonical, in export order with an alias pair
|
|
25
|
+
* collapsed to one member. A canonical spelling the namespace does not export as a component keeps
|
|
26
|
+
* the export's own name, so a rule reading a `displayName` the package left out still names a
|
|
27
|
+
* member the module has.
|
|
28
|
+
*/
|
|
29
|
+
function glyphMembersOf({ namespace, format }) {
|
|
30
|
+
const rule = glyphExportRule(format);
|
|
31
|
+
const members = /* @__PURE__ */ new Set();
|
|
32
|
+
for (const [name, value] of Object.entries(namespace)) {
|
|
33
|
+
if (!isComponentType(value) || !rule.isGlyph({
|
|
34
|
+
name,
|
|
35
|
+
value
|
|
36
|
+
})) continue;
|
|
37
|
+
const canonical = rule.canonical({
|
|
38
|
+
name,
|
|
39
|
+
value
|
|
40
|
+
});
|
|
41
|
+
members.add(isComponentType(namespace[canonical]) ? canonical : name);
|
|
42
|
+
}
|
|
43
|
+
return [...members];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
22
46
|
* Record which export each of `names` is in `namespace`, for the components among them.
|
|
23
47
|
*
|
|
24
48
|
* Only the listed names are recorded, so an alias the package also exports (Phosphor's deprecated
|
|
@@ -195,4 +219,4 @@ function bindPreviewGlyphs({ config, props }) {
|
|
|
195
219
|
return bind(props);
|
|
196
220
|
}
|
|
197
221
|
//#endregion
|
|
198
|
-
export { bindPreviewGlyphs, glyphIdentityOf, glyphLeafOf, glyphOfLibrary, glyphPackageRef, glyphPackageRefOf, isComponentType, libraryGlyphFacts, recordGlyphIdentities };
|
|
222
|
+
export { bindPreviewGlyphs, glyphIdentityOf, glyphLeafOf, glyphMembersOf, glyphOfLibrary, glyphPackageRef, glyphPackageRefOf, isComponentType, libraryGlyphFacts, recordGlyphIdentities };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Config } from '../../framework/Config';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* The rules that hold between icon libraries and the components that draw them: a leaf two bound
|
|
4
|
+
* libraries both ship ({@link collisions}), a glyph nothing bound ({@link unboundGlyphs}), and a
|
|
5
|
+
* member's baked style the drawer's `variant` prop does not declare ({@link bakedVariants}).
|
|
6
6
|
*
|
|
7
|
-
* Declared from
|
|
8
|
-
* rules: a component binding two libraries is a component write,
|
|
9
|
-
* later is an icon write, and
|
|
7
|
+
* Declared from `Component`, `Icon` and `CanvasRole`, since `assertInvariants` runs only the patched
|
|
8
|
+
* kind's rules: a component binding two libraries is a component write, a glyph added to one of them
|
|
9
|
+
* later or a style baked onto a member is an icon write, and a role entry choosing another drawer is
|
|
10
|
+
* a canvas-role write, and any of them can create one of these states.
|
|
10
11
|
*/
|
|
11
12
|
export declare function iconDomainInvariants(config: Config): string[];
|
|
@@ -1,21 +1,62 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf } from "../../framework/utils/refs.js";
|
|
2
|
+
import { spellValues } from "../../framework/value-domain.js";
|
|
2
3
|
import { collectBag, isPlainRecord } from "./style-bag.js";
|
|
3
4
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
4
|
-
import { glyphLibrariesOf, memberLeaves, refListOf } from "../../framework/projections.js";
|
|
5
|
+
import { glyphComponentOf, glyphLibrariesOf, memberLeaves, propValueDomain, refListOf, resolveComponentProps } from "../../framework/projections.js";
|
|
5
6
|
//#region src/entities/system/icon-domain-invariants.ts
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* The rules that hold between icon libraries and the components that draw them: a leaf two bound
|
|
9
|
+
* libraries both ship ({@link collisions}), a glyph nothing bound ({@link unboundGlyphs}), and a
|
|
10
|
+
* member's baked style the drawer's `variant` prop does not declare ({@link bakedVariants}).
|
|
10
11
|
*
|
|
11
|
-
* Declared from
|
|
12
|
-
* rules: a component binding two libraries is a component write,
|
|
13
|
-
* later is an icon write, and
|
|
12
|
+
* Declared from `Component`, `Icon` and `CanvasRole`, since `assertInvariants` runs only the patched
|
|
13
|
+
* kind's rules: a component binding two libraries is a component write, a glyph added to one of them
|
|
14
|
+
* later or a style baked onto a member is an icon write, and a role entry choosing another drawer is
|
|
15
|
+
* a canvas-role write, and any of them can create one of these states.
|
|
14
16
|
*/
|
|
15
17
|
function iconDomainInvariants(config) {
|
|
16
|
-
return [
|
|
18
|
+
return [
|
|
19
|
+
...collisions(config),
|
|
20
|
+
...unboundGlyphs(config),
|
|
21
|
+
...bakedVariants(config)
|
|
22
|
+
];
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
25
|
+
* A member that bakes `variants` names the styles it draws in its package's words, and the drawer
|
|
26
|
+
* that places it may declare a `variant` prop of its own. When it does, every baked word has to be
|
|
27
|
+
* one the prop declares, else the panel would narrow to a style the drawer cannot draw. A drawer
|
|
28
|
+
* with no `variant` prop (a set whose styles are separate exports) is never checked, since the
|
|
29
|
+
* member is the style. The bake writes each member through an ordinary icon update, so the rule
|
|
30
|
+
* runs on the build with no wiring of its own.
|
|
31
|
+
*/
|
|
32
|
+
const bakedVariants = createSliceMemo({
|
|
33
|
+
kinds: [
|
|
34
|
+
"component",
|
|
35
|
+
"icon",
|
|
36
|
+
"canvas-role"
|
|
37
|
+
],
|
|
38
|
+
compute: (config) => {
|
|
39
|
+
const problems = [];
|
|
40
|
+
for (const group of config.groups("icon")) {
|
|
41
|
+
const drawer = glyphComponentOf(config, group.path);
|
|
42
|
+
if (!drawer) continue;
|
|
43
|
+
const declaration = resolveComponentProps(config, drawer.path).variant;
|
|
44
|
+
if (declaration?.type !== "variant") continue;
|
|
45
|
+
const declared = propValueDomain(config, declaration)?.leaves ?? [];
|
|
46
|
+
const allowed = new Set(declared);
|
|
47
|
+
for (const member of config.members("icon", group.path)) {
|
|
48
|
+
const baked = member.body.variants;
|
|
49
|
+
if (!Array.isArray(baked)) continue;
|
|
50
|
+
for (const value of baked) {
|
|
51
|
+
if (typeof value !== "string" || allowed.has(value)) continue;
|
|
52
|
+
problems.push(`Icon library "${group.path}" member "${member.leaf}" bakes the variant "${value}", which the drawer "${drawer.path}" does not declare on its \`variant\` prop (${declared.length === 0 ? "it declares no values" : spellValues(declared)}); a set's styles have to be words its drawer draws.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return problems;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
19
60
|
* A glyph authored as its component leaves the open-bag pass as a `package:` export ref, and the
|
|
20
61
|
* owner-bound pass binds that to the member when the key's domain is a library drawing from that
|
|
21
62
|
* module. One left in a bag is a glyph nothing bound, and this refuses it by what went wrong: no
|
|
@@ -94,8 +94,9 @@ declare function resolveIconLibraries({
|
|
|
94
94
|
* {@link glyphComponentOf}.
|
|
95
95
|
*/
|
|
96
96
|
/**
|
|
97
|
-
* The libraries the canvas's icon tool offers:
|
|
98
|
-
* when the `icon` canvas role is unregistered,
|
|
97
|
+
* The libraries the canvas's icon tool offers: the union of every entry's glyph domain, in entry
|
|
98
|
+
* and then declaration order, each library once. Empty when the `icon` canvas role is unregistered,
|
|
99
|
+
* which is also when the tool is disabled.
|
|
99
100
|
*/
|
|
100
101
|
declare function iconToolLibraries(config: Config | null | undefined): IconLibrary[];
|
|
101
102
|
declare function librariesBoundBy({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
2
|
-
import { glyphComponentOf, glyphLibrariesOf,
|
|
2
|
+
import { glyphComponentOf, glyphLibrariesOf, iconToolFor, iconToolsOf, resolveComponentProps } from "../../framework/projections.js";
|
|
3
3
|
import { isValueSlot } from "../../framework/prop-surface.js";
|
|
4
4
|
import { Component } from "./Component.js";
|
|
5
5
|
import { parseGlyphType } from "../../spec/glyph-jsx.js";
|
|
@@ -162,8 +162,7 @@ function placedGlyphElement(config, glyph, props = {}) {
|
|
|
162
162
|
type: glyph,
|
|
163
163
|
props
|
|
164
164
|
};
|
|
165
|
-
const
|
|
166
|
-
const defaults = tool && tool.component === bound.path ? tool.defaultProps : {};
|
|
165
|
+
const defaults = iconToolFor(config, parsed.slug)?.defaultProps ?? {};
|
|
167
166
|
return {
|
|
168
167
|
type: `component:${bound.path}`,
|
|
169
168
|
props: {
|
|
@@ -207,15 +206,15 @@ function resolveIconLibraries({ config, hints }) {
|
|
|
207
206
|
* {@link glyphComponentOf}.
|
|
208
207
|
*/
|
|
209
208
|
/**
|
|
210
|
-
* The libraries the canvas's icon tool offers:
|
|
211
|
-
* when the `icon` canvas role is unregistered,
|
|
209
|
+
* The libraries the canvas's icon tool offers: the union of every entry's glyph domain, in entry
|
|
210
|
+
* and then declaration order, each library once. Empty when the `icon` canvas role is unregistered,
|
|
211
|
+
* which is also when the tool is disabled.
|
|
212
212
|
*/
|
|
213
213
|
function iconToolLibraries(config) {
|
|
214
214
|
if (!config) return NO_LIBRARIES;
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return glyphLibrariesOf(declaration?.value).map((path) => iconLibrary(config, path)).filter((library) => library !== void 0);
|
|
215
|
+
const paths = /* @__PURE__ */ new Set();
|
|
216
|
+
for (const tool of iconToolsOf(config)) for (const path of tool.libraries) paths.add(path);
|
|
217
|
+
return [...paths].map((path) => iconLibrary(config, path)).filter((library) => library !== void 0);
|
|
219
218
|
}
|
|
220
219
|
function librariesBoundBy({ config, component }) {
|
|
221
220
|
if (!config) return NO_LIBRARIES;
|
|
@@ -54,6 +54,30 @@ declare const iconMetadataDeclaration: z.ZodObject<{
|
|
|
54
54
|
type IconMetadataDeclaration = z.infer<typeof iconMetadataDeclaration>;
|
|
55
55
|
/** A format adapter: raw source data in, per-member metadata out. Throws on a shape it can't read. */
|
|
56
56
|
type IconMetadataAdapter = (raw: unknown) => Record<string, IconMemberMetadata>;
|
|
57
|
+
/**
|
|
58
|
+
* Which of a package's component exports are glyphs, and which name of an alias pair is the member.
|
|
59
|
+
* A format's rule, beside its adapter, because the package the adapter describes is the one that
|
|
60
|
+
* decides both: Phosphor exports every glyph as `XIcon` beside a deprecated bare `X`, and Tabler
|
|
61
|
+
* exports 66 of its glyphs under two `Icon*` names. `Icon.group({ glyphs })` runs the rule over the
|
|
62
|
+
* namespace's component exports to name the set's members, so the caller has already dropped
|
|
63
|
+
* anything that is not a component.
|
|
64
|
+
*/
|
|
65
|
+
interface GlyphExportRule {
|
|
66
|
+
/** Whether a component export of this name is a glyph rather than infrastructure (`IconBase`). */
|
|
67
|
+
readonly isGlyph: (args: {
|
|
68
|
+
name: string;
|
|
69
|
+
value: unknown;
|
|
70
|
+
}) => boolean;
|
|
71
|
+
/** The member name an export stands for: itself, or the spelling the alias pair collapses to. */
|
|
72
|
+
readonly canonical: (args: {
|
|
73
|
+
name: string;
|
|
74
|
+
value: unknown;
|
|
75
|
+
}) => string;
|
|
76
|
+
}
|
|
77
|
+
/** The glyph export rule a set's metadata format declares; a set with no format keeps every
|
|
78
|
+
* component export under its own name. */
|
|
79
|
+
declare function glyphExportRule(format: IconMetadataFormat | undefined): GlyphExportRule;
|
|
80
|
+
declare function iconMetadataSourceFile(format: IconMetadataFormat): string | undefined;
|
|
57
81
|
/**
|
|
58
82
|
* The uds format IS this file schema — `{ [memberName]: { categories?, tags?, codepoint?,
|
|
59
83
|
* variants?, knockoutVariants? } }` —
|
|
@@ -72,7 +96,15 @@ type IconMetadataFile = z.infer<typeof iconMetadataFile>;
|
|
|
72
96
|
declare function iconMetadataFileJsonSchema(): Record<string, unknown>;
|
|
73
97
|
/** `brand-4chan` → `IconBrand4chan`: the react package's export for a slug. */
|
|
74
98
|
declare function tablerExportName(slug: string): string;
|
|
99
|
+
/** `IconStar` plus `filled` → `IconStarFilled`: the export a non-outline style is drawn by. */
|
|
100
|
+
declare function tablerStyledExportName({
|
|
101
|
+
base,
|
|
102
|
+
style
|
|
103
|
+
}: {
|
|
104
|
+
base: string;
|
|
105
|
+
style: string;
|
|
106
|
+
}): string;
|
|
75
107
|
/** Run the named format's adapter. The host resolved and read `raw`; this stays pure. */
|
|
76
108
|
declare function iconMetadata(format: IconMetadataFormat, raw: unknown): Record<string, IconMemberMetadata>;
|
|
77
109
|
//#endregion
|
|
78
|
-
export { ICON_METADATA_FORMATS, IconMemberMetadata, IconMetadataAdapter, IconMetadataDeclaration, IconMetadataFile, IconMetadataFormat, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, tablerExportName };
|
|
110
|
+
export { GlyphExportRule, ICON_METADATA_FORMATS, IconMemberMetadata, IconMetadataAdapter, IconMetadataDeclaration, IconMetadataFile, IconMetadataFormat, glyphExportRule, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, iconMetadataSourceFile, tablerExportName, tablerStyledExportName };
|
|
@@ -52,6 +52,40 @@ const iconMetadataDeclaration = z.strictObject({
|
|
|
52
52
|
from: Package,
|
|
53
53
|
format: iconMetadataFormat
|
|
54
54
|
});
|
|
55
|
+
/** Every component export is a glyph under its own name: the rule for `uds` and for a set that
|
|
56
|
+
* declares no metadata format. */
|
|
57
|
+
const everyComponentExport = {
|
|
58
|
+
isGlyph: () => true,
|
|
59
|
+
canonical: ({ name }) => name
|
|
60
|
+
};
|
|
61
|
+
const GLYPH_EXPORT_RULES = {
|
|
62
|
+
phosphor: {
|
|
63
|
+
isGlyph: ({ name }) => name.endsWith("Icon"),
|
|
64
|
+
canonical: ({ name }) => name.endsWith("Icon") ? name : `${name}Icon`
|
|
65
|
+
},
|
|
66
|
+
uds: everyComponentExport,
|
|
67
|
+
tabler: {
|
|
68
|
+
isGlyph: ({ name }) => name.startsWith("Icon"),
|
|
69
|
+
canonical: ({ name, value }) => {
|
|
70
|
+
const displayName = value?.displayName;
|
|
71
|
+
return typeof displayName === "string" && displayName.length > 0 ? `Icon${displayName}` : name;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/** The glyph export rule a set's metadata format declares; a set with no format keeps every
|
|
76
|
+
* component export under its own name. */
|
|
77
|
+
function glyphExportRule(format) {
|
|
78
|
+
return format === void 0 ? everyComponentExport : GLYPH_EXPORT_RULES[format];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The file inside the source package a format's catalogue is, for a package whose manifest names no
|
|
82
|
+
* entry: `@tabler/icons` exports only `./icons/*` and ships `icons.json` at its root. A format
|
|
83
|
+
* without one reads the package's own entry.
|
|
84
|
+
*/
|
|
85
|
+
const SOURCE_FILES = { tabler: "icons.json" };
|
|
86
|
+
function iconMetadataSourceFile(format) {
|
|
87
|
+
return SOURCE_FILES[format];
|
|
88
|
+
}
|
|
55
89
|
/**
|
|
56
90
|
* The uds format IS this file schema — `{ [memberName]: { categories?, tags?, codepoint?,
|
|
57
91
|
* variants?, knockoutVariants? } }` —
|
|
@@ -107,33 +141,58 @@ const uds = (raw) => {
|
|
|
107
141
|
};
|
|
108
142
|
/**
|
|
109
143
|
* Tabler's catalogue: `@tabler/icons` ships `icons.json`, a record keyed by kebab slug. Each entry
|
|
110
|
-
* carries a singular `category`, `tags` that mix strings
|
|
111
|
-
*
|
|
144
|
+
* carries a singular `category`, `tags` that mix strings, numbers and the odd `null` (the four
|
|
145
|
+
* `*-number-0` entries spell one tag as `null`), and a `styles` record whose keys are the styles the
|
|
146
|
+
* glyph draws (`outline` always, `filled` for a subset), each with its own codepoint. Loose for the
|
|
112
147
|
* same reason as Phosphor's.
|
|
113
148
|
*/
|
|
114
149
|
const tablerCatalog = z.record(z.string().min(1), z.looseObject({
|
|
115
150
|
name: z.string().min(1),
|
|
116
151
|
category: z.string().optional(),
|
|
117
|
-
tags: z.array(z.union([
|
|
152
|
+
tags: z.array(z.union([
|
|
153
|
+
z.string(),
|
|
154
|
+
z.number(),
|
|
155
|
+
z.null()
|
|
156
|
+
])).optional(),
|
|
118
157
|
styles: z.record(z.string().min(1), z.looseObject({ unicode: z.string().optional() }))
|
|
119
158
|
}));
|
|
120
159
|
/** `brand-4chan` → `IconBrand4chan`: the react package's export for a slug. */
|
|
121
160
|
function tablerExportName(slug) {
|
|
122
161
|
return `Icon${slug.split("-").map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("")}`;
|
|
123
162
|
}
|
|
163
|
+
/** `IconStar` plus `filled` → `IconStarFilled`: the export a non-outline style is drawn by. */
|
|
164
|
+
function tablerStyledExportName({ base, style }) {
|
|
165
|
+
if (style === "outline") return base;
|
|
166
|
+
return `${base}${style.charAt(0).toUpperCase()}${style.slice(1)}`;
|
|
167
|
+
}
|
|
168
|
+
/** A style's codepoint from its hex `unicode`. Whole-string hex only: `parseInt` would read `ea1z`
|
|
169
|
+
* as `ea1` and store a wrong glyph. */
|
|
170
|
+
function tablerCodepoint(unicode) {
|
|
171
|
+
if (unicode === void 0 || !/^[0-9a-fA-F]+$/.test(unicode)) return;
|
|
172
|
+
return Number.parseInt(unicode, 16);
|
|
173
|
+
}
|
|
124
174
|
const tabler = (raw) => {
|
|
125
175
|
const parsed = tablerCatalog.safeParse(raw);
|
|
126
176
|
if (!parsed.success) throw new Error(`tabler metadata source did not match @tabler/icons' icons.json shape — ${describeIssues(parsed.error)}`);
|
|
127
177
|
const members = {};
|
|
128
178
|
for (const [slug, entry] of Object.entries(parsed.data)) {
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
179
|
+
const base = tablerExportName(slug);
|
|
180
|
+
const tags = (entry.tags ?? []).filter((tag) => tag !== null).map(String);
|
|
181
|
+
const shared = {
|
|
132
182
|
...entry.category ? { categories: [entry.category] } : {},
|
|
133
|
-
...
|
|
134
|
-
...codepoint !== void 0 ? { codepoint } : {},
|
|
135
|
-
variants: Object.keys(entry.styles)
|
|
183
|
+
...tags.length > 0 ? { tags } : {}
|
|
136
184
|
};
|
|
185
|
+
for (const [style, styled] of Object.entries(entry.styles)) {
|
|
186
|
+
const codepoint = tablerCodepoint(styled.unicode);
|
|
187
|
+
members[tablerStyledExportName({
|
|
188
|
+
base,
|
|
189
|
+
style
|
|
190
|
+
})] = {
|
|
191
|
+
...shared,
|
|
192
|
+
...codepoint !== void 0 ? { codepoint } : {},
|
|
193
|
+
variants: [style]
|
|
194
|
+
};
|
|
195
|
+
}
|
|
137
196
|
}
|
|
138
197
|
return members;
|
|
139
198
|
};
|
|
@@ -148,4 +207,4 @@ function iconMetadata(format, raw) {
|
|
|
148
207
|
return ADAPTERS[format](raw);
|
|
149
208
|
}
|
|
150
209
|
//#endregion
|
|
151
|
-
export { ICON_METADATA_FORMATS, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, tablerExportName };
|
|
210
|
+
export { ICON_METADATA_FORMATS, glyphExportRule, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, iconMetadataSourceFile, tablerExportName, tablerStyledExportName };
|
|
@@ -11,6 +11,9 @@ interface DeclaredRuntimeModule {
|
|
|
11
11
|
readonly exports?: readonly string[];
|
|
12
12
|
/** This module also supplies the members of an icon library. */
|
|
13
13
|
readonly iconLibrary?: true;
|
|
14
|
+
/** This module is an icon library's metadata catalogue, read by the build and imported by
|
|
15
|
+
* nothing a rendered spec reaches. */
|
|
16
|
+
readonly catalogue?: true;
|
|
14
17
|
}
|
|
15
18
|
/**
|
|
16
19
|
* The npm modules this config itself declares at runtime.
|
|
@@ -23,14 +23,24 @@ function declaredRuntimeModules(config) {
|
|
|
23
23
|
for (const group of Icon.groups(config)) {
|
|
24
24
|
const named = group.meta.package;
|
|
25
25
|
const specifier = isRef(named) ? pathOf(named) : void 0;
|
|
26
|
-
if (specifier
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
26
|
+
if (specifier !== void 0) {
|
|
27
|
+
const existing = bySpecifier.get(specifier);
|
|
28
|
+
bySpecifier.set(specifier, {
|
|
29
|
+
...existing,
|
|
30
|
+
specifier,
|
|
31
|
+
iconLibrary: true
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const source = group.meta.metadata?.from;
|
|
35
|
+
const catalogue = isRef(source) ? pathOf(source) : void 0;
|
|
36
|
+
if (catalogue !== void 0) {
|
|
37
|
+
const existing = bySpecifier.get(catalogue);
|
|
38
|
+
bySpecifier.set(catalogue, {
|
|
39
|
+
...existing,
|
|
40
|
+
specifier: catalogue,
|
|
41
|
+
catalogue: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
34
44
|
}
|
|
35
45
|
return [...bySpecifier.values()].sort((left, right) => left.specifier.localeCompare(right.specifier));
|
|
36
46
|
}
|