@driftime/sanity-plugin-icon 0.4.2 → 0.5.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/README.md +40 -1
- package/dist/{adapters-Bx_MyEX_.js → adapters-Dw6yeA3A.js} +2 -3
- package/dist/{adapters-Bx_MyEX_.js.map → adapters-Dw6yeA3A.js.map} +1 -1
- package/dist/{sets-kepuObH8.js → defaults-BEzCWZtH.js} +2 -39
- package/dist/defaults-BEzCWZtH.js.map +1 -0
- package/dist/index.d.ts +1 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -144
- package/dist/index.js.map +1 -1
- package/dist/loader-2g6inuO6.js +96 -0
- package/dist/loader-2g6inuO6.js.map +1 -0
- package/dist/next-loader.d.ts.map +1 -1
- package/dist/next-loader.js +4 -73
- package/dist/next-loader.js.map +1 -1
- package/dist/next.d.ts +3 -2
- package/dist/next.d.ts.map +1 -1
- package/dist/next.js +9 -8
- package/dist/next.js.map +1 -1
- package/dist/{nodes-DAzj56Xn.js → nodes-Bn7fLVZO.js} +47 -3
- package/dist/nodes-Bn7fLVZO.js.map +1 -0
- package/dist/read-worker.js +2 -2
- package/dist/render.d.ts +24 -2
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +21 -3
- package/dist/render.js.map +1 -1
- package/dist/{sets-D5_YGFll.js → sets-B5arQvrZ.js} +59 -6
- package/dist/sets-B5arQvrZ.js.map +1 -0
- package/dist/sets-DH5UbUV_.js +49 -0
- package/dist/sets-DH5UbUV_.js.map +1 -0
- package/dist/types-CmTEhJK6.js +189 -0
- package/dist/types-CmTEhJK6.js.map +1 -0
- package/dist/types-D9GjPlhU.d.ts +59 -0
- package/dist/types-D9GjPlhU.d.ts.map +1 -0
- package/dist/vite.js +3 -4
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/dist/drawing-ByrcBbWB.js +0 -50
- package/dist/drawing-ByrcBbWB.js.map +0 -1
- package/dist/nodes-DAzj56Xn.js.map +0 -1
- package/dist/registry-B0Dxiwhh.js +0 -68
- package/dist/registry-B0Dxiwhh.js.map +0 -1
- package/dist/registry-BEEpqK3z.js +0 -13
- package/dist/registry-BEEpqK3z.js.map +0 -1
- package/dist/sets-D5_YGFll.js.map +0 -1
- package/dist/sets-kepuObH8.js.map +0 -1
- package/dist/types-qlHEYDoN.d.ts +0 -20
- package/dist/types-qlHEYDoN.d.ts.map +0 -1
- package/dist/utils-COPacfAq.js +0 -48
- package/dist/utils-COPacfAq.js.map +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { c as isDefined, i as parseIconRoot, l as isRecord, r as parseIconNode } from "./nodes-Bn7fLVZO.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builds the key a set is registered under.
|
|
4
|
+
*
|
|
5
|
+
* @param library - Identifier of the library.
|
|
6
|
+
* @param style - Identifier of the style.
|
|
7
|
+
* @returns The key.
|
|
8
|
+
*/
|
|
9
|
+
function getIconSetKey(library, style) {
|
|
10
|
+
return `${library}/${style}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reads one icon of a converted set, skipping it when its data isn't usable.
|
|
14
|
+
*
|
|
15
|
+
* @param value - The value to read.
|
|
16
|
+
* @returns The icon, or undefined when the value isn't one.
|
|
17
|
+
*/
|
|
18
|
+
function parseIconSetIcon(value) {
|
|
19
|
+
if (!isRecord(value)) return;
|
|
20
|
+
let { name, keywords, node, root } = value, parsedNode = parseIconNode(node), parsedRoot = isDefined(root) ? parseIconRoot(root) : void 0;
|
|
21
|
+
if (typeof name == "string" && Array.isArray(keywords) && isDefined(parsedNode) && (!isDefined(root) || isDefined(parsedRoot))) return {
|
|
22
|
+
name,
|
|
23
|
+
keywords: keywords.filter((keyword) => typeof keyword == "string"),
|
|
24
|
+
node: parsedNode,
|
|
25
|
+
...isDefined(parsedRoot) && { root: parsedRoot }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reads a converted set, keeping only the icons whose data is usable.
|
|
30
|
+
*
|
|
31
|
+
* @param value - The value to read.
|
|
32
|
+
* @returns The set, or undefined when the value isn't one.
|
|
33
|
+
*/
|
|
34
|
+
function parseIconSet(value) {
|
|
35
|
+
if (!isRecord(value)) return;
|
|
36
|
+
let { library, style, root, icons } = value, parsedRoot = parseIconRoot(root);
|
|
37
|
+
if (typeof library == "string" && typeof style == "string" && isDefined(parsedRoot) && Array.isArray(icons)) return {
|
|
38
|
+
library,
|
|
39
|
+
style,
|
|
40
|
+
root: parsedRoot,
|
|
41
|
+
icons: icons.flatMap((icon) => {
|
|
42
|
+
let parsed = parseIconSetIcon(icon);
|
|
43
|
+
return isDefined(parsed) ? [parsed] : [];
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export { getIconSetKey as n, parseIconSet as t };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=sets-DH5UbUV_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sets-DH5UbUV_.js","names":["IconLibraryInfo","IconSetLoader","Promise","default","IconRegistry","ready","sets","Record","libraries","getIconSetKey","library","style","isDefined","isRecord","IconNode","IconRoot","parseIconNode","parseIconRoot","IconSetIcon","name","keywords","node","root","IconSet","library","style","icons","IconLibraryInfo","label","packageName","packagePrefix","styles","listed","installed","sitePackage","parseIconSetIcon","value","undefined","parsedNode","parsedRoot","Array","isArray","filter","keyword","parseIconSet","flatMap","icon","parsed"],"sources":["../src/lib/registry.ts","../src/lib/sets.ts"],"sourcesContent":["import type { IconLibraryInfo } from \"@/lib/sets\";\n\n/**\n * Loads one converted set, as a module whose default export is the set.\n *\n * @public\n */\nexport type IconSetLoader = () => Promise<{ default: unknown }>;\n\n/**\n * What the build step generates: a loader for every converted set, and every library it knows.\n *\n * @public\n */\nexport interface IconRegistry {\n /** Whether the build step generated the registry, rather than the placeholder being used. */\n ready: boolean;\n /** Loaders keyed by library and style, such as `phosphor/bold`. */\n sets: Record<string, IconSetLoader>;\n /** Libraries the build step knows, keyed by identifier. */\n libraries: Record<string, IconLibraryInfo>;\n}\n\n/**\n * Builds the key a set is registered under.\n *\n * @param library - Identifier of the library.\n * @param style - Identifier of the style.\n * @returns The key.\n */\nexport function getIconSetKey(library: string, style: string) {\n return `${library}/${style}`;\n}\n","import { isDefined, isRecord } from \"@repo/lib/utils\";\n\nimport type { IconNode, IconRoot } from \"@/lib/nodes\";\nimport { parseIconNode, parseIconRoot } from \"@/lib/nodes\";\n\n/** One icon in a converted set. */\nexport interface IconSetIcon {\n /** Name of the icon in its library. */\n name: string;\n /** Words describing the icon, from its library. */\n keywords: string[];\n /** Shapes the icon is drawn from. */\n node: IconNode;\n /** Root for this icon, or undefined when it uses the set's. */\n root?: IconRoot;\n}\n\n/** Icons of one library style, converted by the build step into the stored drawing format. */\nexport interface IconSet {\n /** Identifier of the library, such as `lucide`. */\n library: string;\n /** Identifier of the style, such as `bold`. */\n style: string;\n /** Root most icons in the set share. */\n root: IconRoot;\n /** Every icon in the set. */\n icons: IconSetIcon[];\n}\n\n/**\n * A library the build step knows how to convert, and whether the project has it installed.\n *\n * @public\n */\nexport interface IconLibraryInfo {\n /** Readable name of the library. */\n label: string;\n /** Package the library is read from, or an example of one for a family of packages. */\n packageName: string;\n /** Shared start of the package names of a family of packages, one per style, or undefined for a single package. */\n packagePrefix?: string;\n /** Styles the library offers, the first being the default. */\n styles: string[];\n /** Whether the project's `package.json` lists the package, installed or not. */\n listed: boolean;\n /** Whether the project has the package installed. */\n installed: boolean;\n /** Another package of the library the project lists, such as its React version, or undefined when there's none. */\n sitePackage?: string;\n}\n\n/**\n * Reads one icon of a converted set, skipping it when its data isn't usable.\n *\n * @param value - The value to read.\n * @returns The icon, or undefined when the value isn't one.\n */\nfunction parseIconSetIcon(value: unknown): IconSetIcon | undefined {\n if (!isRecord(value)) return undefined;\n\n const { name, keywords, node, root } = value;\n const parsedNode = parseIconNode(node);\n const parsedRoot = isDefined(root) ? parseIconRoot(root) : undefined;\n\n if (typeof name !== \"string\" || !Array.isArray(keywords) || !isDefined(parsedNode)) return undefined;\n if (isDefined(root) && !isDefined(parsedRoot)) return undefined;\n\n return {\n name,\n keywords: keywords.filter((keyword: unknown) => typeof keyword === \"string\"),\n node: parsedNode,\n ...(isDefined(parsedRoot) && { root: parsedRoot }),\n };\n}\n\n/**\n * Reads a converted set, keeping only the icons whose data is usable.\n *\n * @param value - The value to read.\n * @returns The set, or undefined when the value isn't one.\n */\nexport function parseIconSet(value: unknown): IconSet | undefined {\n if (!isRecord(value)) return undefined;\n\n const { library, style, root, icons } = value;\n const parsedRoot = parseIconRoot(root);\n\n if (typeof library !== \"string\" || typeof style !== \"string\" || !isDefined(parsedRoot) || !Array.isArray(icons)) {\n return undefined;\n }\n\n return {\n library,\n style,\n root: parsedRoot,\n icons: icons.flatMap((icon: unknown) => {\n const parsed = parseIconSetIcon(icon);\n\n return isDefined(parsed) ? [parsed] : [];\n }),\n };\n}\n"],"mappings":";;;;;;;;AA8BA,SAAgBS,cAAcC,SAAiBC,OAAe;CAC5D,OAAO,GAAGD,QAAO,GAAIC;AACvB;;;;;;;ACyBA,SAASwB,iBAAiBC,OAAyC;CACjE,IAAI,CAACvB,SAASuB,KAAK,GAAG;CAEtB,IAAM,EAAEjB,MAAMC,UAAUC,MAAMC,SAASc,OACjCE,aAAatB,cAAcK,IAAI,GAC/BkB,aAAa3B,UAAUU,IAAI,IAAIL,cAAcK,IAAI,IAAIe,KAAAA;CAE3D,IAAI,OAAOlB,QAAS,YAAaqB,MAAMC,QAAQrB,QAAQ,KAAMR,UAAU0B,UAAU,MAC7E1B,WAAUU,IAAI,KAAMV,UAAU2B,UAAU,IAE5C,OAAO;EACLpB;EACAC,UAAUA,SAASsB,QAAQC,YAAqB,OAAOA,WAAY,QAAQ;EAC3EtB,MAAMiB;EACN,GAAI1B,UAAU2B,UAAU,KAAK,EAAEjB,MAAMiB,WAAW;CAClD;AACF;;;;;;;AAQA,SAAgBK,aAAaR,OAAqC;CAChE,IAAI,CAACvB,SAASuB,KAAK,GAAG;CAEtB,IAAM,EAAEZ,SAASC,OAAOH,MAAMI,UAAUU,OAClCG,aAAatB,cAAcK,IAAI;CAErC,IAAI,OAAOE,WAAY,YAAY,OAAOC,SAAU,YAAab,UAAU2B,UAAU,KAAMC,MAAMC,QAAQf,KAAK,GAI9G,OAAO;EACLF;EACAC;EACAH,MAAMiB;EACNb,OAAOA,MAAMmB,SAASC,SAAkB;GACtC,IAAMC,SAASZ,iBAAiBW,IAAI;GAEpC,OAAOlC,UAAUmC,MAAM,IAAI,CAACA,MAAM,IAAI,CAAA;EACxC,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { c as isDefined, n as iconSvgAttributes, s as convertCase } from "./nodes-Bn7fLVZO.js";
|
|
2
|
+
import { n as getIconSetKey, t as parseIconSet } from "./sets-DH5UbUV_.js";
|
|
3
|
+
import { createElement } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { iconRegistry } from "@driftime/sanity-plugin-icon/sets";
|
|
6
|
+
/**
|
|
7
|
+
* Converts stored attributes to React props, turning a `style` attribute into the object React expects.
|
|
8
|
+
*
|
|
9
|
+
* @param attributes - The stored attributes.
|
|
10
|
+
* @returns The props.
|
|
11
|
+
*/
|
|
12
|
+
function toProps({ style, ...attributes }) {
|
|
13
|
+
if (!isDefined(style)) return attributes;
|
|
14
|
+
let declarations = style.split(";").flatMap((declaration) => {
|
|
15
|
+
let [property = "", ...value] = declaration.split(":"), name = property.trim(), joined = value.join(":").trim();
|
|
16
|
+
return !isDefined(name) || !isDefined(joined) ? [] : [[name.startsWith("--") ? name : name.replace(/^-ms-/u, "ms-").replaceAll(/-(?<letter>[a-z])/gu, (_match, letter) => letter.toUpperCase()), joined]];
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
...attributes,
|
|
20
|
+
style: Object.fromEntries(declarations)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Draws one element of a stored drawing, with its children.
|
|
25
|
+
*
|
|
26
|
+
* @param child - The element, or text inside one.
|
|
27
|
+
* @param index - Its position among its siblings.
|
|
28
|
+
* @returns The element.
|
|
29
|
+
*/
|
|
30
|
+
function renderChild(child, index) {
|
|
31
|
+
if (typeof child == "string") return child;
|
|
32
|
+
let [element, attributes, children] = child;
|
|
33
|
+
return createElement(element, {
|
|
34
|
+
...toProps(attributes),
|
|
35
|
+
key: String(index)
|
|
36
|
+
}, children?.map((nested, position) => renderChild(nested, position)));
|
|
37
|
+
}
|
|
38
|
+
function Drawing({ drawing, ...props }) {
|
|
39
|
+
if (!isDefined(drawing)) return null;
|
|
40
|
+
let root = toProps(drawing.root);
|
|
41
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
42
|
+
...iconSvgAttributes,
|
|
43
|
+
...root,
|
|
44
|
+
"aria-hidden": "true",
|
|
45
|
+
...props,
|
|
46
|
+
children: drawing.node.map((child, index) => renderChild(child, index))
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Normalises text for search, so hyphenated names and multi-word keywords match the same way.
|
|
51
|
+
*
|
|
52
|
+
* @param value - The text.
|
|
53
|
+
* @returns The normalised text.
|
|
54
|
+
*/
|
|
55
|
+
function normalizeTerms(value) {
|
|
56
|
+
return value.toLowerCase().replaceAll(/[\s-]+/gu, " ").trim();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Splits text into the parts a search matches and the parts it doesn't, matching the way search does: ignoring case,
|
|
60
|
+
* and treating spaces and hyphens alike.
|
|
61
|
+
*
|
|
62
|
+
* @param text - The text to split.
|
|
63
|
+
* @param query - The normalised search.
|
|
64
|
+
* @returns The parts in order, each with where it starts in the text and whether it matches.
|
|
65
|
+
*/
|
|
66
|
+
function splitMatches(text, query) {
|
|
67
|
+
if (!isDefined(query)) return [{
|
|
68
|
+
text,
|
|
69
|
+
start: 0,
|
|
70
|
+
match: !1
|
|
71
|
+
}];
|
|
72
|
+
let pattern = query.split(" ").map((word) => word.replaceAll(/[$()*+.?[\\\]^{|}]/gu, String.raw`\$&`)).join(String.raw`[\s-]+`), parts = text.split(RegExp(`(${pattern})`, "giu"));
|
|
73
|
+
return parts.map((part, index) => ({
|
|
74
|
+
text: part,
|
|
75
|
+
start: parts.slice(0, index).join("").length,
|
|
76
|
+
match: index % 2 == 1
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Narrows the library to the named icons, in the order given. Unknown names are skipped, so a list keeps working
|
|
81
|
+
* across library releases.
|
|
82
|
+
*
|
|
83
|
+
* @param library - Every icon in the library.
|
|
84
|
+
* @param names - The icons to offer, or undefined for all of them.
|
|
85
|
+
* @returns The icons to offer.
|
|
86
|
+
*/
|
|
87
|
+
function selectIcons(library, names) {
|
|
88
|
+
if (!isDefined(names)) return library;
|
|
89
|
+
let byName = new Map(library.map((icon) => [icon.name, icon]));
|
|
90
|
+
return [...new Set(names)].flatMap((name) => {
|
|
91
|
+
let icon = byName.get(name);
|
|
92
|
+
return isDefined(icon) ? [icon] : [];
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Lists identifiers as inline code, separated by commas.
|
|
97
|
+
*
|
|
98
|
+
* @param identifiers - The identifiers.
|
|
99
|
+
* @returns The list.
|
|
100
|
+
*/
|
|
101
|
+
function formatList(identifiers) {
|
|
102
|
+
return identifiers.map((identifier) => `\`${identifier}\``).join(", ");
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Describes why a library the project hasn't installed can't be shown, and what to add.
|
|
106
|
+
*
|
|
107
|
+
* @param label - Readable name of the library.
|
|
108
|
+
* @param packageName - Package the library is read from, or an example of one for a family of packages.
|
|
109
|
+
* @param family - Whether the library is a family of packages, one per style.
|
|
110
|
+
* @param listed - Whether the project's `package.json` lists the package.
|
|
111
|
+
* @param sitePackage - Another package of the library the project lists, or undefined when there's none.
|
|
112
|
+
* @returns The problem.
|
|
113
|
+
*/
|
|
114
|
+
function describeMissingLibrary(label, packageName, family, listed, sitePackage) {
|
|
115
|
+
return listed ? {
|
|
116
|
+
title: `${label} isn't installed yet`,
|
|
117
|
+
description: `\`${packageName}\` is in \`package.json\` but not in \`node_modules\`. Reinstall the project's dependencies.`
|
|
118
|
+
} : isDefined(sitePackage) ? {
|
|
119
|
+
title: `${label} needs \`${packageName}\``,
|
|
120
|
+
description: `The Studio reads ${label} from \`${packageName}\`, not \`${sitePackage}\`. Add it as a dev dependency.`
|
|
121
|
+
} : {
|
|
122
|
+
title: `${label} isn't installed`,
|
|
123
|
+
description: family ? `Install a ${label} style package, such as \`${packageName}\`.` : `Install \`${packageName}\` in the project.`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Loads one library style from the sets the build step converted.
|
|
128
|
+
*
|
|
129
|
+
* @param library - Identifier of the library, or undefined when none is set.
|
|
130
|
+
* @param style - Identifier of the style, or undefined for the library's default.
|
|
131
|
+
* @returns The icons, or why they can't be shown.
|
|
132
|
+
*/
|
|
133
|
+
async function readLibrary(library, style) {
|
|
134
|
+
if (!isDefined(library)) return { problem: {
|
|
135
|
+
title: "No icon library set",
|
|
136
|
+
description: "Set `library` in the icon plugin's configuration or in the field's options."
|
|
137
|
+
} };
|
|
138
|
+
if (!iconRegistry.ready) return { problem: {
|
|
139
|
+
title: "Icons aren't set up",
|
|
140
|
+
description: "Add `withIcons()` to the Studio's build configuration, then restart the Studio."
|
|
141
|
+
} };
|
|
142
|
+
let info = iconRegistry.libraries[library];
|
|
143
|
+
if (!isDefined(info)) return { problem: {
|
|
144
|
+
title: "Unknown icon library",
|
|
145
|
+
description: `There's no icon library called \`${library}\`. Use one of: ${formatList(Object.keys(iconRegistry.libraries))}.`
|
|
146
|
+
} };
|
|
147
|
+
let { label, packageName, packagePrefix, styles, listed, installed, sitePackage } = info;
|
|
148
|
+
if (!installed) return { problem: describeMissingLibrary(label, packageName, isDefined(packagePrefix), listed, sitePackage) };
|
|
149
|
+
let resolvedStyle = style ?? styles[0] ?? "", loader = iconRegistry.sets[getIconSetKey(library, resolvedStyle)];
|
|
150
|
+
if (!isDefined(loader)) return { problem: isDefined(packagePrefix) ? {
|
|
151
|
+
title: `${label} style \`${resolvedStyle}\` isn't installed`,
|
|
152
|
+
description: `Install \`${packagePrefix}${resolvedStyle}\` in the project.`
|
|
153
|
+
} : {
|
|
154
|
+
title: `Unknown ${label} style`,
|
|
155
|
+
description: `${label} has no \`${resolvedStyle}\` style. Use one of: ${formatList(styles)}.`
|
|
156
|
+
} };
|
|
157
|
+
let module = await loader(), set = parseIconSet(module.default);
|
|
158
|
+
return isDefined(set) ? { icons: set.icons.map(({ name, keywords, node, root }) => ({
|
|
159
|
+
name,
|
|
160
|
+
label: convertCase(name, "title"),
|
|
161
|
+
tags: keywords.join(", "),
|
|
162
|
+
drawing: {
|
|
163
|
+
root: root ?? set.root,
|
|
164
|
+
node
|
|
165
|
+
},
|
|
166
|
+
terms: normalizeTerms([name, ...keywords].join(" "))
|
|
167
|
+
})) } : { problem: {
|
|
168
|
+
title: `Couldn't load ${label}`,
|
|
169
|
+
description: "Restart the Studio and try again."
|
|
170
|
+
} };
|
|
171
|
+
}
|
|
172
|
+
/** Library requests shared by every field in the session, keyed by library and style, since the data never changes. */
|
|
173
|
+
const libraryRequests = /* @__PURE__ */ new Map();
|
|
174
|
+
/**
|
|
175
|
+
* Loads a library style, reusing a request already in progress.
|
|
176
|
+
*
|
|
177
|
+
* @param library - Identifier of the library, or undefined when none is set.
|
|
178
|
+
* @param style - Identifier of the style, or undefined for the library's default.
|
|
179
|
+
* @returns The icons, or why they can't be shown.
|
|
180
|
+
*/
|
|
181
|
+
async function requestLibrary(library, style) {
|
|
182
|
+
let key = getIconSetKey(library ?? "", style ?? ""), request = libraryRequests.get(key);
|
|
183
|
+
return isDefined(request) || (request = readLibrary(library, style), libraryRequests.set(key, request)), await request;
|
|
184
|
+
}
|
|
185
|
+
/** Schema type name of the icon object. */
|
|
186
|
+
const iconTypeName = "icon";
|
|
187
|
+
export { splitMatches as a, selectIcons as i, normalizeTerms as n, Drawing as o, requestLibrary as r, iconTypeName as t };
|
|
188
|
+
|
|
189
|
+
//# sourceMappingURL=types-CmTEhJK6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-CmTEhJK6.js","names":["isDefined","ComponentProps","ReactElement","createElement","IconDrawing","IconElement","iconSvgAttributes","toProps","style","attributes","Record","declarations","split","flatMap","declaration","property","value","name","trim","joined","join","key","startsWith","replace","replaceAll","_match","letter","toUpperCase","Object","fromEntries","renderChild","child","index","element","children","String","map","nested","position","DrawingProps","Omit","drawing","Drawing","props","root","node","iconRegistry","convertCase","isDefined","IconDrawing","getIconSetKey","parseIconSet","LibraryIcon","name","label","tags","drawing","terms","LibraryProblem","title","description","LibraryResult","icons","problem","normalizeTerms","value","toLowerCase","replaceAll","trim","splitMatches","text","query","start","match","pattern","split","map","word","String","raw","join","parts","RegExp","part","index","slice","length","selectIcons","library","names","byName","Map","icon","Set","flatMap","get","formatList","identifiers","identifier","describeMissingLibrary","packageName","family","listed","sitePackage","readLibrary","style","Promise","ready","info","libraries","Object","keys","packagePrefix","styles","installed","resolvedStyle","loader","sets","module","set","default","keywords","node","root","libraryRequests","requestLibrary","key","request","result","SanityIconNames","iconLibraryStyles","iconTypeName","SanityIcon","_type","library","style","name","node","IconLibraryStyles","SanityIconLibrary","SanityIconStyle","Library","SanityIconName","ListedLibraryId","NonNullable","Extract","IconLibraryId"],"sources":["../src/components/drawing.tsx","../src/lib/library.ts","../src/types.ts"],"sourcesContent":["// Consumers render this in server components, where the compiler's memo cache hook can't run.\n\"use no memo\";\n\nimport { isDefined } from \"@repo/lib/utils\";\nimport type { ComponentProps, ReactElement } from \"react\";\nimport { createElement } from \"react\";\n\nimport type { IconDrawing, IconElement } from \"@/lib/nodes\";\nimport { iconSvgAttributes } from \"@/lib/nodes\";\n\n/**\n * Converts stored attributes to React props, turning a `style` attribute into the object React expects.\n *\n * @param attributes - The stored attributes.\n * @returns The props.\n */\nfunction toProps({ style, ...attributes }: Record<string, string>) {\n if (!isDefined(style)) return attributes;\n\n const declarations = style.split(\";\").flatMap((declaration): [string, string][] => {\n const [property = \"\", ...value] = declaration.split(\":\");\n const name = property.trim();\n const joined = value.join(\":\").trim();\n if (!isDefined(name) || !isDefined(joined)) return [];\n\n const key = name.startsWith(\"--\")\n ? name\n : name\n .replace(/^-ms-/u, \"ms-\")\n .replaceAll(/-(?<letter>[a-z])/gu, (_match, letter: string) => letter.toUpperCase());\n\n return [[key, joined]];\n });\n\n return { ...attributes, style: Object.fromEntries(declarations) };\n}\n\n/**\n * Draws one element of a stored drawing, with its children.\n *\n * @param child - The element, or text inside one.\n * @param index - Its position among its siblings.\n * @returns The element.\n */\nfunction renderChild(child: IconElement | string, index: number): ReactElement | string {\n if (typeof child === \"string\") return child;\n\n const [element, attributes, children] = child;\n\n return createElement(\n element,\n { ...toProps(attributes), key: String(index) },\n children?.map((nested, position) => renderChild(nested, position)),\n );\n}\n\nexport type DrawingProps = Omit<ComponentProps<\"svg\">, \"children\"> & { drawing: IconDrawing | undefined };\n\nexport function Drawing({ drawing, ...props }: DrawingProps) {\n if (!isDefined(drawing)) return null;\n\n // Stored roots only hold checked attribute names, but their values are text, not React's literal types.\n const root = toProps(drawing.root) as ComponentProps<\"svg\">;\n\n return (\n <svg {...iconSvgAttributes} {...root} aria-hidden=\"true\" {...props}>\n {drawing.node.map((child, index) => renderChild(child, index))}\n </svg>\n );\n}\n","import { iconRegistry } from \"@driftime/sanity-plugin-icon/sets\";\nimport { convertCase, isDefined } from \"@repo/lib/utils\";\n\nimport type { IconDrawing } from \"@/lib/nodes\";\nimport { getIconSetKey } from \"@/lib/registry\";\nimport { parseIconSet } from \"@/lib/sets\";\n\n/** Icon in the library, with the terms a search matches against. */\nexport interface LibraryIcon {\n /** Name of the icon in its library. */\n name: string;\n /** Readable form of the name. */\n label: string;\n /** Keywords describing the icon, as a comma-separated list. */\n tags: string;\n /** The icon's shapes and the SVG attributes they're drawn inside. */\n drawing: IconDrawing;\n /** Name and keywords, normalised for search. */\n terms: string;\n}\n\n/** Why a library's icons can't be shown, and what to do about it, with code marked by backticks. */\nexport interface LibraryProblem {\n /** What's wrong, in a few words. */\n title: string;\n /** What to do about it. */\n description: string;\n}\n\n/** Outcome of loading a library: its icons, or why they can't be shown. */\nexport type LibraryResult =\n | { icons: LibraryIcon[]; problem?: undefined }\n | { icons?: undefined; problem: LibraryProblem };\n\n/**\n * Normalises text for search, so hyphenated names and multi-word keywords match the same way.\n *\n * @param value - The text.\n * @returns The normalised text.\n */\nexport function normalizeTerms(value: string) {\n return value\n .toLowerCase()\n .replaceAll(/[\\s-]+/gu, \" \")\n .trim();\n}\n\n/**\n * Splits text into the parts a search matches and the parts it doesn't, matching the way search does: ignoring case,\n * and treating spaces and hyphens alike.\n *\n * @param text - The text to split.\n * @param query - The normalised search.\n * @returns The parts in order, each with where it starts in the text and whether it matches.\n */\nexport function splitMatches(text: string, query: string) {\n if (!isDefined(query)) return [{ text, start: 0, match: false }];\n\n const pattern = query\n .split(\" \")\n .map((word) => word.replaceAll(/[$()*+.?[\\\\\\]^{|}]/gu, String.raw`\\$&`))\n .join(String.raw`[\\s-]+`);\n\n const parts = text.split(new RegExp(`(${pattern})`, \"giu\"));\n\n return parts.map((part, index) => ({\n text: part,\n start: parts.slice(0, index).join(\"\").length,\n match: index % 2 === 1,\n }));\n}\n\n/**\n * Narrows the library to the named icons, in the order given. Unknown names are skipped, so a list keeps working\n * across library releases.\n *\n * @param library - Every icon in the library.\n * @param names - The icons to offer, or undefined for all of them.\n * @returns The icons to offer.\n */\nexport function selectIcons(library: LibraryIcon[], names: string[] | undefined) {\n if (!isDefined(names)) return library;\n\n const byName = new Map(library.map((icon) => [icon.name, icon]));\n\n return [...new Set(names)].flatMap((name) => {\n const icon = byName.get(name);\n\n return isDefined(icon) ? [icon] : [];\n });\n}\n\n/**\n * Lists identifiers as inline code, separated by commas.\n *\n * @param identifiers - The identifiers.\n * @returns The list.\n */\nfunction formatList(identifiers: string[]) {\n return identifiers.map((identifier) => `\\`${identifier}\\``).join(\", \");\n}\n\n/**\n * Describes why a library the project hasn't installed can't be shown, and what to add.\n *\n * @param label - Readable name of the library.\n * @param packageName - Package the library is read from, or an example of one for a family of packages.\n * @param family - Whether the library is a family of packages, one per style.\n * @param listed - Whether the project's `package.json` lists the package.\n * @param sitePackage - Another package of the library the project lists, or undefined when there's none.\n * @returns The problem.\n */\nfunction describeMissingLibrary(\n label: string,\n packageName: string,\n family: boolean,\n listed: boolean,\n sitePackage: string | undefined,\n): LibraryProblem {\n if (listed) {\n return {\n title: `${label} isn't installed yet`,\n description: `\\`${packageName}\\` is in \\`package.json\\` but not in \\`node_modules\\`. Reinstall the project's dependencies.`,\n };\n }\n\n if (isDefined(sitePackage)) {\n return {\n title: `${label} needs \\`${packageName}\\``,\n description: `The Studio reads ${label} from \\`${packageName}\\`, not \\`${sitePackage}\\`. Add it as a dev dependency.`,\n };\n }\n\n return {\n title: `${label} isn't installed`,\n description: family\n ? `Install a ${label} style package, such as \\`${packageName}\\`.`\n : `Install \\`${packageName}\\` in the project.`,\n };\n}\n\n/**\n * Loads one library style from the sets the build step converted.\n *\n * @param library - Identifier of the library, or undefined when none is set.\n * @param style - Identifier of the style, or undefined for the library's default.\n * @returns The icons, or why they can't be shown.\n */\nasync function readLibrary(library: string | undefined, style: string | undefined): Promise<LibraryResult> {\n if (!isDefined(library)) {\n return {\n problem: {\n title: \"No icon library set\",\n description: \"Set `library` in the icon plugin's configuration or in the field's options.\",\n },\n };\n }\n\n if (!iconRegistry.ready) {\n return {\n problem: {\n title: \"Icons aren't set up\",\n description: \"Add `withIcons()` to the Studio's build configuration, then restart the Studio.\",\n },\n };\n }\n\n const info = iconRegistry.libraries[library];\n if (!isDefined(info)) {\n return {\n problem: {\n title: \"Unknown icon library\",\n description: `There's no icon library called \\`${library}\\`. Use one of: ${formatList(Object.keys(iconRegistry.libraries))}.`,\n },\n };\n }\n\n const { label, packageName, packagePrefix, styles, listed, installed, sitePackage } = info;\n if (!installed) {\n return { problem: describeMissingLibrary(label, packageName, isDefined(packagePrefix), listed, sitePackage) };\n }\n\n const resolvedStyle = style ?? styles[0] ?? \"\";\n const loader = iconRegistry.sets[getIconSetKey(library, resolvedStyle)];\n if (!isDefined(loader)) {\n return {\n problem: isDefined(packagePrefix)\n ? {\n title: `${label} style \\`${resolvedStyle}\\` isn't installed`,\n description: `Install \\`${packagePrefix}${resolvedStyle}\\` in the project.`,\n }\n : {\n title: `Unknown ${label} style`,\n description: `${label} has no \\`${resolvedStyle}\\` style. Use one of: ${formatList(styles)}.`,\n },\n };\n }\n\n const module = await loader();\n const set = parseIconSet(module.default);\n if (!isDefined(set)) {\n return { problem: { title: `Couldn't load ${label}`, description: \"Restart the Studio and try again.\" } };\n }\n\n return {\n icons: set.icons.map(({ name, keywords, node, root }) => ({\n name,\n label: convertCase(name, \"title\"),\n tags: keywords.join(\", \"),\n drawing: { root: root ?? set.root, node },\n terms: normalizeTerms([name, ...keywords].join(\" \")),\n })),\n };\n}\n\n/** Library requests shared by every field in the session, keyed by library and style, since the data never changes. */\nconst libraryRequests = new Map<string, Promise<LibraryResult>>();\n\n/**\n * Loads a library style, reusing a request already in progress.\n *\n * @param library - Identifier of the library, or undefined when none is set.\n * @param style - Identifier of the style, or undefined for the library's default.\n * @returns The icons, or why they can't be shown.\n */\nexport async function requestLibrary(library: string | undefined, style: string | undefined) {\n const key = getIconSetKey(library ?? \"\", style ?? \"\");\n let request = libraryRequests.get(key);\n\n if (!isDefined(request)) {\n request = readLibrary(library, style);\n libraryRequests.set(key, request);\n }\n\n const result = await request;\n\n return result;\n}\n","import type { SanityIconNames } from \"@driftime/sanity-plugin-icon/names\";\n\nimport type { iconLibraryStyles } from \"@/lib/libraries\";\n\n/** Schema type name of the icon object. */\nexport const iconTypeName = \"icon\";\n\n/**\n * Stored icon: which library it came from, its name, and the shapes it's drawn from.\n *\n * @public\n */\nexport interface SanityIcon {\n _type: typeof iconTypeName;\n /** Identifier of the library the icon came from. */\n library?: string;\n /** Identifier of the library style the icon came from. */\n style?: string;\n /** Name of the icon in its library. */\n name?: string;\n /** Shapes the icon is drawn from, saved when it's chosen. */\n node?: string;\n}\n\n/** Styles of each supported library, from the plugin's own list. */\ntype IconLibraryStyles = typeof iconLibraryStyles;\n\n/**\n * Identifier of a library the plugin supports.\n *\n * @public\n */\nexport type SanityIconLibrary = keyof IconLibraryStyles;\n\n/**\n * Styles a library offers. The project's own icon folders have one style, `default`.\n *\n * @public\n */\nexport type SanityIconStyle<Library extends string> = Library extends SanityIconLibrary\n ? IconLibraryStyles[Library][number]\n : \"default\";\n\n/**\n * Names of a library's icons, once the build step has listed the installed version's, or any name before then.\n *\n * @public\n */\nexport type SanityIconName<Library extends string> = Library extends keyof SanityIconNames\n ? SanityIconNames[Library]\n : string;\n\n/** Libraries the build step has listed, or any identifier before it has, so the project's own folders can be named. */\nexport type ListedLibraryId = [keyof SanityIconNames] extends [never]\n ? string & NonNullable<unknown>\n : Extract<keyof SanityIconNames, string>;\n\n/** Libraries a field can name: the supported ones, plus the project's own folders. */\nexport type IconLibraryId = SanityIconLibrary | ListedLibraryId;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { SanityIconNames } from "@driftime/sanity-plugin-icon/names";
|
|
2
|
+
/**
|
|
3
|
+
* Styles of each library the plugin supports, the first being the default. For a library published as a family of
|
|
4
|
+
* packages, its styles are the packages it publishes, and the installed ones are used.
|
|
5
|
+
*/
|
|
6
|
+
declare const iconLibraryStyles: {
|
|
7
|
+
readonly central: ("round-filled-radius-0-stroke-1" | "round-filled-radius-0-stroke-1.5" | "round-filled-radius-0-stroke-2" | "round-filled-radius-1-stroke-1" | "round-filled-radius-1-stroke-1.5" | "round-filled-radius-1-stroke-2" | "round-filled-radius-2-stroke-1" | "round-filled-radius-2-stroke-1.5" | "round-filled-radius-2-stroke-2" | "round-filled-radius-3-stroke-1" | "round-filled-radius-3-stroke-1.5" | "round-filled-radius-3-stroke-2" | "round-outlined-radius-0-stroke-1" | "round-outlined-radius-0-stroke-1.5" | "round-outlined-radius-0-stroke-2" | "round-outlined-radius-1-stroke-1" | "round-outlined-radius-1-stroke-1.5" | "round-outlined-radius-1-stroke-2" | "round-outlined-radius-2-stroke-1" | "round-outlined-radius-2-stroke-1.5" | "round-outlined-radius-2-stroke-2" | "round-outlined-radius-3-stroke-1" | "round-outlined-radius-3-stroke-1.5" | "round-outlined-radius-3-stroke-2" | "square-filled-radius-0-stroke-1" | "square-filled-radius-0-stroke-1.5" | "square-filled-radius-0-stroke-2" | "square-outlined-radius-0-stroke-1" | "square-outlined-radius-0-stroke-1.5" | "square-outlined-radius-0-stroke-2")[];
|
|
8
|
+
readonly heroicons: readonly ["outline", "solid", "mini", "micro"];
|
|
9
|
+
readonly hugeicons: readonly ["stroke-rounded"];
|
|
10
|
+
readonly iconoir: readonly ["regular", "solid"];
|
|
11
|
+
readonly lucide: readonly ["default"];
|
|
12
|
+
readonly nucleo: readonly ["arcade", "core-essential-fill-24", "core-essential-fill-32", "core-essential-fill-48", "core-essential-outline-24", "core-essential-outline-32", "core-essential-outline-48", "core-fill-24", "core-fill-32", "core-fill-48", "core-outline-24", "core-outline-32", "core-outline-48", "credit-cards", "flags", "glass", "isometric", "micro-bold", "micro-bold-essential", "pixel", "pixel-essential", "sharp", "sharp-essential", "social-media", "ui-essential-fill-12", "ui-essential-fill-18", "ui-essential-fill-duo-18", "ui-essential-outline-12", "ui-essential-outline-18", "ui-essential-outline-duo-18", "ui-fill-12", "ui-fill-18", "ui-fill-duo-18", "ui-outline-12", "ui-outline-18", "ui-outline-duo-18"];
|
|
13
|
+
readonly phosphor: readonly ["regular", "thin", "light", "bold", "fill", "duotone"];
|
|
14
|
+
readonly tabler: readonly ["outline", "filled"];
|
|
15
|
+
};
|
|
16
|
+
/** Schema type name of the icon object. */
|
|
17
|
+
declare const iconTypeName = "icon";
|
|
18
|
+
/**
|
|
19
|
+
* Stored icon: which library it came from, its name, and the shapes it's drawn from.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
interface SanityIcon {
|
|
24
|
+
_type: typeof iconTypeName;
|
|
25
|
+
/** Identifier of the library the icon came from. */
|
|
26
|
+
library?: string;
|
|
27
|
+
/** Identifier of the library style the icon came from. */
|
|
28
|
+
style?: string;
|
|
29
|
+
/** Name of the icon in its library. */
|
|
30
|
+
name?: string;
|
|
31
|
+
/** Shapes the icon is drawn from, saved when it's chosen. */
|
|
32
|
+
node?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Styles of each supported library, from the plugin's own list. */
|
|
35
|
+
type IconLibraryStyles = typeof iconLibraryStyles;
|
|
36
|
+
/**
|
|
37
|
+
* Identifier of a library the plugin supports.
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
type SanityIconLibrary = keyof IconLibraryStyles;
|
|
42
|
+
/**
|
|
43
|
+
* Styles a library offers. The project's own icon folders have one style, `default`.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
type SanityIconStyle<Library extends string> = Library extends SanityIconLibrary ? IconLibraryStyles[Library][number] : "default";
|
|
48
|
+
/**
|
|
49
|
+
* Names of a library's icons, once the build step has listed the installed version's, or any name before then.
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
type SanityIconName<Library extends string> = Library extends keyof SanityIconNames ? SanityIconNames[Library] : string;
|
|
54
|
+
/** Libraries the build step has listed, or any identifier before it has, so the project's own folders can be named. */
|
|
55
|
+
type ListedLibraryId = [keyof SanityIconNames] extends [never] ? string & NonNullable<unknown> : Extract<keyof SanityIconNames, string>;
|
|
56
|
+
/** Libraries a field can name: the supported ones, plus the project's own folders. */
|
|
57
|
+
type IconLibraryId = SanityIconLibrary | ListedLibraryId;
|
|
58
|
+
export { SanityIconName as a, SanityIconLibrary as i, ListedLibraryId as n, SanityIconStyle as o, SanityIcon as r, iconTypeName as s, IconLibraryId as t };
|
|
59
|
+
//# sourceMappingURL=types-D9GjPlhU.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-D9GjPlhU.d.ts","names":["SanityIconNames","iconLibraryStyles","iconTypeName","SanityIcon","IconLibraryStyles","SanityIconLibrary","SanityIconStyle","Library","SanityIconName","ListedLibraryId","NonNullable","Extract","IconLibraryId"],"sources":["../src/lib/libraries.ts","../src/types.ts"],"mappings":";;;;;cAiEa;WACX;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;cCpEWE;;;;;;UAOIC;EACf,cAAcD;;EAEd;;EAEA;;EAEA;;EAEA;;;KAIGE,2BAA2BH;;;;;;KAOpBI,0BAA0BD;;;;;;KAO1BE,gBAAgB,0BAA0BC,gBAAgBF,oBAClED,kBAAkBG;;;;;;KAQVC,eAAe,0BAA0BD,sBAAsBP,kBACvEA,gBAAgBO;;KAIRE,yBAAyBT,4CACxBU,uBACTC,cAAcX;;KAGNY,gBAAgBP,oBAAoBI"}
|
package/dist/vite.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import {
|
|
3
|
-
import { r as isRegistryModule, t as
|
|
4
|
-
import { a as writeIconNames, i as loadIconSet, n as detectLibraries, r as listRegistryDependencies, t as describeReport } from "./sets-D5_YGFll.js";
|
|
1
|
+
import { n as pluginName, t as logger } from "./defaults-BEzCWZtH.js";
|
|
2
|
+
import { c as isDefined } from "./nodes-Bn7fLVZO.js";
|
|
3
|
+
import { a as writeIconNames, i as loadIconSet, n as detectLibraries, o as createRegistryModule, r as listRegistryDependencies, s as isRegistryModule, t as describeReport } from "./sets-B5arQvrZ.js";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
/** Prefix of the module each set is loaded from, followed by its library and style. */
|
|
7
6
|
const setPrefix = `virtual:${pluginName}/set/`;
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.js","names":["path","isDefined","writeIconNames","createRegistryModule","isRegistryModule","DetectedLibrary","describeReport","detectLibraries","listRegistryDependencies","loadIconSet","logger","pluginName","SanityIconBuildOptions","custom","Record","SanityIconVitePlugin","name","config","optimizeDeps","exclude","configResolved","root","cacheDir","Promise","configureServer","server","watcher","add","paths","on","event","listener","file","moduleGraph","invalidateAll","ws","send","payload","type","buildStart","resolveId","id","load","this","addWatchFile","setPrefix","iconLibraries","options","process","cwd","undefined","libraries","folders","Object","values","map","folder","resolve","_event","some","startsWith","sep","names","Map","Set","loaded","all","flatMap","library","styles","style","set","adapter","libraryNames","get","icon","icons","files","key","libraryName","slice","length","split","find","report","info","label","JSON","stringify","withIcons","extendConfig","plugins","Config"],"sources":["../src/build/vite.ts"],"sourcesContent":["import path from \"node:path\";\n\nimport { isDefined } from \"@repo/lib/utils\";\n\nimport { writeIconNames } from \"@/build/names\";\nimport { createRegistryModule, isRegistryModule } from \"@/build/registry\";\nimport type { DetectedLibrary } from \"@/build/sets\";\nimport { describeReport, detectLibraries, listRegistryDependencies, loadIconSet } from \"@/build/sets\";\nimport { logger, pluginName } from \"@/config/defaults\";\n\n/**\n * Options for the build step that converts icon libraries for the Studio.\n *\n * @public\n */\nexport interface SanityIconBuildOptions {\n /** Folders of the project's own SVG icons, keyed by the identifier fields use, such as `{ acme: \"./icons\" }`. */\n custom?: Record<string, string>;\n}\n\n/**\n * A Vite plugin, limited to the hooks the build step uses, so the package doesn't depend on Vite's own types.\n *\n * @public\n */\nexport interface SanityIconVitePlugin {\n /** Name Vite reports the plugin under. */\n name: string;\n /**\n * Keeps the placeholder registry out of Vite's pre-bundling in development, which would fix it in place, while the\n * rest of the plugin and its dependencies are pre-bundled as usual.\n *\n * @returns The configuration to merge.\n */\n config: () => { optimizeDeps: { exclude: string[] } };\n /**\n * Reads the project folder and cache folder once Vite has resolved its configuration.\n *\n * @param config - Vite's resolved configuration.\n */\n configResolved: (config: { root: string; cacheDir: string }) => Promise<void>;\n /**\n * Watches the project's own icon folders in development, reloading the Studio when an icon is added, changed, or\n * removed.\n *\n * @param server - Vite's development server.\n */\n configureServer: (server: {\n watcher: {\n add: (paths: string[]) => void;\n on: (event: \"all\", listener: (event: string, file: string) => void) => void;\n };\n moduleGraph: { invalidateAll: () => void };\n ws: { send: (payload: { type: \"full-reload\" }) => void };\n }) => void;\n /** Lists the installed icon names in the plugin's types when a build or dev server starts. */\n buildStart: () => Promise<void>;\n /**\n * Claims the modules each set is loaded from.\n *\n * @param id - The module requested.\n * @returns The module's resolved id, or undefined when it isn't a set.\n */\n resolveId: (id: string) => string | undefined;\n /**\n * Generates the registry in place of the placeholder, and each set's module.\n *\n * @param this - Vite's plugin context, used to watch the files the registry depends on.\n * @param id - The resolved module id.\n * @returns The module's code, or undefined when it isn't the build step's.\n */\n load: (this: { addWatchFile?: (file: string) => void }, id: string) => Promise<string | undefined>;\n}\n\n/** Prefix of the module each set is loaded from, followed by its library and style. */\nconst setPrefix = `virtual:${pluginName}/set/`;\n\n/**\n * Creates the Vite plugin that converts the project's installed icon libraries when the Studio starts or builds.\n *\n * @param options - Options for the build step.\n * @returns The Vite plugin.\n * @public\n */\nexport function iconLibraries(options: SanityIconBuildOptions = {}): SanityIconVitePlugin {\n let root = process.cwd();\n let cacheDir: string | undefined = undefined;\n let libraries: DetectedLibrary[] = [];\n\n return {\n name: pluginName,\n config() {\n return { optimizeDeps: { exclude: [`${pluginName}/sets`] } };\n },\n async configResolved(config) {\n ({ root, cacheDir } = config);\n libraries = await detectLibraries(root, options.custom);\n },\n configureServer(server) {\n const folders = Object.values(options.custom ?? {}).map((folder) => path.resolve(root, folder));\n if (!isDefined(folders)) return;\n\n server.watcher.add(folders);\n server.watcher.on(\"all\", (_event, file) => {\n if (!folders.some((folder) => file.startsWith(`${folder}${path.sep}`))) return;\n\n server.moduleGraph.invalidateAll();\n server.ws.send({ type: \"full-reload\" });\n });\n },\n async buildStart() {\n const names = new Map<string, Set<string>>();\n const loaded = await Promise.all(\n libraries.flatMap((library) =>\n library.styles.map(async ({ style }) => {\n const { set } = await loadIconSet(library, style, { root, cacheDir });\n\n return { library: library.adapter.library, set };\n }),\n ),\n );\n\n for (const { library, set } of loaded) {\n const libraryNames = names.get(library) ?? new Set<string>();\n\n for (const icon of set.icons) libraryNames.add(icon.name);\n names.set(library, libraryNames);\n }\n\n await writeIconNames(names);\n },\n resolveId(id) {\n return id.startsWith(setPrefix) ? `\\0${id}` : undefined;\n },\n async load(id) {\n if (isRegistryModule(id)) {\n libraries = await detectLibraries(root, options.custom);\n\n // Vite treats watched files as imports in development, so folders are watched by the server instead.\n const { files } = listRegistryDependencies(root, libraries);\n for (const file of files) this.addWatchFile?.(file);\n\n return createRegistryModule(libraries, (key) => `${setPrefix}${key}`);\n }\n if (!id.startsWith(`\\0${setPrefix}`)) return undefined;\n\n const [libraryName, style] = id.slice(`\\0${setPrefix}`.length).split(\"/\");\n const library = libraries.find(({ adapter }) => adapter.library === libraryName);\n if (!isDefined(library) || !isDefined(style)) return undefined;\n\n const { set, report } = await loadIconSet(library, style, { root, cacheDir });\n logger.info(describeReport(library.adapter.label, style, report));\n\n return `export default JSON.parse(${JSON.stringify(JSON.stringify(set))});`;\n },\n };\n}\n\n/**\n * Adds the icon build step to a Vite configuration, for the `vite` option in `sanity.cli.ts` or a framework's own\n * Vite settings.\n *\n * @param options - Options for the build step.\n * @returns A function that extends the Vite configuration.\n * @public\n */\nexport function withIcons(options: SanityIconBuildOptions = {}) {\n return function extendConfig<Config extends { plugins?: unknown[] }>(config: Config): Config {\n return { ...config, plugins: [...(config.plugins ?? []), iconLibraries(options)] };\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"vite.js","names":["path","isDefined","writeIconNames","createRegistryModule","isRegistryModule","DetectedLibrary","describeReport","detectLibraries","listRegistryDependencies","loadIconSet","logger","pluginName","SanityIconBuildOptions","custom","Record","SanityIconVitePlugin","name","config","optimizeDeps","exclude","configResolved","root","cacheDir","Promise","configureServer","server","watcher","add","paths","on","event","listener","file","moduleGraph","invalidateAll","ws","send","payload","type","buildStart","resolveId","id","load","this","addWatchFile","setPrefix","iconLibraries","options","process","cwd","undefined","libraries","folders","Object","values","map","folder","resolve","_event","some","startsWith","sep","names","Map","Set","loaded","all","flatMap","library","styles","style","set","adapter","libraryNames","get","icon","icons","files","key","libraryName","slice","length","split","find","report","info","label","JSON","stringify","withIcons","extendConfig","plugins","Config"],"sources":["../src/build/vite.ts"],"sourcesContent":["import path from \"node:path\";\n\nimport { isDefined } from \"@repo/lib/utils\";\n\nimport { writeIconNames } from \"@/build/names\";\nimport { createRegistryModule, isRegistryModule } from \"@/build/registry\";\nimport type { DetectedLibrary } from \"@/build/sets\";\nimport { describeReport, detectLibraries, listRegistryDependencies, loadIconSet } from \"@/build/sets\";\nimport { logger, pluginName } from \"@/config/defaults\";\n\n/**\n * Options for the build step that converts icon libraries for the Studio.\n *\n * @public\n */\nexport interface SanityIconBuildOptions {\n /** Folders of the project's own SVG icons, keyed by the identifier fields use, such as `{ acme: \"./icons\" }`. */\n custom?: Record<string, string>;\n}\n\n/**\n * A Vite plugin, limited to the hooks the build step uses, so the package doesn't depend on Vite's own types.\n *\n * @public\n */\nexport interface SanityIconVitePlugin {\n /** Name Vite reports the plugin under. */\n name: string;\n /**\n * Keeps the placeholder registry out of Vite's pre-bundling in development, which would fix it in place, while the\n * rest of the plugin and its dependencies are pre-bundled as usual.\n *\n * @returns The configuration to merge.\n */\n config: () => { optimizeDeps: { exclude: string[] } };\n /**\n * Reads the project folder and cache folder once Vite has resolved its configuration.\n *\n * @param config - Vite's resolved configuration.\n */\n configResolved: (config: { root: string; cacheDir: string }) => Promise<void>;\n /**\n * Watches the project's own icon folders in development, reloading the Studio when an icon is added, changed, or\n * removed.\n *\n * @param server - Vite's development server.\n */\n configureServer: (server: {\n watcher: {\n add: (paths: string[]) => void;\n on: (event: \"all\", listener: (event: string, file: string) => void) => void;\n };\n moduleGraph: { invalidateAll: () => void };\n ws: { send: (payload: { type: \"full-reload\" }) => void };\n }) => void;\n /** Lists the installed icon names in the plugin's types when a build or dev server starts. */\n buildStart: () => Promise<void>;\n /**\n * Claims the modules each set is loaded from.\n *\n * @param id - The module requested.\n * @returns The module's resolved id, or undefined when it isn't a set.\n */\n resolveId: (id: string) => string | undefined;\n /**\n * Generates the registry in place of the placeholder, and each set's module.\n *\n * @param this - Vite's plugin context, used to watch the files the registry depends on.\n * @param id - The resolved module id.\n * @returns The module's code, or undefined when it isn't the build step's.\n */\n load: (this: { addWatchFile?: (file: string) => void }, id: string) => Promise<string | undefined>;\n}\n\n/** Prefix of the module each set is loaded from, followed by its library and style. */\nconst setPrefix = `virtual:${pluginName}/set/`;\n\n/**\n * Creates the Vite plugin that converts the project's installed icon libraries when the Studio starts or builds.\n *\n * @param options - Options for the build step.\n * @returns The Vite plugin.\n * @public\n */\nexport function iconLibraries(options: SanityIconBuildOptions = {}): SanityIconVitePlugin {\n let root = process.cwd();\n let cacheDir: string | undefined = undefined;\n let libraries: DetectedLibrary[] = [];\n\n return {\n name: pluginName,\n config() {\n return { optimizeDeps: { exclude: [`${pluginName}/sets`] } };\n },\n async configResolved(config) {\n ({ root, cacheDir } = config);\n libraries = await detectLibraries(root, options.custom);\n },\n configureServer(server) {\n const folders = Object.values(options.custom ?? {}).map((folder) => path.resolve(root, folder));\n if (!isDefined(folders)) return;\n\n server.watcher.add(folders);\n server.watcher.on(\"all\", (_event, file) => {\n if (!folders.some((folder) => file.startsWith(`${folder}${path.sep}`))) return;\n\n server.moduleGraph.invalidateAll();\n server.ws.send({ type: \"full-reload\" });\n });\n },\n async buildStart() {\n const names = new Map<string, Set<string>>();\n const loaded = await Promise.all(\n libraries.flatMap((library) =>\n library.styles.map(async ({ style }) => {\n const { set } = await loadIconSet(library, style, { root, cacheDir });\n\n return { library: library.adapter.library, set };\n }),\n ),\n );\n\n for (const { library, set } of loaded) {\n const libraryNames = names.get(library) ?? new Set<string>();\n\n for (const icon of set.icons) libraryNames.add(icon.name);\n names.set(library, libraryNames);\n }\n\n await writeIconNames(names);\n },\n resolveId(id) {\n return id.startsWith(setPrefix) ? `\\0${id}` : undefined;\n },\n async load(id) {\n if (isRegistryModule(id)) {\n libraries = await detectLibraries(root, options.custom);\n\n // Vite treats watched files as imports in development, so folders are watched by the server instead.\n const { files } = listRegistryDependencies(root, libraries);\n for (const file of files) this.addWatchFile?.(file);\n\n return createRegistryModule(libraries, (key) => `${setPrefix}${key}`);\n }\n if (!id.startsWith(`\\0${setPrefix}`)) return undefined;\n\n const [libraryName, style] = id.slice(`\\0${setPrefix}`.length).split(\"/\");\n const library = libraries.find(({ adapter }) => adapter.library === libraryName);\n if (!isDefined(library) || !isDefined(style)) return undefined;\n\n const { set, report } = await loadIconSet(library, style, { root, cacheDir });\n logger.info(describeReport(library.adapter.label, style, report));\n\n return `export default JSON.parse(${JSON.stringify(JSON.stringify(set))});`;\n },\n };\n}\n\n/**\n * Adds the icon build step to a Vite configuration, for the `vite` option in `sanity.cli.ts` or a framework's own\n * Vite settings.\n *\n * @param options - Options for the build step.\n * @returns A function that extends the Vite configuration.\n * @public\n */\nexport function withIcons(options: SanityIconBuildOptions = {}) {\n return function extendConfig<Config extends { plugins?: unknown[] }>(config: Config): Config {\n return { ...config, plugins: [...(config.plugins ?? []), iconLibraries(options)] };\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/drawing-ByrcBbWB.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { n as isDefined } from "./utils-COPacfAq.js";
|
|
2
|
-
import { n as iconSvgAttributes } from "./nodes-DAzj56Xn.js";
|
|
3
|
-
import { createElement } from "react";
|
|
4
|
-
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
/**
|
|
6
|
-
* Converts stored attributes to React props, turning a `style` attribute into the object React expects.
|
|
7
|
-
*
|
|
8
|
-
* @param attributes - The stored attributes.
|
|
9
|
-
* @returns The props.
|
|
10
|
-
*/
|
|
11
|
-
function toProps({ style, ...attributes }) {
|
|
12
|
-
if (!isDefined(style)) return attributes;
|
|
13
|
-
let declarations = style.split(";").flatMap((declaration) => {
|
|
14
|
-
let [property = "", ...value] = declaration.split(":"), name = property.trim(), joined = value.join(":").trim();
|
|
15
|
-
return !isDefined(name) || !isDefined(joined) ? [] : [[name.startsWith("--") ? name : name.replace(/^-ms-/u, "ms-").replaceAll(/-(?<letter>[a-z])/gu, (_match, letter) => letter.toUpperCase()), joined]];
|
|
16
|
-
});
|
|
17
|
-
return {
|
|
18
|
-
...attributes,
|
|
19
|
-
style: Object.fromEntries(declarations)
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Draws one element of a stored drawing, with its children.
|
|
24
|
-
*
|
|
25
|
-
* @param child - The element, or text inside one.
|
|
26
|
-
* @param index - Its position among its siblings.
|
|
27
|
-
* @returns The element.
|
|
28
|
-
*/
|
|
29
|
-
function renderChild(child, index) {
|
|
30
|
-
if (typeof child == "string") return child;
|
|
31
|
-
let [element, attributes, children] = child;
|
|
32
|
-
return createElement(element, {
|
|
33
|
-
...toProps(attributes),
|
|
34
|
-
key: String(index)
|
|
35
|
-
}, children?.map((nested, position) => renderChild(nested, position)));
|
|
36
|
-
}
|
|
37
|
-
function Drawing({ drawing, ...props }) {
|
|
38
|
-
if (!isDefined(drawing)) return null;
|
|
39
|
-
let root = toProps(drawing.root);
|
|
40
|
-
return /* @__PURE__ */ jsx("svg", {
|
|
41
|
-
...iconSvgAttributes,
|
|
42
|
-
...root,
|
|
43
|
-
"aria-hidden": "true",
|
|
44
|
-
...props,
|
|
45
|
-
children: drawing.node.map((child, index) => renderChild(child, index))
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
export { Drawing as t };
|
|
49
|
-
|
|
50
|
-
//# sourceMappingURL=drawing-ByrcBbWB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drawing-ByrcBbWB.js","names":["isDefined","ComponentProps","ReactElement","createElement","IconDrawing","IconElement","iconSvgAttributes","toProps","style","attributes","Record","declarations","split","flatMap","declaration","property","value","name","trim","joined","join","key","startsWith","replace","replaceAll","_match","letter","toUpperCase","Object","fromEntries","renderChild","child","index","element","children","String","map","nested","position","DrawingProps","Omit","drawing","Drawing","props","root","node"],"sources":["../src/components/drawing.tsx"],"sourcesContent":["// Consumers render this in server components, where the compiler's memo cache hook can't run.\n\"use no memo\";\n\nimport { isDefined } from \"@repo/lib/utils\";\nimport type { ComponentProps, ReactElement } from \"react\";\nimport { createElement } from \"react\";\n\nimport type { IconDrawing, IconElement } from \"@/lib/nodes\";\nimport { iconSvgAttributes } from \"@/lib/nodes\";\n\n/**\n * Converts stored attributes to React props, turning a `style` attribute into the object React expects.\n *\n * @param attributes - The stored attributes.\n * @returns The props.\n */\nfunction toProps({ style, ...attributes }: Record<string, string>) {\n if (!isDefined(style)) return attributes;\n\n const declarations = style.split(\";\").flatMap((declaration): [string, string][] => {\n const [property = \"\", ...value] = declaration.split(\":\");\n const name = property.trim();\n const joined = value.join(\":\").trim();\n if (!isDefined(name) || !isDefined(joined)) return [];\n\n const key = name.startsWith(\"--\")\n ? name\n : name\n .replace(/^-ms-/u, \"ms-\")\n .replaceAll(/-(?<letter>[a-z])/gu, (_match, letter: string) => letter.toUpperCase());\n\n return [[key, joined]];\n });\n\n return { ...attributes, style: Object.fromEntries(declarations) };\n}\n\n/**\n * Draws one element of a stored drawing, with its children.\n *\n * @param child - The element, or text inside one.\n * @param index - Its position among its siblings.\n * @returns The element.\n */\nfunction renderChild(child: IconElement | string, index: number): ReactElement | string {\n if (typeof child === \"string\") return child;\n\n const [element, attributes, children] = child;\n\n return createElement(\n element,\n { ...toProps(attributes), key: String(index) },\n children?.map((nested, position) => renderChild(nested, position)),\n );\n}\n\nexport type DrawingProps = Omit<ComponentProps<\"svg\">, \"children\"> & { drawing: IconDrawing | undefined };\n\nexport function Drawing({ drawing, ...props }: DrawingProps) {\n if (!isDefined(drawing)) return null;\n\n // Stored roots only hold checked attribute names, but their values are text, not React's literal types.\n const root = toProps(drawing.root) as ComponentProps<\"svg\">;\n\n return (\n <svg {...iconSvgAttributes} {...root} aria-hidden=\"true\" {...props}>\n {drawing.node.map((child, index) => renderChild(child, index))}\n </svg>\n );\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAASO,QAAQ,EAAEC,OAAO,GAAGC,cAAsC;CACjE,IAAI,CAACT,UAAUQ,KAAK,GAAG,OAAOC;CAE9B,IAAME,eAAeH,MAAMI,MAAM,GAAG,CAAC,CAACC,SAASC,gBAAoC;EACjF,IAAM,CAACC,WAAW,IAAI,GAAGC,SAASF,YAAYF,MAAM,GAAG,GACjDK,OAAOF,SAASG,KAAK,GACrBC,SAASH,MAAMI,KAAK,GAAG,CAAC,CAACF,KAAK;EASpC,OARI,CAAClB,UAAUiB,IAAI,KAAK,CAACjB,UAAUmB,MAAM,IAAU,CAAA,IAQ5C,CAAC,CANIF,KAAKK,WAAW,IAAI,IAC5BL,OACAA,KACGM,QAAQ,UAAU,KAAK,CAAC,CACxBC,WAAW,wBAAwBC,QAAQC,WAAmBA,OAAOC,YAAY,CAAC,GAE3ER,MAAM,CAAC;CACvB,CAAC;CAED,OAAO;EAAE,GAAGV;EAAYD,OAAOoB,OAAOC,YAAYlB,YAAY;CAAE;AAClE;;;;;;;;AASA,SAASmB,YAAYC,OAA6BC,OAAsC;CACtF,IAAI,OAAOD,SAAU,UAAU,OAAOA;CAEtC,IAAM,CAACE,SAASxB,YAAYyB,YAAYH;CAExC,OAAO5B,cACL8B,SACA;EAAE,GAAG1B,QAAQE,UAAU;EAAGY,KAAKc,OAAOH,KAAK;CAAE,GAC7CE,UAAUE,KAAKC,QAAQC,aAAaR,YAAYO,QAAQC,QAAQ,CAAC,CACnE;AACF;AAIA,SAAgBI,QAAQ,EAAED,SAAS,GAAGE,SAAuB;CAC3D,IAAI,CAAC3C,UAAUyC,OAAO,GAAG,OAAO;CAGhC,IAAMG,OAAOrC,QAAQkC,QAAQG,IAAI;CAEjC,OACE,oBAAC,OAAD;EAAK,GAAItC;EAAmB,GAAIsC;EAAM,eAAY;EAAO,GAAID;EAC1DF,UAAAA,QAAQI,KAAKT,KAAKL,OAAOC,UAAUF,YAAYC,OAAOC,KAAK,CAAC;CAC1D,CAAA;AAET"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nodes-DAzj56Xn.js","names":["isDefined","isRecord","stegaClean","IconElement","element","attributes","Record","children","IconNode","IconRoot","IconDrawing","root","node","iconElements","ReadonlySet","Set","linkAttributes","urlPattern","iconSvgAttributes","xmlns","width","height","const","isAttributes","value","Object","values","every","attribute","isIconElement","Array","isArray","length","parts","name","child","findAttributeProblem","entries","test","has","startsWith","includes","references","matchAll","outside","some","groups","trim","replace","split","undefined","findNodeProblem","problem","findDrawingProblem","parseIconNode","parseIconRoot","parseJson","JSON","parse","resolveIconDrawing","cleaned","stored","drawing","serializeIconDrawing","stringify","parts","\"reference\"","\"root\"","\"node\""],"sources":["../src/lib/nodes.ts"],"sourcesContent":["import { isDefined, isRecord } from \"@repo/lib/utils\";\nimport { stegaClean } from \"@sanity/client/stega\";\n\n/** One element in a drawing: its name, its attributes, and any children, which may include text. */\nexport type IconElement = [element: string, attributes: Record<string, string>, children?: (IconElement | string)[]];\n\n/** An icon's drawing, stored as a tree of elements rather than a component. */\nexport type IconNode = IconElement[];\n\n/** Attributes for the SVG around a drawing's elements. */\nexport type IconRoot = Record<string, string>;\n\n/** An icon's elements together with the SVG attributes they're drawn inside. */\nexport interface IconDrawing {\n /** Attributes for the SVG around the elements. */\n root: IconRoot;\n /** Elements the icon is drawn from. */\n node: IconNode;\n}\n\n/**\n * SVG elements a drawing may contain: everything that draws, paints, clips, masks, or filters. Anything that runs\n * code, embeds other content, links away, loads a file, animates, or styles the page around it is left out.\n */\nconst iconElements: ReadonlySet<string> = new Set([\n \"circle\",\n \"clipPath\",\n \"defs\",\n \"ellipse\",\n \"feBlend\",\n \"feColorMatrix\",\n \"feComponentTransfer\",\n \"feComposite\",\n \"feConvolveMatrix\",\n \"feDiffuseLighting\",\n \"feDisplacementMap\",\n \"feDistantLight\",\n \"feDropShadow\",\n \"feFlood\",\n \"feFuncA\",\n \"feFuncB\",\n \"feFuncG\",\n \"feFuncR\",\n \"feGaussianBlur\",\n \"feMerge\",\n \"feMergeNode\",\n \"feMorphology\",\n \"feOffset\",\n \"fePointLight\",\n \"feSpecularLighting\",\n \"feSpotLight\",\n \"feTile\",\n \"feTurbulence\",\n \"filter\",\n \"g\",\n \"line\",\n \"linearGradient\",\n \"marker\",\n \"mask\",\n \"path\",\n \"pattern\",\n \"polygon\",\n \"polyline\",\n \"radialGradient\",\n \"rect\",\n \"stop\",\n \"symbol\",\n \"text\",\n \"textPath\",\n \"tspan\",\n \"use\",\n]);\n\n/** Attributes that point at another element by URL, which must point inside the drawing. */\nconst linkAttributes = new Set([\"href\", \"xlinkHref\"]);\n\n/** A reference to another element in an attribute value, such as `url(#fade)`. */\nconst urlPattern = /url\\((?<reference>[^)]*)\\)/gu;\n\n/** Attributes every drawing's SVG carries, whichever library it came from. */\nexport const iconSvgAttributes = { xmlns: \"http://www.w3.org/2000/svg\", width: 24, height: 24 } as const;\n\n/**\n * Checks whether a value is a set of attributes, each with a text value.\n *\n * @param value - The value to check.\n * @returns True if the value is a set of attributes.\n */\nfunction isAttributes(value: unknown): value is Record<string, string> {\n return isRecord(value) && Object.values(value).every((attribute) => typeof attribute === \"string\");\n}\n\n/**\n * Checks whether a value is an element in a drawing, with text attributes and valid children.\n *\n * @param value - The value to check.\n * @returns True if the value is an element.\n */\nfunction isIconElement(value: unknown): value is IconElement {\n if (!Array.isArray(value) || value.length < 2 || value.length > 3) return false;\n\n const parts: unknown[] = value;\n const [name, attributes, children] = parts;\n if (typeof name !== \"string\" || !isAttributes(attributes)) return false;\n\n return (\n !isDefined(children) ||\n (Array.isArray(children) && children.every((child) => typeof child === \"string\" || isIconElement(child)))\n );\n}\n\n/**\n * Finds why an element's attributes can't be drawn safely.\n *\n * @param attributes - The attributes.\n * @returns The problem, or undefined when the attributes are safe.\n */\nfunction findAttributeProblem(attributes: Record<string, string>) {\n for (const [name, value] of Object.entries(attributes)) {\n if (/^on/iu.test(name)) return `has an event handler (\\`${name}\\`)`;\n if (!/^[a-zA-Z][a-zA-Z0-9]*$/u.test(name)) return `has an unknown attribute (\\`${name}\\`)`;\n if (/javascript:/iu.test(value)) return \"runs a script\";\n\n if (linkAttributes.has(name) && !value.startsWith(\"#\")) return \"links outside the icon\";\n\n if (value.includes(\"url(\")) {\n const references = [...value.matchAll(urlPattern)];\n const outside = references.some(\n ({ groups }) => !(groups?.[\"reference\"]?.trim().replace(/^[\"']/u, \"\").startsWith(\"#\") ?? false),\n );\n\n if (outside || value.split(\"url(\").length - 1 !== references.length) {\n return \"refers to something outside the icon\";\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Finds why part of a drawing can't be drawn safely.\n *\n * @param node - The elements to check.\n * @returns The problem, or undefined when every element is safe.\n */\nfunction findNodeProblem(node: (IconElement | string)[]): string | undefined {\n for (const child of node) {\n if (typeof child === \"string\") continue;\n\n const [name, attributes, children] = child;\n if (!iconElements.has(name)) return `uses the \\`<${name}>\\` element`;\n\n const problem = findAttributeProblem(attributes) ?? (isDefined(children) ? findNodeProblem(children) : undefined);\n if (isDefined(problem)) return problem;\n }\n\n return undefined;\n}\n\n/**\n * Finds why a drawing can't be drawn safely: an element or attribute that could run code, load something, or reach\n * outside the icon. The same check guards the build step's output and every stored value before it's drawn.\n *\n * @param drawing - The drawing to check.\n * @returns The problem, or undefined when the drawing is safe.\n */\nexport function findDrawingProblem({ root, node }: IconDrawing) {\n if (!isDefined(node)) return \"draws nothing\";\n\n return findAttributeProblem(root) ?? findNodeProblem(node);\n}\n\n/**\n * Reads a drawing's elements from an already parsed value, such as a converted set.\n *\n * @param value - The value to read.\n * @returns The elements, or undefined when the value isn't a list of them.\n */\nexport function parseIconNode(value: unknown) {\n return Array.isArray(value) && value.every((element) => isIconElement(element)) ? value : undefined;\n}\n\n/**\n * Reads an SVG root from an already parsed value.\n *\n * @param value - The value to read.\n * @returns The root, or undefined when the value isn't one.\n */\nexport function parseIconRoot(value: unknown) {\n return isAttributes(value) ? value : undefined;\n}\n\n/**\n * Parses stored JSON.\n *\n * @param value - The stored text.\n * @returns The parsed value, or undefined when the text isn't JSON.\n */\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Reads a drawing back from its stored form, removing stega characters first.\n *\n * @param value - The stored drawing.\n * @returns The drawing, or undefined when nothing readable and safe was stored.\n */\nexport function resolveIconDrawing(value: string | undefined): IconDrawing | undefined {\n const cleaned = stegaClean(value);\n if (!isDefined(cleaned)) return undefined;\n\n const stored = parseJson(cleaned);\n if (!isRecord(stored)) return undefined;\n\n const root = parseIconRoot(stored[\"root\"]);\n const node = parseIconNode(stored[\"node\"]);\n if (!isDefined(root) || !isDefined(node)) return undefined;\n\n const drawing = { root, node };\n\n return isDefined(findDrawingProblem(drawing)) ? undefined : drawing;\n}\n\n/**\n * Converts a drawing to its stored form.\n *\n * @param drawing - The drawing.\n * @returns The drawing as a string.\n */\nexport function serializeIconDrawing(drawing: IconDrawing) {\n return JSON.stringify({ root: drawing.root, node: drawing.node });\n}\n"],"mappings":"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"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { n as isDefined } from "./utils-COPacfAq.js";
|
|
2
|
-
import { t as getIconSetKey } from "./registry-BEEpqK3z.js";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { realpathSync } from "node:fs";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
/**
|
|
7
|
-
* Resolves symbolic links in a path, so a package linked into `node_modules` matches its real location.
|
|
8
|
-
*
|
|
9
|
-
* @param file - The path.
|
|
10
|
-
* @returns The real path, or the path unchanged when it doesn't exist.
|
|
11
|
-
*/
|
|
12
|
-
function resolveRealPath(file) {
|
|
13
|
-
try {
|
|
14
|
-
return realpathSync(file);
|
|
15
|
-
} catch {
|
|
16
|
-
return file;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Path of the placeholder registry module the Studio imports, which the build step replaces. The build step's own
|
|
21
|
-
* code is published next to it, so the path is found from this file's location.
|
|
22
|
-
*/
|
|
23
|
-
const registryModulePath = resolveRealPath(fileURLToPath(new URL("sets.js", import.meta.url)));
|
|
24
|
-
/**
|
|
25
|
-
* Checks whether a module the bundler is loading is the placeholder registry.
|
|
26
|
-
*
|
|
27
|
-
* @param id - The module's path, possibly followed by a query.
|
|
28
|
-
* @returns Whether it's the placeholder.
|
|
29
|
-
*/
|
|
30
|
-
function isRegistryModule(id) {
|
|
31
|
-
let [file] = id.split("?");
|
|
32
|
-
return isDefined(file) && resolveRealPath(file) === registryModulePath;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Works out the folder the Next.js build step writes converted sets to, inside the project's `node_modules`.
|
|
36
|
-
*
|
|
37
|
-
* @param root - The project's folder.
|
|
38
|
-
* @returns The folder's path.
|
|
39
|
-
*/
|
|
40
|
-
function getSetsFolder(root) {
|
|
41
|
-
return path.join(root, "node_modules", ".cache", "driftime-icon", "sets");
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Writes the module that replaces the placeholder registry, with a loader for each installed library style, so each
|
|
45
|
-
* set is only downloaded when a picker for it opens.
|
|
46
|
-
*
|
|
47
|
-
* @param libraries - Every library the build step knows.
|
|
48
|
-
* @param importFor - The specifier the bundler imports a set from, given its key.
|
|
49
|
-
* @returns The module's code.
|
|
50
|
-
*/
|
|
51
|
-
function createRegistryModule(libraries, importFor) {
|
|
52
|
-
let loaders = libraries.flatMap(({ adapter, styles }) => styles.map(({ style }) => {
|
|
53
|
-
let key = getIconSetKey(adapter.library, style);
|
|
54
|
-
return `${JSON.stringify(key)}: () => import(${JSON.stringify(importFor(key))})`;
|
|
55
|
-
})), info = Object.fromEntries(libraries.map(({ adapter, styles, listed, sitePackage }) => [adapter.library, {
|
|
56
|
-
label: adapter.label,
|
|
57
|
-
packageName: adapter.packageName ?? adapter.packageExample ?? adapter.library,
|
|
58
|
-
...isDefined(adapter.packagePrefix) && { packagePrefix: adapter.packagePrefix },
|
|
59
|
-
styles: isDefined(styles) ? styles.map(({ style }) => style) : adapter.styles,
|
|
60
|
-
listed,
|
|
61
|
-
installed: isDefined(styles),
|
|
62
|
-
...isDefined(sitePackage) && { sitePackage }
|
|
63
|
-
}]));
|
|
64
|
-
return [`const sets = {\n ${loaders.join(",\n ")}\n};`, `export const iconRegistry = { ready: true, sets, libraries: ${JSON.stringify(info)} };`].join("\n");
|
|
65
|
-
}
|
|
66
|
-
export { registryModulePath as i, getSetsFolder as n, isRegistryModule as r, createRegistryModule as t };
|
|
67
|
-
|
|
68
|
-
//# sourceMappingURL=registry-B0Dxiwhh.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-B0Dxiwhh.js","names":["realpathSync","path","fileURLToPath","isDefined","DetectedLibrary","getIconSetKey","IconLibraryInfo","resolveRealPath","file","registryModulePath","URL","import","meta","url","isRegistryModule","id","split","getSetsFolder","root","join","createRegistryModule","libraries","importFor","key","loaders","flatMap","adapter","styles","map","style","library","JSON","stringify","info","Record","Object","fromEntries","listed","sitePackage","label","packageName","packageExample","packagePrefix","installed"],"sources":["../src/build/registry.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { isDefined } from \"@repo/lib/utils\";\n\nimport type { DetectedLibrary } from \"@/build/sets\";\nimport { getIconSetKey } from \"@/lib/registry\";\nimport type { IconLibraryInfo } from \"@/lib/sets\";\n\n/**\n * Resolves symbolic links in a path, so a package linked into `node_modules` matches its real location.\n *\n * @param file - The path.\n * @returns The real path, or the path unchanged when it doesn't exist.\n */\nfunction resolveRealPath(file: string) {\n try {\n return realpathSync(file);\n } catch {\n return file;\n }\n}\n\n/**\n * Path of the placeholder registry module the Studio imports, which the build step replaces. The build step's own\n * code is published next to it, so the path is found from this file's location.\n */\nexport const registryModulePath = resolveRealPath(fileURLToPath(new URL(\"sets.js\", import.meta.url)));\n\n/**\n * Checks whether a module the bundler is loading is the placeholder registry.\n *\n * @param id - The module's path, possibly followed by a query.\n * @returns Whether it's the placeholder.\n */\nexport function isRegistryModule(id: string) {\n const [file] = id.split(\"?\");\n\n return isDefined(file) && resolveRealPath(file) === registryModulePath;\n}\n\n/**\n * Works out the folder the Next.js build step writes converted sets to, inside the project's `node_modules`.\n *\n * @param root - The project's folder.\n * @returns The folder's path.\n */\nexport function getSetsFolder(root: string) {\n return path.join(root, \"node_modules\", \".cache\", \"driftime-icon\", \"sets\");\n}\n\n/**\n * Writes the module that replaces the placeholder registry, with a loader for each installed library style, so each\n * set is only downloaded when a picker for it opens.\n *\n * @param libraries - Every library the build step knows.\n * @param importFor - The specifier the bundler imports a set from, given its key.\n * @returns The module's code.\n */\nexport function createRegistryModule(libraries: DetectedLibrary[], importFor: (key: string) => string) {\n const loaders = libraries.flatMap(({ adapter, styles }) =>\n styles.map(({ style }) => {\n const key = getIconSetKey(adapter.library, style);\n\n return `${JSON.stringify(key)}: () => import(${JSON.stringify(importFor(key))})`;\n }),\n );\n\n const info: Record<string, IconLibraryInfo> = Object.fromEntries(\n libraries.map(({ adapter, styles, listed, sitePackage }) => [\n adapter.library,\n {\n label: adapter.label,\n packageName: adapter.packageName ?? adapter.packageExample ?? adapter.library,\n ...(isDefined(adapter.packagePrefix) && { packagePrefix: adapter.packagePrefix }),\n styles: isDefined(styles) ? styles.map(({ style }) => style) : adapter.styles,\n listed,\n installed: isDefined(styles),\n ...(isDefined(sitePackage) && { sitePackage }),\n },\n ]),\n );\n\n return [\n `const sets = {\\n ${loaders.join(\",\\n \")}\\n};`,\n `export const iconRegistry = { ready: true, sets, libraries: ${JSON.stringify(info)} };`,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAASO,gBAAgBC,MAAc;CACrC,IAAI;EACF,OAAOR,aAAaQ,IAAI;CAC1B,QAAQ;EACN,OAAOA;CACT;AACF;;;;;AAMA,MAAaC,qBAAqBF,gBAAgBL,cAAc,IAAIQ,IAAI,WAAWC,YAAYE,GAAG,CAAC,CAAC;;;;;;;AAQpG,SAAgBC,iBAAiBC,IAAY;CAC3C,IAAM,CAACP,QAAQO,GAAGC,MAAM,GAAG;CAE3B,OAAOb,UAAUK,IAAI,KAAKD,gBAAgBC,IAAI,MAAMC;AACtD;;;;;;;AAQA,SAAgBQ,cAAcC,MAAc;CAC1C,OAAOjB,KAAKkB,KAAKD,MAAM,gBAAgB,UAAU,iBAAiB,MAAM;AAC1E;;;;;;;;;AAUA,SAAgBE,qBAAqBC,WAA8BC,WAAoC;CACrG,IAAME,UAAUH,UAAUI,SAAS,EAAEC,SAASC,aAC5CA,OAAOC,KAAK,EAAEC,YAAY;EACxB,IAAMN,MAAMlB,cAAcqB,QAAQI,SAASD,KAAK;EAEhD,OAAO,GAAGE,KAAKC,UAAUT,GAAG,EAAC,iBAAkBQ,KAAKC,UAAUV,UAAUC,GAAG,CAAC,EAAC;CAC/E,CAAC,CACH,GAEMU,OAAwCE,OAAOC,YACnDf,UAAUO,KAAK,EAAEF,SAASC,QAAQU,QAAQC,kBAAkB,CAC1DZ,QAAQI,SACR;EACES,OAAOb,QAAQa;EACfC,aAAad,QAAQc,eAAed,QAAQe,kBAAkBf,QAAQI;EACtE,GAAI3B,UAAUuB,QAAQgB,aAAa,KAAK,EAAEA,eAAehB,QAAQgB,cAAc;EAC/Ef,QAAQxB,UAAUwB,MAAM,IAAIA,OAAOC,KAAK,EAAEC,YAAYA,KAAK,IAAIH,QAAQC;EACvEU;EACAM,WAAWxC,UAAUwB,MAAM;EAC3B,GAAIxB,UAAUmC,WAAW,KAAK,EAAEA,YAAY;CAC9C,CAAC,CACF,CACH;CAEA,OAAO,CACL,qBAAqBd,QAAQL,KAAK,OAAO,EAAC,OAC1C,+DAA+DY,KAAKC,UAAUC,IAAI,EAAC,IAAK,CACzF,CAACd,KAAK,IAAI;AACb"}
|