@yahoo/uds-create-config 4.10.2 → 4.10.4
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 +165 -77
- package/dist/configs/documentation.d.ts +1 -1
- package/dist/configs/react-native-system.d.ts +111 -52
- package/dist/configs/system.d.ts +121 -87
- package/dist/configs/system.js +4 -0
- package/dist/entities/documentation/Documentation.d.ts +1 -1
- package/dist/entities/native/NativeModifier.d.ts +1 -1
- package/dist/entities/native/NativeSettings.d.ts +1 -1
- package/dist/entities/native/NativeStyleProperty.d.ts +2 -2
- package/dist/entities/native/NativeToken.d.ts +4 -3
- package/dist/entities/system/CanvasRole.d.ts +1 -1
- package/dist/entities/system/Component.d.ts +23 -13
- package/dist/entities/system/Component.js +41 -15
- package/dist/entities/system/Composite.d.ts +1 -1
- package/dist/entities/system/Device.d.ts +1 -1
- package/dist/entities/system/File.d.ts +2 -2
- package/dist/entities/system/Font.d.ts +1 -1
- package/dist/entities/system/GlobalStyle.d.ts +1 -1
- package/dist/entities/system/Guidance.d.ts +1 -1
- package/dist/entities/system/GuidanceStyle.d.ts +1 -1
- package/dist/entities/system/Icon.d.ts +63 -11
- package/dist/entities/system/Icon.js +70 -14
- package/dist/entities/system/LinkedSystem.d.ts +1 -1
- package/dist/entities/system/Modifier.d.ts +2 -2
- package/dist/entities/system/Motion.d.ts +1 -1
- package/dist/entities/system/Package.d.ts +1 -1
- package/dist/entities/system/Settings.d.ts +1 -1
- package/dist/entities/system/StyleProperty.d.ts +12 -19
- package/dist/entities/system/StyleProperty.js +7 -10
- package/dist/entities/system/Token.d.ts +4 -3
- package/dist/entities/system/defineComponent.d.ts +21 -6
- package/dist/entities/system/defineComponent.js +7 -12
- package/dist/entities/system/glyph-identity.d.ts +7 -0
- package/dist/entities/system/glyph-identity.js +153 -0
- package/dist/entities/system/icon-domain-invariants.d.ts +11 -0
- package/dist/entities/system/icon-domain-invariants.js +178 -0
- package/dist/entities/system/icon-library.d.ts +93 -34
- package/dist/entities/system/icon-library.js +218 -50
- package/dist/entities/system/icon-metadata.d.ts +10 -4
- package/dist/entities/system/icon-metadata.js +45 -5
- package/dist/entities/system/runtime-modules.js +5 -5
- package/dist/entities/system/style-bag.js +14 -2
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +34 -5
- package/dist/framework/defineConfig.d.ts +6 -3
- package/dist/framework/defineEntity.d.ts +54 -15
- package/dist/framework/defineEntity.js +56 -2
- package/dist/framework/projections.d.ts +40 -2
- package/dist/framework/projections.js +99 -5
- package/dist/framework/prop-surface.d.ts +6 -5
- package/dist/framework/prop-surface.js +12 -14
- package/dist/framework/registry.d.ts +17 -1
- package/dist/framework/registry.js +2 -1
- package/dist/framework/render-spec.d.ts +6 -5
- package/dist/framework/render-spec.js +16 -11
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/signature.js +5 -1
- package/dist/framework/utils/group.d.ts +15 -1
- package/dist/framework/utils/ref-grammar.d.ts +35 -0
- package/dist/framework/utils/ref-grammar.js +76 -0
- package/dist/framework/utils/refs.d.ts +13 -45
- package/dist/framework/utils/refs.js +31 -94
- package/dist/framework/value-domain.js +53 -8
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/migrations/2.0.0/v1-artifact.d.ts +62 -45
- package/dist/migrations/2.0.0/v1-artifact.js +5 -7
- package/dist/migrations/20260921044042_icon_library_without_component.d.ts +19 -0
- package/dist/migrations/20260921044042_icon_library_without_component.js +86 -0
- package/dist/migrations/20260922013625_icon_libraries.d.ts +18 -0
- package/dist/migrations/20260922013625_icon_libraries.js +8 -0
- package/dist/renderer/UdsRenderer.d.ts +8 -1
- package/dist/renderer/UdsRenderer.js +7 -3
- package/dist/renderer/glyphEntries.d.ts +32 -0
- package/dist/renderer/glyphEntries.js +48 -0
- package/dist/renderer/glyphRenderable.d.ts +10 -0
- package/dist/renderer/glyphRenderable.js +40 -0
- package/dist/renderer/icon-library.d.ts +18 -11
- package/dist/renderer/index.d.ts +4 -2
- package/dist/renderer/index.js +4 -2
- package/dist/renderer/resolveGlyph.d.ts +47 -0
- package/dist/renderer/resolveGlyph.js +78 -0
- package/dist/renderer/wrapRegistry.d.ts +13 -4
- package/dist/renderer/wrapRegistry.js +7 -5
- package/dist/renderer/wrappers/component-refs.js +6 -2
- package/dist/renderer/wrappers/glyph-props.d.ts +15 -0
- package/dist/renderer/wrappers/glyph-props.js +65 -0
- package/dist/spec/glyph-jsx.d.ts +41 -0
- package/dist/spec/{asset-jsx.js → glyph-jsx.js} +7 -25
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +2 -2
- package/dist/spec/jsxToSpec.d.ts +10 -4
- package/dist/spec/jsxToSpec.js +21 -4
- package/dist/spec/specToJsx.d.ts +20 -9
- package/dist/spec/specToJsx.js +77 -16
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/renderer/assetEntries.d.ts +0 -37
- package/dist/renderer/assetEntries.js +0 -38
- package/dist/renderer/assetRenderable.d.ts +0 -25
- package/dist/renderer/assetRenderable.js +0 -19
- package/dist/spec/asset-jsx.d.ts +0 -61
|
@@ -1,45 +1,105 @@
|
|
|
1
1
|
import { Config } from "../../framework/Config.js";
|
|
2
|
+
import { Icon, IconVariantAs } from "./Icon.js";
|
|
2
3
|
|
|
3
4
|
//#region src/entities/system/icon-library.d.ts
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* An icon library as its group node reads: the path, the stored set facts (`sizes`, `variants`,
|
|
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
|
|
9
|
+
* `Icon.groups`, so a field added on the entity is visible here without a second declaration.
|
|
10
|
+
*/
|
|
11
|
+
type IconLibrary = {
|
|
7
12
|
readonly path: string;
|
|
8
|
-
|
|
9
|
-
readonly members: readonly string[];
|
|
10
|
-
/** Named sizes (`sm: 16`). */
|
|
13
|
+
} & Undefinable<Omit<ReturnType<typeof Icon.groups>[number]['meta'], 'items' | 'sizes' | 'variants'>> & {
|
|
11
14
|
readonly sizes: Readonly<Record<string, number>>;
|
|
12
|
-
/** Weights/styles the set ships. */
|
|
13
15
|
readonly variants: readonly string[];
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
readonly
|
|
18
|
-
/** The
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
/** The variant the bound component declares in its `defaultProps` — what a
|
|
22
|
-
* picker seeds when nothing is stored. Passed through as DECLARED; a policy
|
|
23
|
-
* read validates against {@link variants} before trusting it. */
|
|
16
|
+
/** For a ragged set, the members whose own `variants` differ from the set's, by leaf. A member
|
|
17
|
+
* listing exactly the set's variants is left out, so the map stays as sparse as the
|
|
18
|
+
* raggedness. */
|
|
19
|
+
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
|
|
21
|
+
* stored. Passed through as declared; a policy read validates it against {@link variants}
|
|
22
|
+
* before trusting it. */
|
|
24
23
|
readonly defaultVariant?: string;
|
|
25
|
-
/** The size bucket the
|
|
26
|
-
*
|
|
24
|
+
/** The size bucket the library's drawer declares in its `defaultProps`. Same contract as
|
|
25
|
+
* {@link defaultVariant}: declared, not validated. */
|
|
27
26
|
readonly defaultSizeKey?: string;
|
|
28
|
-
}
|
|
27
|
+
};
|
|
28
|
+
/** A field that may hold `undefined` may be left out: a computed's `string | undefined` reads as an
|
|
29
|
+
* optional key, so a literal need not spell the absence. */
|
|
30
|
+
type Undefinable<T> = { readonly [K in keyof T as undefined extends T[K] ? K : never]?: T[K] } & { readonly [K in keyof T as undefined extends T[K] ? never : K]: T[K] };
|
|
29
31
|
/** The spec `type` a placed glyph of this library carries — its own ref. */
|
|
30
|
-
declare function
|
|
32
|
+
declare function glyphType(library: IconLibrary, member: string): string;
|
|
31
33
|
/** One library by its group path — `undefined` when the config has no such set. */
|
|
32
34
|
declare function iconLibrary(config: Config | null | undefined, path: string): IconLibrary | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The exports a glyph is drawn from: its own name, plus the export each `variantAs.export`
|
|
37
|
+
* template names for it. A per-glyph module has to carry all of them, since the glyph resolver
|
|
38
|
+
* swaps between them at render; a `prop` strategy or no declaration needs the bare export alone.
|
|
39
|
+
* With `variants`, the member's own list, only the templates for variants it ships are added: a
|
|
40
|
+
* ragged set's member has no export for the rest, and naming one fails the module's bundle.
|
|
41
|
+
*/
|
|
42
|
+
declare function glyphExportNames({
|
|
43
|
+
variantAs,
|
|
44
|
+
name,
|
|
45
|
+
variants
|
|
46
|
+
}: {
|
|
47
|
+
variantAs: IconVariantAs | undefined;
|
|
48
|
+
name: string;
|
|
49
|
+
variants?: readonly string[];
|
|
50
|
+
}): string[];
|
|
51
|
+
/**
|
|
52
|
+
* The element a glyph is PLACED as: an instance of the component that draws from its library, the
|
|
53
|
+
* member on that component's glyph prop and the set's axes as the component's own props — so a
|
|
54
|
+
* placed glyph paints exactly as the component would, and the panel edits it as one. A library no
|
|
55
|
+
* component draws from places the member raw, under its own `icon:` type.
|
|
56
|
+
*
|
|
57
|
+
* Only for placing. A node a render wrote (`<StarIcon size={12} />`) stays the raw member it is.
|
|
58
|
+
*/
|
|
59
|
+
declare function placedGlyphElement(config: Config | null | undefined, glyph: string, props?: Record<string, unknown>): {
|
|
60
|
+
type: string;
|
|
61
|
+
props: Record<string, unknown>;
|
|
62
|
+
};
|
|
33
63
|
/** Every icon library the config declares. */
|
|
34
64
|
declare function iconLibraries(config: Config | null | undefined): IconLibrary[];
|
|
35
65
|
/**
|
|
36
|
-
* The
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
66
|
+
* The libraries a surface should offer: the hinted ones in the order given (a prop whose domain
|
|
67
|
+
* lists several sets), else every library that actually has members. One home for that policy — the
|
|
68
|
+
* toolbar, placement and the panel all resolve through here, so no surface carries its own idea of
|
|
69
|
+
* a default set. A hint naming no library is dropped rather than failing the list, so one stale
|
|
70
|
+
* slug in a pair still shows the other set. An empty list of hints offers nothing: the caller had a
|
|
71
|
+
* domain and it named no library, which is not the same as having no domain.
|
|
41
72
|
*/
|
|
42
|
-
declare function
|
|
73
|
+
declare function resolveIconLibraries({
|
|
74
|
+
config,
|
|
75
|
+
hints
|
|
76
|
+
}: {
|
|
77
|
+
config: Config | null | undefined;
|
|
78
|
+
hints?: readonly string[];
|
|
79
|
+
}): IconLibrary[];
|
|
80
|
+
/**
|
|
81
|
+
* The libraries a component binds: every icon group one of its variant props names as its domain,
|
|
82
|
+
* in the order the props and their lists declare them. A surface handed a bare glyph name by the
|
|
83
|
+
* component resolves it against this list, so a set outside the domain never answers for one in it.
|
|
84
|
+
* A facet ref (`icon:phosphor#variants`) offers the set's variants rather than its glyphs, so it
|
|
85
|
+
* binds nothing — `glyphLibrariesOf` is the one reading of the edge, shared with
|
|
86
|
+
* {@link glyphComponentOf}.
|
|
87
|
+
*/
|
|
88
|
+
declare function librariesBoundBy({
|
|
89
|
+
config,
|
|
90
|
+
component
|
|
91
|
+
}: {
|
|
92
|
+
config: Config | null | undefined;
|
|
93
|
+
component: string;
|
|
94
|
+
}): IconLibrary[];
|
|
95
|
+
/** The library holding `member`, among the ones a surface offers. */
|
|
96
|
+
declare function libraryHolding({
|
|
97
|
+
libraries,
|
|
98
|
+
member
|
|
99
|
+
}: {
|
|
100
|
+
libraries: readonly IconLibrary[];
|
|
101
|
+
member: string | undefined;
|
|
102
|
+
}): IconLibrary | undefined;
|
|
43
103
|
/**
|
|
44
104
|
* Every category the library's members carry, RAW as stored (lowercase, unsorted within a member,
|
|
45
105
|
* plural per member), deduplicated and sorted for a filter menu. Casing is display policy — a
|
|
@@ -47,13 +107,12 @@ declare function resolveIconLibrary(config: Config | null | undefined, hint?: st
|
|
|
47
107
|
*/
|
|
48
108
|
declare function iconCategories(config: Config | null | undefined, libraryPath: string): readonly string[];
|
|
49
109
|
/**
|
|
50
|
-
* The variants a placed glyph may take
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* some of its glyphs support will offer it for all of them until that closes.
|
|
110
|
+
* The variants a placed glyph may take: the member's own `variants` when its metadata lists them (a
|
|
111
|
+
* ragged set), else the whole library's. Kept in the library's order, so a picker's axis reads the
|
|
112
|
+
* same across glyphs. A member listing only variants the set doesn't ship falls back to the set's,
|
|
113
|
+
* so the axis is never empty for a set that ships one.
|
|
55
114
|
*/
|
|
56
|
-
declare function memberVariantOptions(library: IconLibrary,
|
|
115
|
+
declare function memberVariantOptions(library: IconLibrary, member: string): readonly string[];
|
|
57
116
|
/**
|
|
58
117
|
* Whether an element type declares a prop that may survive layer-style projection. A placed
|
|
59
118
|
* glyph's type isn't a component, so its prop surface comes from its library instead: the
|
|
@@ -61,4 +120,4 @@ declare function memberVariantOptions(library: IconLibrary, _member: string): re
|
|
|
61
120
|
*/
|
|
62
121
|
declare function isDeclaredElementProp(config: Config | null | undefined, elementType: string, propName: string): boolean;
|
|
63
122
|
//#endregion
|
|
64
|
-
export { IconLibrary,
|
|
123
|
+
export { IconLibrary, glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
|
|
@@ -1,68 +1,237 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { resolveComponentProps } from "../../framework/projections.js";
|
|
1
|
+
import { createSliceMemo } from "../../framework/memo.js";
|
|
2
|
+
import { glyphComponentOf, glyphLibrariesOf, resolveComponentProps } from "../../framework/projections.js";
|
|
3
3
|
import { Component } from "./Component.js";
|
|
4
4
|
import { Icon } from "./Icon.js";
|
|
5
|
-
import {
|
|
5
|
+
import { parseGlyphType } from "../../spec/glyph-jsx.js";
|
|
6
6
|
//#region src/entities/system/icon-library.ts
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* the entity that stores them.
|
|
8
|
+
* Icon-library reads — an icon group's node with its computeds, and the policy reads over it.
|
|
10
9
|
*
|
|
11
10
|
* An icon is an entity (`icon:phosphor/StarIcon`) and everything describing the SET lives on the
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* rather than re-querying the config per member.
|
|
11
|
+
* group node: the sizes and variants it ships, the package its glyphs come from, and the members
|
|
12
|
+
* and module the entity computes from those. {@link IconLibrary} is that node flattened with its
|
|
13
|
+
* path, so a surface asks a plain value rather than re-querying the config per member.
|
|
15
14
|
*
|
|
16
15
|
* A placed glyph's spec `type` IS the member's ref (`icon:phosphor/StarIcon`) — the same identity
|
|
17
|
-
* the config uses, which is what `
|
|
16
|
+
* the config uses, which is what `parseGlyphType` reads.
|
|
18
17
|
*
|
|
19
18
|
* This is the one home for the question "what icon sets does this system have" — Studio owns only
|
|
20
|
-
* UI policy on top (picker state, grid geometry, recents, search ranking).
|
|
21
|
-
* the
|
|
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
|
|
21
|
+
* its version comes from (`package`) — so it is reference-stable across calls on one config and
|
|
22
|
+
* safe in a dep array.
|
|
22
23
|
*/
|
|
23
|
-
const EMPTY_VARIANTS = Object.freeze([]);
|
|
24
|
-
const EMPTY_SIZES = Object.freeze({});
|
|
25
24
|
const EMPTY_CATEGORIES = Object.freeze([]);
|
|
25
|
+
const EMPTY_SIZES = Object.freeze({});
|
|
26
|
+
const EMPTY_VARIANTS = Object.freeze([]);
|
|
27
|
+
const NO_LIBRARIES = [];
|
|
26
28
|
/** The spec `type` a placed glyph of this library carries — its own ref. */
|
|
27
|
-
function
|
|
29
|
+
function glyphType(library, member) {
|
|
28
30
|
return `icon:${library.path}/${member}`;
|
|
29
31
|
}
|
|
30
32
|
/** One library by its group path — `undefined` when the config has no such set. */
|
|
31
33
|
function iconLibrary(config, path) {
|
|
32
34
|
if (!config) return void 0;
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const cache = librariesOf(config);
|
|
36
|
+
if (cache.has(path)) return cache.get(path);
|
|
37
|
+
const library = readIconLibrary(config, path);
|
|
38
|
+
cache.set(path, library);
|
|
39
|
+
return library;
|
|
40
|
+
}
|
|
41
|
+
/** Per-config cache of {@link iconLibrary} answers. `package` is in the key because the set's
|
|
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. */
|
|
44
|
+
const librariesOf = createSliceMemo({
|
|
45
|
+
kinds: [
|
|
46
|
+
"icon",
|
|
47
|
+
"component",
|
|
48
|
+
"package"
|
|
49
|
+
],
|
|
50
|
+
compute: (_config) => /* @__PURE__ */ new Map()
|
|
51
|
+
});
|
|
52
|
+
function readIconLibrary(config, path) {
|
|
53
|
+
const group = Icon.groups(config).find((entry) => entry.path === path);
|
|
54
|
+
if (!group) return void 0;
|
|
55
|
+
const { items: _items, sizes, variants, ...meta } = group.meta;
|
|
56
|
+
const set = setMembers({
|
|
57
|
+
config,
|
|
58
|
+
path,
|
|
59
|
+
declared: variants
|
|
60
|
+
});
|
|
39
61
|
return {
|
|
62
|
+
...meta,
|
|
40
63
|
path,
|
|
41
|
-
members:
|
|
42
|
-
sizes:
|
|
43
|
-
variants:
|
|
44
|
-
...
|
|
45
|
-
...
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
64
|
+
members: set.members,
|
|
65
|
+
sizes: sizes ?? EMPTY_SIZES,
|
|
66
|
+
variants: variants ?? EMPTY_VARIANTS,
|
|
67
|
+
...set.memberVariants ? { memberVariants: set.memberVariants } : {},
|
|
68
|
+
...drawerDefaults({
|
|
69
|
+
config,
|
|
70
|
+
library: path
|
|
71
|
+
})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The defaults the set's drawer declares: the component whose own variant prop names this library
|
|
76
|
+
* carries "what a bare glyph looks like", read back here so every picker seeds from that one
|
|
77
|
+
* declaration rather than its own literal. A library no component draws from has no defaults.
|
|
78
|
+
*/
|
|
79
|
+
function drawerDefaults({ config, library }) {
|
|
80
|
+
const drawer = glyphComponentOf(config, library);
|
|
81
|
+
if (!drawer) return {};
|
|
82
|
+
const defaults = Component.get(config, drawer.path)?.defaultProps;
|
|
83
|
+
const variant = defaults?.variant;
|
|
84
|
+
const size = defaults?.size;
|
|
85
|
+
return {
|
|
86
|
+
...typeof variant === "string" ? { defaultVariant: variant } : {},
|
|
87
|
+
...typeof size === "string" ? { defaultSizeKey: size } : {}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Per-config cache of the member walk, which is the cost a large set carries. */
|
|
91
|
+
const membersOf = createSliceMemo({
|
|
92
|
+
kinds: ["icon"],
|
|
93
|
+
compute: (_config) => /* @__PURE__ */ new Map()
|
|
94
|
+
});
|
|
95
|
+
function setMembers({ config, path, declared }) {
|
|
96
|
+
const walked = membersOf(config);
|
|
97
|
+
const hit = walked.get(path);
|
|
98
|
+
if (hit) return hit;
|
|
99
|
+
const members = [];
|
|
100
|
+
const memberVariants = {};
|
|
101
|
+
for (const member of config.members("icon", path)) {
|
|
102
|
+
const leaf = member.path.startsWith(`${path}/`) ? member.path.slice(path.length + 1) : member.path;
|
|
103
|
+
members.push(leaf);
|
|
104
|
+
const own = ownVariantsOf(member.body);
|
|
105
|
+
if (own && own.length > 0 && !sameVariants({
|
|
106
|
+
own,
|
|
107
|
+
declared
|
|
108
|
+
})) memberVariants[leaf] = own;
|
|
109
|
+
}
|
|
110
|
+
const set = {
|
|
111
|
+
members,
|
|
112
|
+
...Object.keys(memberVariants).length > 0 ? { memberVariants } : {}
|
|
113
|
+
};
|
|
114
|
+
walked.set(path, set);
|
|
115
|
+
return set;
|
|
116
|
+
}
|
|
117
|
+
/** A member body's `variants`, when it is a list of names. */
|
|
118
|
+
function ownVariantsOf(body) {
|
|
119
|
+
const declared = body.variants;
|
|
120
|
+
if (!Array.isArray(declared)) return void 0;
|
|
121
|
+
return declared.filter((variant) => typeof variant === "string");
|
|
122
|
+
}
|
|
123
|
+
/** Whether a member's list names exactly the set's variants, in any order. */
|
|
124
|
+
function sameVariants({ own, declared }) {
|
|
125
|
+
if (!declared || declared.length !== own.length) return false;
|
|
126
|
+
const set = new Set(declared);
|
|
127
|
+
return own.every((variant) => set.has(variant));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The exports a glyph is drawn from: its own name, plus the export each `variantAs.export`
|
|
131
|
+
* template names for it. A per-glyph module has to carry all of them, since the glyph resolver
|
|
132
|
+
* swaps between them at render; a `prop` strategy or no declaration needs the bare export alone.
|
|
133
|
+
* With `variants`, the member's own list, only the templates for variants it ships are added: a
|
|
134
|
+
* ragged set's member has no export for the rest, and naming one fails the module's bundle.
|
|
135
|
+
*/
|
|
136
|
+
function glyphExportNames({ variantAs, name, variants }) {
|
|
137
|
+
const names = new Set([name]);
|
|
138
|
+
if (variantAs && "export" in variantAs) for (const [variant, template] of Object.entries(variantAs.export)) {
|
|
139
|
+
if (variants && !variants.includes(variant)) continue;
|
|
140
|
+
names.add(template.replaceAll("{name}", name));
|
|
141
|
+
}
|
|
142
|
+
return [...names];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The element a glyph is PLACED as: an instance of the component that draws from its library, the
|
|
146
|
+
* member on that component's glyph prop and the set's axes as the component's own props — so a
|
|
147
|
+
* placed glyph paints exactly as the component would, and the panel edits it as one. A library no
|
|
148
|
+
* component draws from places the member raw, under its own `icon:` type.
|
|
149
|
+
*
|
|
150
|
+
* Only for placing. A node a render wrote (`<StarIcon size={12} />`) stays the raw member it is.
|
|
151
|
+
*/
|
|
152
|
+
function placedGlyphElement(config, glyph, props = {}) {
|
|
153
|
+
const parsed = parseGlyphType(glyph);
|
|
154
|
+
const drawer = parsed && config ? glyphComponentOf(config, parsed.slug) : void 0;
|
|
155
|
+
if (!parsed || !drawer) return {
|
|
156
|
+
type: glyph,
|
|
157
|
+
props
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
type: `component:${drawer.path}`,
|
|
161
|
+
props: {
|
|
162
|
+
[drawer.prop]: parsed.member,
|
|
163
|
+
...props
|
|
164
|
+
}
|
|
49
165
|
};
|
|
50
166
|
}
|
|
51
167
|
/** Every icon library the config declares. */
|
|
52
168
|
function iconLibraries(config) {
|
|
53
|
-
if (!config) return
|
|
54
|
-
return
|
|
169
|
+
if (!config) return NO_LIBRARIES;
|
|
170
|
+
return allLibrariesOf(config);
|
|
55
171
|
}
|
|
172
|
+
const allLibrariesOf = createSliceMemo({
|
|
173
|
+
kinds: [
|
|
174
|
+
"icon",
|
|
175
|
+
"component",
|
|
176
|
+
"package"
|
|
177
|
+
],
|
|
178
|
+
compute: (config) => Icon.groups(config).map(({ path }) => iconLibrary(config, path)).filter((library) => library !== void 0)
|
|
179
|
+
});
|
|
56
180
|
/**
|
|
57
|
-
* The
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
181
|
+
* The libraries a surface should offer: the hinted ones in the order given (a prop whose domain
|
|
182
|
+
* lists several sets), else every library that actually has members. One home for that policy — the
|
|
183
|
+
* toolbar, placement and the panel all resolve through here, so no surface carries its own idea of
|
|
184
|
+
* a default set. A hint naming no library is dropped rather than failing the list, so one stale
|
|
185
|
+
* slug in a pair still shows the other set. An empty list of hints offers nothing: the caller had a
|
|
186
|
+
* domain and it named no library, which is not the same as having no domain.
|
|
62
187
|
*/
|
|
63
|
-
function
|
|
64
|
-
if (
|
|
65
|
-
return iconLibraries(config).
|
|
188
|
+
function resolveIconLibraries({ config, hints }) {
|
|
189
|
+
if (hints !== void 0) return hints.map((hint) => iconLibrary(config, hint)).filter((library) => library !== void 0);
|
|
190
|
+
return iconLibraries(config).filter((library) => library.members.length > 0);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The libraries a component binds: every icon group one of its variant props names as its domain,
|
|
194
|
+
* in the order the props and their lists declare them. A surface handed a bare glyph name by the
|
|
195
|
+
* component resolves it against this list, so a set outside the domain never answers for one in it.
|
|
196
|
+
* A facet ref (`icon:phosphor#variants`) offers the set's variants rather than its glyphs, so it
|
|
197
|
+
* binds nothing — `glyphLibrariesOf` is the one reading of the edge, shared with
|
|
198
|
+
* {@link glyphComponentOf}.
|
|
199
|
+
*/
|
|
200
|
+
function librariesBoundBy({ config, component }) {
|
|
201
|
+
if (!config) return NO_LIBRARIES;
|
|
202
|
+
const cache = boundLibrariesOf(config);
|
|
203
|
+
const hit = cache.get(component);
|
|
204
|
+
if (hit) return hit;
|
|
205
|
+
const bound = readBoundLibraries({
|
|
206
|
+
config,
|
|
207
|
+
component
|
|
208
|
+
});
|
|
209
|
+
cache.set(component, bound);
|
|
210
|
+
return bound;
|
|
211
|
+
}
|
|
212
|
+
/** Per-config cache of {@link librariesBoundBy}, keyed on the slices a prop's domain and the
|
|
213
|
+
* libraries it names read. */
|
|
214
|
+
const boundLibrariesOf = createSliceMemo({
|
|
215
|
+
kinds: [
|
|
216
|
+
"component",
|
|
217
|
+
"icon",
|
|
218
|
+
"package"
|
|
219
|
+
],
|
|
220
|
+
compute: (_config) => /* @__PURE__ */ new Map()
|
|
221
|
+
});
|
|
222
|
+
function readBoundLibraries({ config, component }) {
|
|
223
|
+
const paths = /* @__PURE__ */ new Set();
|
|
224
|
+
for (const declaration of Object.values(resolveComponentProps(config, component))) {
|
|
225
|
+
const declared = declaration;
|
|
226
|
+
if (declared?.type !== "variant") continue;
|
|
227
|
+
for (const path of glyphLibrariesOf(declared.value)) paths.add(path);
|
|
228
|
+
}
|
|
229
|
+
return [...paths].map((path) => iconLibrary(config, path)).filter((library) => library !== void 0);
|
|
230
|
+
}
|
|
231
|
+
/** The library holding `member`, among the ones a surface offers. */
|
|
232
|
+
function libraryHolding({ libraries, member }) {
|
|
233
|
+
if (!member) return void 0;
|
|
234
|
+
return libraries.find((library) => library.members.includes(member));
|
|
66
235
|
}
|
|
67
236
|
/**
|
|
68
237
|
* Every category the library's members carry, RAW as stored (lowercase, unsorted within a member,
|
|
@@ -79,14 +248,16 @@ function iconCategories(config, libraryPath) {
|
|
|
79
248
|
return [...categories].sort((a, b) => a.localeCompare(b));
|
|
80
249
|
}
|
|
81
250
|
/**
|
|
82
|
-
* The variants a placed glyph may take
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* some of its glyphs support will offer it for all of them until that closes.
|
|
251
|
+
* The variants a placed glyph may take: the member's own `variants` when its metadata lists them (a
|
|
252
|
+
* ragged set), else the whole library's. Kept in the library's order, so a picker's axis reads the
|
|
253
|
+
* same across glyphs. A member listing only variants the set doesn't ship falls back to the set's,
|
|
254
|
+
* so the axis is never empty for a set that ships one.
|
|
87
255
|
*/
|
|
88
|
-
function memberVariantOptions(library,
|
|
89
|
-
|
|
256
|
+
function memberVariantOptions(library, member) {
|
|
257
|
+
const own = library.memberVariants?.[member];
|
|
258
|
+
if (!own || own.length === 0) return library.variants;
|
|
259
|
+
const narrowed = library.variants.filter((variant) => own.includes(variant));
|
|
260
|
+
return narrowed.length > 0 ? narrowed : library.variants;
|
|
90
261
|
}
|
|
91
262
|
/**
|
|
92
263
|
* Whether an element type declares a prop that may survive layer-style projection. A placed
|
|
@@ -101,16 +272,13 @@ function isDeclaredElementProp(config, elementType, propName) {
|
|
|
101
272
|
if (propName.startsWith("--")) return false;
|
|
102
273
|
return config.resolve("style-property", propName) === void 0;
|
|
103
274
|
}
|
|
104
|
-
const parsed =
|
|
275
|
+
const parsed = parseGlyphType(elementType);
|
|
105
276
|
if (!parsed) return false;
|
|
106
277
|
const library = iconLibrary(config, parsed.slug);
|
|
107
278
|
if (!library?.members.includes(parsed.member)) return false;
|
|
108
|
-
if (library.component) {
|
|
109
|
-
if (resolveComponentProps(config, library.component)[propName] !== void 0) return true;
|
|
110
|
-
}
|
|
111
279
|
if (propName === "size") return Object.keys(library.sizes).length > 0;
|
|
112
280
|
if (propName === "variant") return memberVariantOptions(library, parsed.member).length > 0;
|
|
113
281
|
return false;
|
|
114
282
|
}
|
|
115
283
|
//#endregion
|
|
116
|
-
export {
|
|
284
|
+
export { glyphExportNames, glyphType, iconCategories, iconLibraries, iconLibrary, isDeclaredElementProp, librariesBoundBy, libraryHolding, memberVariantOptions, placedGlyphElement, resolveIconLibraries };
|
|
@@ -16,10 +16,11 @@ import { z } from "zod";
|
|
|
16
16
|
* name). The list and the adapter table are one file so they cannot drift apart.
|
|
17
17
|
*/
|
|
18
18
|
/** The formats an icon group's `metadata.format` may declare — exactly the shipped adapters. */
|
|
19
|
-
declare const ICON_METADATA_FORMATS: readonly ["phosphor", "uds"];
|
|
19
|
+
declare const ICON_METADATA_FORMATS: readonly ["phosphor", "uds", "tabler"];
|
|
20
20
|
declare const iconMetadataFormat: z.ZodEnum<{
|
|
21
21
|
uds: "uds";
|
|
22
22
|
phosphor: "phosphor";
|
|
23
|
+
tabler: "tabler";
|
|
23
24
|
}>;
|
|
24
25
|
type IconMetadataFormat = (typeof ICON_METADATA_FORMATS)[number];
|
|
25
26
|
/**
|
|
@@ -30,6 +31,7 @@ declare const iconMemberMetadata: z.ZodObject<{
|
|
|
30
31
|
categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
31
32
|
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
32
33
|
codepoint: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
variants: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
33
35
|
knockoutVariants: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
34
36
|
}, z.core.$strict>;
|
|
35
37
|
type IconMemberMetadata = z.infer<typeof iconMemberMetadata>;
|
|
@@ -42,10 +44,11 @@ declare const iconMetadataDeclaration: z.ZodObject<{
|
|
|
42
44
|
from: EntityClass<z.ZodObject<{
|
|
43
45
|
version: z.ZodOptional<z.ZodString>;
|
|
44
46
|
exports: z.ZodOptional<SubEntityClass<z.ZodObject<{}, z.core.$strict>>>;
|
|
45
|
-
}, z.core.$strict>, z.ZodObject<Record<never, never>, z.core.$strip>, "package", Record<never, never>, Record<never, never>, false
|
|
47
|
+
}, z.core.$strict>, z.ZodObject<Record<never, never>, z.core.$strip>, "package", Record<never, never>, Record<never, never>, false, Record<never, never>, Record<never, never>>;
|
|
46
48
|
format: z.ZodEnum<{
|
|
47
49
|
uds: "uds";
|
|
48
50
|
phosphor: "phosphor";
|
|
51
|
+
tabler: "tabler";
|
|
49
52
|
}>;
|
|
50
53
|
}, z.core.$strict>;
|
|
51
54
|
type IconMetadataDeclaration = z.infer<typeof iconMetadataDeclaration>;
|
|
@@ -53,7 +56,7 @@ type IconMetadataDeclaration = z.infer<typeof iconMetadataDeclaration>;
|
|
|
53
56
|
type IconMetadataAdapter = (raw: unknown) => Record<string, IconMemberMetadata>;
|
|
54
57
|
/**
|
|
55
58
|
* The uds format IS this file schema — `{ [memberName]: { categories?, tags?, codepoint?,
|
|
56
|
-
* knockoutVariants? } }` —
|
|
59
|
+
* variants?, knockoutVariants? } }` —
|
|
57
60
|
* the escape hatch a consumer's own script writes. Exported (with a JSON-Schema form below) so
|
|
58
61
|
* writing that script is a validated contract rather than a guess.
|
|
59
62
|
*/
|
|
@@ -61,12 +64,15 @@ declare const iconMetadataFile: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
|
61
64
|
categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
62
65
|
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
63
66
|
codepoint: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
variants: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
64
68
|
knockoutVariants: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
65
69
|
}, z.core.$strict>>;
|
|
66
70
|
type IconMetadataFile = z.infer<typeof iconMetadataFile>;
|
|
67
71
|
/** The uds file contract as JSON Schema — what a generator stamps into `$schema`-aware tooling. */
|
|
68
72
|
declare function iconMetadataFileJsonSchema(): Record<string, unknown>;
|
|
73
|
+
/** `brand-4chan` → `IconBrand4chan`: the react package's export for a slug. */
|
|
74
|
+
declare function tablerExportName(slug: string): string;
|
|
69
75
|
/** Run the named format's adapter. The host resolved and read `raw`; this stays pure. */
|
|
70
76
|
declare function iconMetadata(format: IconMetadataFormat, raw: unknown): Record<string, IconMemberMetadata>;
|
|
71
77
|
//#endregion
|
|
72
|
-
export { ICON_METADATA_FORMATS, IconMemberMetadata, IconMetadataAdapter, IconMetadataDeclaration, IconMetadataFile, IconMetadataFormat, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat };
|
|
78
|
+
export { ICON_METADATA_FORMATS, IconMemberMetadata, IconMetadataAdapter, IconMetadataDeclaration, IconMetadataFile, IconMetadataFormat, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, tablerExportName };
|
|
@@ -14,7 +14,11 @@ import { z } from "zod";
|
|
|
14
14
|
* name). The list and the adapter table are one file so they cannot drift apart.
|
|
15
15
|
*/
|
|
16
16
|
/** The formats an icon group's `metadata.format` may declare — exactly the shipped adapters. */
|
|
17
|
-
const ICON_METADATA_FORMATS = [
|
|
17
|
+
const ICON_METADATA_FORMATS = [
|
|
18
|
+
"phosphor",
|
|
19
|
+
"uds",
|
|
20
|
+
"tabler"
|
|
21
|
+
];
|
|
18
22
|
const iconMetadataFormat = z.enum(ICON_METADATA_FORMATS);
|
|
19
23
|
/**
|
|
20
24
|
* One member's descriptive facts — the same schema `Icon.fields` registers, owned here so the
|
|
@@ -29,6 +33,9 @@ const iconMemberMetadata = z.strictObject({
|
|
|
29
33
|
tags: z.array(z.string()).optional(),
|
|
30
34
|
/** The glyph's code point in a font-backed set — what a native glyphmap reads. */
|
|
31
35
|
codepoint: z.number().optional(),
|
|
36
|
+
/** The subset of the set's `variants` this glyph ships, for a ragged set (Tabler draws `filled`
|
|
37
|
+
* for a third of its glyphs). Absent means every variant the set declares. */
|
|
38
|
+
variants: z.array(z.string().min(1)).optional(),
|
|
32
39
|
/** Variants whose glyph paints a literal white fill by design (a "knockout" meant for dark or
|
|
33
40
|
* branded surfaces) rather than `currentColor`. Such a glyph is invisible on a light surface,
|
|
34
41
|
* so pickers and catalogs preview these variants on a dark one. Rendering is untouched — the
|
|
@@ -47,7 +54,7 @@ const iconMetadataDeclaration = z.strictObject({
|
|
|
47
54
|
});
|
|
48
55
|
/**
|
|
49
56
|
* The uds format IS this file schema — `{ [memberName]: { categories?, tags?, codepoint?,
|
|
50
|
-
* knockoutVariants? } }` —
|
|
57
|
+
* variants?, knockoutVariants? } }` —
|
|
51
58
|
* the escape hatch a consumer's own script writes. Exported (with a JSON-Schema form below) so
|
|
52
59
|
* writing that script is a validated contract rather than a guess.
|
|
53
60
|
*/
|
|
@@ -95,17 +102,50 @@ const phosphor = (raw) => {
|
|
|
95
102
|
};
|
|
96
103
|
const uds = (raw) => {
|
|
97
104
|
const parsed = iconMetadataFile.safeParse(raw);
|
|
98
|
-
if (!parsed.success) throw new Error(`uds metadata source did not match the uds file contract ({ [memberName]: { categories?, tags?, codepoint?, knockoutVariants? } }) — ${describeIssues(parsed.error)}`);
|
|
105
|
+
if (!parsed.success) throw new Error(`uds metadata source did not match the uds file contract ({ [memberName]: { categories?, tags?, codepoint?, variants?, knockoutVariants? } }) — ${describeIssues(parsed.error)}`);
|
|
99
106
|
return parsed.data;
|
|
100
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* 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 and numbers, and a `styles` record whose
|
|
111
|
+
* keys are the variants the glyph draws (`outline` always, `filled` for a subset). Loose for the
|
|
112
|
+
* same reason as Phosphor's.
|
|
113
|
+
*/
|
|
114
|
+
const tablerCatalog = z.record(z.string().min(1), z.looseObject({
|
|
115
|
+
name: z.string().min(1),
|
|
116
|
+
category: z.string().optional(),
|
|
117
|
+
tags: z.array(z.union([z.string(), z.number()])).optional(),
|
|
118
|
+
styles: z.record(z.string().min(1), z.looseObject({ unicode: z.string().optional() }))
|
|
119
|
+
}));
|
|
120
|
+
/** `brand-4chan` → `IconBrand4chan`: the react package's export for a slug. */
|
|
121
|
+
function tablerExportName(slug) {
|
|
122
|
+
return `Icon${slug.split("-").map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("")}`;
|
|
123
|
+
}
|
|
124
|
+
const tabler = (raw) => {
|
|
125
|
+
const parsed = tablerCatalog.safeParse(raw);
|
|
126
|
+
if (!parsed.success) throw new Error(`tabler metadata source did not match @tabler/icons' icons.json shape — ${describeIssues(parsed.error)}`);
|
|
127
|
+
const members = {};
|
|
128
|
+
for (const [slug, entry] of Object.entries(parsed.data)) {
|
|
129
|
+
const outline = entry.styles.outline?.unicode;
|
|
130
|
+
const codepoint = outline !== void 0 && /^[0-9a-fA-F]+$/.test(outline) ? Number.parseInt(outline, 16) : void 0;
|
|
131
|
+
members[tablerExportName(slug)] = {
|
|
132
|
+
...entry.category ? { categories: [entry.category] } : {},
|
|
133
|
+
...entry.tags && entry.tags.length > 0 ? { tags: entry.tags.map(String) } : {},
|
|
134
|
+
...codepoint !== void 0 ? { codepoint } : {},
|
|
135
|
+
variants: Object.keys(entry.styles)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return members;
|
|
139
|
+
};
|
|
101
140
|
/** Exhaustive by type: a format added to the list without an adapter here fails to compile. */
|
|
102
141
|
const ADAPTERS = {
|
|
103
142
|
phosphor,
|
|
104
|
-
uds
|
|
143
|
+
uds,
|
|
144
|
+
tabler
|
|
105
145
|
};
|
|
106
146
|
/** Run the named format's adapter. The host resolved and read `raw`; this stays pure. */
|
|
107
147
|
function iconMetadata(format, raw) {
|
|
108
148
|
return ADAPTERS[format](raw);
|
|
109
149
|
}
|
|
110
150
|
//#endregion
|
|
111
|
-
export { ICON_METADATA_FORMATS, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat };
|
|
151
|
+
export { ICON_METADATA_FORMATS, iconMemberMetadata, iconMetadata, iconMetadataDeclaration, iconMetadataFile, iconMetadataFileJsonSchema, iconMetadataFormat, tablerExportName };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRef, pathOf } from "../../framework/utils/refs.js";
|
|
1
2
|
import { Icon } from "./Icon.js";
|
|
2
3
|
//#region src/entities/system/runtime-modules.ts
|
|
3
4
|
/**
|
|
@@ -20,14 +21,13 @@ function declaredRuntimeModules(config) {
|
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
for (const group of Icon.groups(config)) {
|
|
23
|
-
const
|
|
24
|
-
|
|
24
|
+
const named = group.meta.package;
|
|
25
|
+
const specifier = isRef(named) ? pathOf(named) : void 0;
|
|
26
|
+
if (specifier === void 0) continue;
|
|
25
27
|
const existing = bySpecifier.get(specifier);
|
|
26
|
-
const groupVersion = group.meta.version;
|
|
27
|
-
const version = existing?.version ?? (typeof groupVersion === "string" ? groupVersion : void 0);
|
|
28
28
|
bySpecifier.set(specifier, {
|
|
29
29
|
specifier,
|
|
30
|
-
...version ? { version } : {},
|
|
30
|
+
...existing?.version ? { version: existing.version } : {},
|
|
31
31
|
...existing?.exports ? { exports: existing.exports } : {},
|
|
32
32
|
iconLibrary: true
|
|
33
33
|
});
|