@driftime/sanity-plugin-icon 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +253 -61
  2. package/dist/adapters-Bx_MyEX_.js +633 -0
  3. package/dist/adapters-Bx_MyEX_.js.map +1 -0
  4. package/dist/drawing-ByrcBbWB.js +50 -0
  5. package/dist/drawing-ByrcBbWB.js.map +1 -0
  6. package/dist/index.d.ts +84 -32
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +545 -323
  9. package/dist/index.js.map +1 -1
  10. package/dist/names.d.ts +8 -0
  11. package/dist/names.d.ts.map +1 -0
  12. package/dist/names.js +0 -0
  13. package/dist/next-loader.d.ts +64 -0
  14. package/dist/next-loader.d.ts.map +1 -0
  15. package/dist/next-loader.js +103 -0
  16. package/dist/next-loader.js.map +1 -0
  17. package/dist/next.d.ts +43 -0
  18. package/dist/next.d.ts.map +1 -0
  19. package/dist/next.js +52 -0
  20. package/dist/next.js.map +1 -0
  21. package/dist/nodes-DAzj56Xn.js +139 -0
  22. package/dist/nodes-DAzj56Xn.js.map +1 -0
  23. package/dist/read-worker.d.ts +1 -0
  24. package/dist/read-worker.js +23 -0
  25. package/dist/read-worker.js.map +1 -0
  26. package/dist/registry-B0Dxiwhh.js +68 -0
  27. package/dist/registry-B0Dxiwhh.js.map +1 -0
  28. package/dist/registry-BEEpqK3z.js +13 -0
  29. package/dist/registry-BEEpqK3z.js.map +1 -0
  30. package/dist/render.d.ts +4 -5
  31. package/dist/render.d.ts.map +1 -1
  32. package/dist/render.js +5 -5
  33. package/dist/render.js.map +1 -1
  34. package/dist/sets-D5_YGFll.js +258 -0
  35. package/dist/sets-D5_YGFll.js.map +1 -0
  36. package/dist/sets-kepuObH8.js +90 -0
  37. package/dist/sets-kepuObH8.js.map +1 -0
  38. package/dist/sets.d.ts +50 -0
  39. package/dist/sets.d.ts.map +1 -0
  40. package/dist/sets.js +14 -0
  41. package/dist/sets.js.map +1 -0
  42. package/dist/types-qlHEYDoN.d.ts +20 -0
  43. package/dist/types-qlHEYDoN.d.ts.map +1 -0
  44. package/dist/utils-COPacfAq.js +48 -0
  45. package/dist/utils-COPacfAq.js.map +1 -0
  46. package/dist/vite-ifICG8y9.d.ts +98 -0
  47. package/dist/vite-ifICG8y9.d.ts.map +1 -0
  48. package/dist/vite.d.ts +2 -0
  49. package/dist/vite.js +88 -0
  50. package/dist/vite.js.map +1 -0
  51. package/package.json +42 -5
  52. package/dist/drawing-BThiR2bN.js +0 -129
  53. package/dist/drawing-BThiR2bN.js.map +0 -1
  54. package/dist/types-_D2jGm25.d.ts +0 -16
  55. package/dist/types-_D2jGm25.d.ts.map +0 -1
@@ -0,0 +1,633 @@
1
+ import { n as isDefined, r as isRecord, t as convertCase } from "./utils-COPacfAq.js";
2
+ import { t as findDrawingProblem } from "./nodes-DAzj56Xn.js";
3
+ import path from "node:path";
4
+ import { readFile, readdir } from "node:fs/promises";
5
+ import { pathToFileURL } from "node:url";
6
+ import { createRequire } from "node:module";
7
+ import { createHash } from "node:crypto";
8
+ import { optimize } from "svgo";
9
+ /** Attributes of the outer SVG that size or label it rather than draw it, since the renderer sets its own. */
10
+ const rootOnlyAttributes = /* @__PURE__ */ new Set([
11
+ "class",
12
+ "focusable",
13
+ "height",
14
+ "role",
15
+ "version",
16
+ "width"
17
+ ]);
18
+ /**
19
+ * Converts an SVG attribute name to its React form, such as `stroke-width` to `strokeWidth` and `xlink:href` to
20
+ * `xlinkHref`.
21
+ *
22
+ * @param name - The attribute name.
23
+ * @returns The React name.
24
+ */
25
+ function toReactName(name) {
26
+ return name.replaceAll(/[-:](?<character>[a-z])/gu, (_match, character) => character.toUpperCase());
27
+ }
28
+ /**
29
+ * Converts attributes to React naming, leaving out namespaces, classes, and data and accessibility attributes, which
30
+ * don't draw anything.
31
+ *
32
+ * @param attributes - The attributes.
33
+ * @param omitted - Further attributes to leave out.
34
+ * @returns The converted attributes.
35
+ */
36
+ function readAttributes(attributes, omitted = /* @__PURE__ */ new Set(["class"])) {
37
+ return Object.fromEntries(Object.entries(attributes).flatMap(([name, value]) => /^(?:xmlns|data-|aria-)/u.test(name) || omitted.has(name) ? [] : [[toReactName(name), value]]));
38
+ }
39
+ /**
40
+ * Closes a `url(` left open at the end of each attribute value, which is how browsers read it.
41
+ *
42
+ * @param element - The element whose attributes to close.
43
+ */
44
+ function closeOpenUrls(element) {
45
+ for (let [name, value] of Object.entries(element.attributes)) /url\([^)]*$/u.test(value) && (element.attributes[name] = `${value})`);
46
+ }
47
+ /**
48
+ * Converts SVGO's parsed children into stored elements, keeping text and dropping comments.
49
+ *
50
+ * @param children - The parsed children.
51
+ * @returns The elements and text.
52
+ */
53
+ function readChildren(children) {
54
+ return children.flatMap((child) => {
55
+ if (child.type === "text") return isDefined(child.value.trim()) ? [child.value] : [];
56
+ if (child.type !== "element") return [];
57
+ let nested = readChildren(child.children), attributes = readAttributes(child.attributes);
58
+ return [isDefined(nested) ? [
59
+ child.name,
60
+ attributes,
61
+ nested
62
+ ] : [child.name, attributes]];
63
+ });
64
+ }
65
+ /**
66
+ * Reads SVGO's parsed document into a drawing, from its outer `svg` element.
67
+ *
68
+ * @param tree - The parsed document.
69
+ * @returns The drawing, or undefined when the document has no `svg` element.
70
+ */
71
+ function readSvgElement(tree) {
72
+ let element = tree.children.find((child) => child.type === "element" && child.name === "svg");
73
+ if (!isDefined(element)) return;
74
+ let width = element.attributes.width?.replace(/px$/u, "") ?? "24", height = element.attributes.height?.replace(/px$/u, "") ?? width, attributes = readAttributes(element.attributes, rootOnlyAttributes);
75
+ return {
76
+ root: {
77
+ ...attributes,
78
+ viewBox: attributes.viewBox ?? `0 0 ${width} ${height}`
79
+ },
80
+ node: readChildren(element.children).filter((child) => typeof child != "string")
81
+ };
82
+ }
83
+ /**
84
+ * Cleans and minifies an icon with SVGO, then reads the result into a drawing. Paths, numbers, and transforms are kept
85
+ * exactly as drawn, since rounding or merging them changes how some icons look, and every identifier gets a prefix
86
+ * unique to the icon, so two icons on one page can't clash.
87
+ *
88
+ * @param svg - The icon's SVG markup.
89
+ * @returns The drawing, or undefined when the markup has no SVG.
90
+ * @throws When the markup can't be parsed.
91
+ */
92
+ function readDrawing(svg) {
93
+ let result = {}, declared = svg.includes("xlink:") && !svg.includes("xmlns:xlink") ? svg.replace("<svg", "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"") : svg;
94
+ return optimize(declared, {
95
+ multipass: !0,
96
+ plugins: [
97
+ {
98
+ name: "closeOpenUrls",
99
+ fn: () => ({ element: { enter: closeOpenUrls } })
100
+ },
101
+ {
102
+ name: "preset-default",
103
+ params: { overrides: {
104
+ cleanupNumericValues: !1,
105
+ convertPathData: !1,
106
+ convertTransform: !1,
107
+ inlineStyles: { onlyMatchedOnce: !1 },
108
+ mergePaths: !1
109
+ } }
110
+ },
111
+ "removeScripts",
112
+ "removeTitle",
113
+ {
114
+ name: "prefixIds",
115
+ params: { prefix: `i${createHash("sha256").update(svg).digest("hex").slice(0, 8)}` }
116
+ },
117
+ {
118
+ name: "read",
119
+ fn: () => ({ root: { enter(tree) {
120
+ result.drawing = readSvgElement(tree);
121
+ } } })
122
+ }
123
+ ]
124
+ }), result.drawing;
125
+ }
126
+ /**
127
+ * Reads an icon's markup into a drawing, or says why it can't be read.
128
+ *
129
+ * @param svg - The icon's SVG markup.
130
+ * @returns The drawing, or why there isn't one.
131
+ */
132
+ function parseDrawing(svg) {
133
+ try {
134
+ return readDrawing(svg) ?? "has no SVG";
135
+ } catch {
136
+ return "isn't valid SVG";
137
+ }
138
+ }
139
+ /**
140
+ * Converts one icon into a stored drawing, the same way whichever library it came from.
141
+ *
142
+ * @param source - The icon as read from its library.
143
+ * @returns The converted icon, or why it couldn't be converted.
144
+ */
145
+ function convertIcon(source) {
146
+ let drawing = parseDrawing(source.svg);
147
+ if (typeof drawing == "string") return { problem: drawing };
148
+ let problem = findDrawingProblem(drawing);
149
+ if (isDefined(problem)) return { problem };
150
+ let nameWords = new Set(source.name.split("-")), keywords = [...new Set(source.keywords.map((keyword) => keyword.trim().toLowerCase()))].filter((keyword) => isDefined(keyword) && !nameWords.has(keyword));
151
+ return { icon: {
152
+ name: source.name,
153
+ keywords,
154
+ node: drawing.node,
155
+ root: drawing.root
156
+ } };
157
+ }
158
+ /** Root of a 24-unit stroke icon with rounded ends, shared by Lucide and Tabler's outline style. */
159
+ const roundStrokeRoot = {
160
+ viewBox: "0 0 24 24",
161
+ fill: "none",
162
+ stroke: "currentColor",
163
+ "stroke-width": "2",
164
+ "stroke-linecap": "round",
165
+ "stroke-linejoin": "round"
166
+ };
167
+ /**
168
+ * Converts a PascalCase export name to the kebab-case name libraries use on their websites, splitting before numbers
169
+ * too, so `Home01` becomes `home-01`.
170
+ *
171
+ * @param name - The export name.
172
+ * @returns The kebab-case name.
173
+ */
174
+ function toKebabName(name) {
175
+ return name.replaceAll(/(?<upper>[A-Z])(?<next>[A-Z][a-z])/gu, "$<upper>-$<next>").replaceAll(/(?<lower>[a-z0-9])(?<upper>[A-Z])/gu, "$<lower>-$<upper>").replaceAll(/(?<letter>[a-zA-Z])(?<digit>[0-9])/gu, "$<letter>-$<digit>").toLowerCase();
176
+ }
177
+ /**
178
+ * Checks whether a module is React, with its element factory.
179
+ *
180
+ * @param value - The module.
181
+ * @returns True if the module is React.
182
+ */
183
+ function isReact(value) {
184
+ return isRecord(value) && typeof value.createElement == "function";
185
+ }
186
+ /**
187
+ * Checks whether a module is React's server renderer.
188
+ *
189
+ * @param value - The module.
190
+ * @returns True if the module is the server renderer.
191
+ */
192
+ function isServerRenderer(value) {
193
+ return isRecord(value) && typeof value.renderToStaticMarkup == "function";
194
+ }
195
+ /**
196
+ * Checks whether a value can be rendered as a React element: a tag name, a component, or a wrapped component such as
197
+ * one made by `memo`.
198
+ *
199
+ * @param value - The value.
200
+ * @returns True if the value is an element type.
201
+ */
202
+ function isElementType(value) {
203
+ return typeof value == "string" || typeof value == "function" || isRecord(value);
204
+ }
205
+ /**
206
+ * Loads the project's React and its server renderer, so markup is written the way the project itself would write it.
207
+ *
208
+ * @param root - The project folder.
209
+ * @returns React's element factory and a function that renders an element to markup, or undefined when the project
210
+ * has no React.
211
+ */
212
+ function loadRenderer(root) {
213
+ let react = requireFromProject(root, "react"), server = requireFromProject(root, "react-dom/server");
214
+ if (isReact(react) && isServerRenderer(server)) return {
215
+ createElement: react.createElement,
216
+ render: (type, props = {}) => server.renderToStaticMarkup(react.createElement(type, props))
217
+ };
218
+ }
219
+ /**
220
+ * Converts attributes to React props, so React writes each name the way SVG spells it.
221
+ *
222
+ * @param attributes - The attributes, in SVG or React naming.
223
+ * @returns The props.
224
+ */
225
+ function toProps(attributes) {
226
+ return Object.fromEntries(Object.entries(attributes).flatMap(([name, value]) => name === "key" ? [] : [[toReactName(name), String(value)]]));
227
+ }
228
+ /**
229
+ * Writes a list of `[element, attributes]` pairs, the format several libraries ship, as SVG markup. React writes the
230
+ * attributes, so names in either SVG or React form come out right.
231
+ *
232
+ * @param root - The project folder.
233
+ * @param attributes - Attributes of the SVG around the elements.
234
+ * @param value - The list.
235
+ * @returns The markup, or undefined when the value isn't a list of pairs.
236
+ */
237
+ function writeElementPairs(root, attributes, value) {
238
+ let renderer = loadRenderer(root);
239
+ if (!isDefined(renderer) || !Array.isArray(value)) return;
240
+ let { createElement: create, render } = renderer, elements = value.flatMap((pair, index) => Array.isArray(pair) && typeof pair[0] == "string" && isRecord(pair[1]) ? [create(pair[0], {
241
+ ...toProps(pair[1]),
242
+ key: String(index)
243
+ })] : []);
244
+ if (elements.length === value.length) return render("svg", {
245
+ xmlns: "http://www.w3.org/2000/svg",
246
+ ...toProps(attributes),
247
+ children: elements
248
+ });
249
+ }
250
+ /**
251
+ * Reads SVG files from a folder into icons.
252
+ *
253
+ * @param folder - The folder.
254
+ * @param files - The file names to read.
255
+ * @param describe - Gives each file's icon name and keywords.
256
+ * @returns The icons, in the order given.
257
+ */
258
+ async function readSvgIcons(folder, files, describe) {
259
+ return await Promise.all(files.map(async (file) => ({
260
+ ...describe(file),
261
+ svg: await readFile(path.join(folder, file), "utf8")
262
+ })));
263
+ }
264
+ /**
265
+ * Lists the SVG files in a folder.
266
+ *
267
+ * @param directory - The folder.
268
+ * @returns The file names, sorted.
269
+ */
270
+ async function listSvgFiles(directory) {
271
+ return (await readdir(directory)).filter((file) => file.endsWith(".svg")).toSorted();
272
+ }
273
+ /**
274
+ * Imports a JavaScript module from inside an installed package, by path, since some packages don't allow importing
275
+ * the file by name.
276
+ *
277
+ * @param directory - The package folder.
278
+ * @param file - The module's path within the package.
279
+ * @returns The module's exports.
280
+ */
281
+ async function importPackageFile(directory, file) {
282
+ let loaded = await import(pathToFileURL(path.join(directory, file)).href);
283
+ return isRecord(loaded) ? loaded : {};
284
+ }
285
+ /**
286
+ * Loads a package the way the project itself resolves it, so rendering uses the project's own copy of React.
287
+ *
288
+ * @param root - The project folder.
289
+ * @param name - The package name.
290
+ * @returns The package's exports.
291
+ */
292
+ function requireFromProject(root, name) {
293
+ return createRequire(path.join(root, "package.json"))(name);
294
+ }
295
+ /**
296
+ * Lists the plugin's own published code files.
297
+ *
298
+ * @returns The files' paths, sorted.
299
+ */
300
+ async function listPluginFiles() {
301
+ return (await readdir(import.meta.dirname)).filter((file) => file.endsWith(".js")).toSorted().map((file) => path.join(import.meta.dirname, file));
302
+ }
303
+ /**
304
+ * Hashes the plugin's own published code, so anything built from an older version is replaced. It uses the contents
305
+ * rather than modification times, because packages installed from npm all carry the same fixed date.
306
+ *
307
+ * @returns The hash.
308
+ */
309
+ async function readPluginBuild() {
310
+ let files = await listPluginFiles(), contents = await Promise.all(files.map(async (file) => ({
311
+ file,
312
+ content: await readFile(file)
313
+ }))), hash = createHash("sha256");
314
+ for (let { file, content } of contents) hash.update(path.basename(file)).update(content);
315
+ return hash.digest("hex").slice(0, 16);
316
+ }
317
+ /**
318
+ * Reads and parses a JSON file.
319
+ *
320
+ * @param file - Path to the file.
321
+ * @returns The parsed contents, or undefined when the file is missing or isn't JSON.
322
+ */
323
+ async function readJson(file) {
324
+ try {
325
+ return JSON.parse(await readFile(file, "utf8"));
326
+ } catch {
327
+ return;
328
+ }
329
+ }
330
+ /**
331
+ * Lists a folder and every folder above it, nearest first.
332
+ *
333
+ * @param directory - The folder to start from.
334
+ * @returns The folders.
335
+ */
336
+ function listAncestors(directory) {
337
+ let parent = path.dirname(directory);
338
+ return parent === directory ? [directory] : [directory, ...listAncestors(parent)];
339
+ }
340
+ /**
341
+ * Finds an installed package by walking up from the project folder through each `node_modules`, the way Node does.
342
+ * Its `package.json` is read directly, because some icon packages don't allow importing it.
343
+ *
344
+ * @param root - The project folder.
345
+ * @param name - The package name.
346
+ * @returns The package, or undefined when it isn't installed.
347
+ */
348
+ async function findPackage(root, name) {
349
+ let candidates = await Promise.all(listAncestors(path.resolve(root)).map(async (folder) => {
350
+ let directory = path.join(folder, "node_modules", name);
351
+ return {
352
+ directory,
353
+ manifest: await readJson(path.join(directory, "package.json"))
354
+ };
355
+ }));
356
+ for (let { directory, manifest } of candidates) if (isRecord(manifest) && typeof manifest.version == "string") return {
357
+ name: typeof manifest.name == "string" ? manifest.name : name,
358
+ directory,
359
+ version: manifest.version
360
+ };
361
+ }
362
+ /**
363
+ * Lists the packages a project declares, from its dependencies, dev dependencies, and peer dependencies.
364
+ *
365
+ * @param root - The project folder.
366
+ * @returns The declared package names.
367
+ */
368
+ async function readDeclaredPackages(root) {
369
+ let manifest = await readJson(path.join(root, "package.json"));
370
+ if (!isRecord(manifest)) return /* @__PURE__ */ new Set();
371
+ let groups = [
372
+ manifest.dependencies,
373
+ manifest.devDependencies,
374
+ manifest.peerDependencies
375
+ ];
376
+ return new Set(groups.flatMap((group) => isRecord(group) ? Object.keys(group) : []).filter((name) => isDefined(name)));
377
+ }
378
+ /**
379
+ * Creates an adapter for a folder of the project's own SVG files. Each file becomes an icon named after the file, and an
380
+ * optional `keywords.json` in the folder lists each icon's keywords by name.
381
+ *
382
+ * @param library - Identifier of the set.
383
+ * @param folder - The folder, relative to the project.
384
+ * @returns The adapter.
385
+ */
386
+ function createCustomAdapter(library, folder) {
387
+ return {
388
+ library,
389
+ label: convertCase(library, "title"),
390
+ packageName: void 0,
391
+ styles: ["default"],
392
+ async read({ root }) {
393
+ let directory = path.resolve(root, folder), [files, keywords] = await Promise.all([listSvgFiles(directory), readJson(path.join(directory, "keywords.json"))]);
394
+ return readSvgIcons(directory, files, (file) => {
395
+ let name = convertCase(file.slice(0, -4), "kebab"), listed = isRecord(keywords) ? keywords[name] : void 0;
396
+ return {
397
+ name,
398
+ keywords: Array.isArray(listed) ? listed.map(String) : []
399
+ };
400
+ });
401
+ }
402
+ };
403
+ }
404
+ /**
405
+ * Central, read by rendering the React components of its licensed style packages. Each installed
406
+ * `@central-icons-react/` package is a style, named after the rest of its name, so several can be used at once. Each
407
+ * icon is drawn in Central's raw mode, since its default mode draws through a mask.
408
+ */
409
+ const centralAdapter = {
410
+ library: "central",
411
+ label: "Central Icon System",
412
+ packageName: void 0,
413
+ packagePrefix: "@central-icons-react/",
414
+ packageExample: "@central-icons-react/round-outlined-radius-2-stroke-1.5",
415
+ styles: [],
416
+ async read({ directory, root }) {
417
+ let renderer = loadRenderer(root);
418
+ if (!isDefined(renderer)) return [];
419
+ let [exports, index] = await Promise.all([importPackageFile(directory, "index.mjs"), readJson(path.join(directory, "icons-index.json"))]), aliases = isRecord(index) && isRecord(index.iconAliases) ? index.iconAliases : {};
420
+ return Object.entries(exports).flatMap(([exportName, component]) => {
421
+ if (!exportName.startsWith("Icon") || exportName.endsWith("Default") || !isElementType(component)) return [];
422
+ let svg = renderer.render(component, { mode: "raw" }), listed = aliases[exportName], keywords = typeof listed == "string" ? listed.split(",").map((keyword) => keyword.trim()) : [];
423
+ return [{
424
+ name: toKebabName(exportName.slice(4)),
425
+ keywords,
426
+ svg
427
+ }];
428
+ });
429
+ }
430
+ }, centralFills = ["outlined", "filled"], centralRadii = [
431
+ "0",
432
+ "1",
433
+ "2",
434
+ "3"
435
+ ], centralStrokes = [
436
+ "1",
437
+ "1.5",
438
+ "2"
439
+ ], iconLibraryStyles = {
440
+ central: [...centralFills.flatMap((fill) => centralRadii.flatMap((radius) => centralStrokes.map((stroke) => `round-${fill}-radius-${radius}-stroke-${stroke}`))), ...centralFills.flatMap((fill) => centralStrokes.map((stroke) => `square-${fill}-radius-0-stroke-${stroke}`))],
441
+ heroicons: [
442
+ "outline",
443
+ "solid",
444
+ "mini",
445
+ "micro"
446
+ ],
447
+ hugeicons: ["stroke-rounded"],
448
+ iconoir: ["regular", "solid"],
449
+ lucide: ["default"],
450
+ nucleo: /* @__PURE__ */ "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".split("."),
451
+ phosphor: [
452
+ "regular",
453
+ "thin",
454
+ "light",
455
+ "bold",
456
+ "fill",
457
+ "duotone"
458
+ ],
459
+ tabler: ["outline", "filled"]
460
+ }, styleFolders = {
461
+ outline: "24/outline",
462
+ solid: "24/solid",
463
+ mini: "20/solid",
464
+ micro: "16/solid"
465
+ }, heroiconsAdapter = {
466
+ library: "heroicons",
467
+ label: "Heroicons",
468
+ packageName: "heroicons",
469
+ packagePattern: /^(?:heroicons|@heroicons\/.+)$/u,
470
+ styles: [...iconLibraryStyles.heroicons],
471
+ async read({ directory, style }) {
472
+ let folder = path.join(directory, styleFolders[style] ?? "24/outline");
473
+ return readSvgIcons(folder, await listSvgFiles(folder), (file) => ({
474
+ name: file.slice(0, -4),
475
+ keywords: []
476
+ }));
477
+ }
478
+ }, exportSuffixes = /(?:FreeIcons|Icon)$/u, hugeiconsAdapter = {
479
+ library: "hugeicons",
480
+ label: "Hugeicons",
481
+ packageName: "@hugeicons/core-free-icons",
482
+ packagePattern: /^@hugeicons\//u,
483
+ styles: [...iconLibraryStyles.hugeicons],
484
+ async read({ directory, root }) {
485
+ let exports = await importPackageFile(directory, "dist/esm/index.js"), namesByIcon = /* @__PURE__ */ new Map();
486
+ for (let [exportName, value] of Object.entries(exports)) namesByIcon.set(value, [...namesByIcon.get(value) ?? [], exportName]);
487
+ return [...namesByIcon].flatMap(([value, exportNames]) => {
488
+ let svg = writeElementPairs(root, {
489
+ viewBox: "0 0 24 24",
490
+ fill: "none"
491
+ }, value), [primary] = exportNames.filter((exportName) => exportName.endsWith("Icon")).toSorted();
492
+ return !isDefined(svg) || !isDefined(primary) ? [] : [{
493
+ name: toKebabName(primary.replace(exportSuffixes, "")),
494
+ keywords: [],
495
+ svg
496
+ }];
497
+ });
498
+ }
499
+ }, iconoirAdapter = {
500
+ library: "iconoir",
501
+ label: "Iconoir",
502
+ packageName: "iconoir",
503
+ packagePattern: /^iconoir(?:-.+)?$/u,
504
+ styles: [...iconLibraryStyles.iconoir],
505
+ async read({ directory, style }) {
506
+ let folder = path.join(directory, "icons", style);
507
+ return readSvgIcons(folder, await listSvgFiles(folder), (file) => ({
508
+ name: file.slice(0, -4),
509
+ keywords: []
510
+ }));
511
+ }
512
+ }, lucideAdapter = {
513
+ library: "lucide",
514
+ label: "Lucide",
515
+ packageName: "lucide-static",
516
+ packagePattern: /^(?:lucide(?:-.+)?|@lucide\/.+)$/u,
517
+ styles: [...iconLibraryStyles.lucide],
518
+ async read({ directory, root }) {
519
+ let [nodes, tags] = await Promise.all([readJson(path.join(directory, "icon-nodes.json")), readJson(path.join(directory, "tags.json"))]);
520
+ return isRecord(nodes) ? Object.entries(nodes).flatMap(([name, value]) => {
521
+ let svg = writeElementPairs(root, roundStrokeRoot, value);
522
+ return isDefined(svg) ? [{
523
+ name,
524
+ keywords: isRecord(tags) && Array.isArray(tags[name]) ? tags[name].map(String) : [],
525
+ svg
526
+ }] : [];
527
+ }) : [];
528
+ }
529
+ };
530
+ /**
531
+ * Finds the style suffix every export name in a Nucleo package ends with, such as `Outline18`, so it can be removed to
532
+ * get each icon's own name.
533
+ *
534
+ * @param names - The export names.
535
+ * @returns The shared suffix, starting at a capital letter, or an empty string when there's none.
536
+ */
537
+ function findStyleSuffix(names) {
538
+ let [first, ...rest] = names;
539
+ if (!isDefined(first)) return "";
540
+ let length = 0;
541
+ for (; length < first.length && rest.every((name) => name.at(-1 - length) === first.at(-1 - length));) length += 1;
542
+ let shared = first.slice(first.length - length), start = shared.search(/[A-Z]/u);
543
+ return start === -1 ? "" : shared.slice(start);
544
+ }
545
+ /**
546
+ * Nucleo, read by rendering the React components of its licensed packages. Each installed `nucleo-` package is a
547
+ * style, named after the rest of its name, such as `ui-outline-18`. It has no keywords.
548
+ */
549
+ const nucleoAdapter = {
550
+ library: "nucleo",
551
+ label: "Nucleo",
552
+ packageName: void 0,
553
+ packagePrefix: "nucleo-",
554
+ packageExample: "nucleo-ui-outline-18",
555
+ styles: [],
556
+ async read({ directory, root }) {
557
+ let renderer = loadRenderer(root);
558
+ if (!isDefined(renderer)) return [];
559
+ let exports = await importPackageFile(directory, "dist/index.js"), components = Object.entries(exports).flatMap(([exportName, component]) => exportName.startsWith("Icon") && exportName !== "Icon" && isElementType(component) ? [[exportName, component]] : []), suffix = findStyleSuffix(components.map(([exportName]) => exportName));
560
+ return components.flatMap(([exportName, component]) => {
561
+ let svg = renderer.render(component);
562
+ return [{
563
+ name: toKebabName(exportName.slice(4, exportName.length - suffix.length)),
564
+ keywords: [],
565
+ svg
566
+ }];
567
+ });
568
+ }
569
+ };
570
+ /**
571
+ * Reads Phosphor's keywords from the icon list `@phosphor-icons/core` exports.
572
+ *
573
+ * @param directory - The package folder.
574
+ * @returns Keywords keyed by icon name.
575
+ */
576
+ async function readPhosphorKeywords(directory) {
577
+ let { icons } = await importPackageFile(directory, "dist/index.mjs");
578
+ return Array.isArray(icons) ? new Map(icons.flatMap((icon) => isRecord(icon) && typeof icon.name == "string" && Array.isArray(icon.tags) ? [[icon.name, icon.tags.map(String)]] : [])) : /* @__PURE__ */ new Map();
579
+ }
580
+ /** Every library the build step knows how to read from its package. */
581
+ const iconAdapters = [
582
+ centralAdapter,
583
+ heroiconsAdapter,
584
+ hugeiconsAdapter,
585
+ iconoirAdapter,
586
+ lucideAdapter,
587
+ nucleoAdapter,
588
+ {
589
+ library: "phosphor",
590
+ label: "Phosphor Icons",
591
+ packageName: "@phosphor-icons/core",
592
+ packagePattern: /^@phosphor-icons\//u,
593
+ styles: [...iconLibraryStyles.phosphor],
594
+ async read({ directory, style }) {
595
+ let folder = path.join(directory, "assets", style), [files, keywords] = await Promise.all([listSvgFiles(folder), readPhosphorKeywords(directory)]), suffix = style === "regular" ? ".svg" : `-${style}.svg`;
596
+ return readSvgIcons(folder, files.filter((file) => file.endsWith(suffix)), (file) => {
597
+ let name = file.slice(0, -suffix.length);
598
+ return {
599
+ name,
600
+ keywords: keywords.get(name) ?? []
601
+ };
602
+ });
603
+ }
604
+ },
605
+ {
606
+ library: "tabler",
607
+ label: "Tabler Icons",
608
+ packageName: "@tabler/icons",
609
+ packagePattern: /^@tabler\/icons(?:-.+)?$/u,
610
+ styles: [...iconLibraryStyles.tabler],
611
+ async read({ directory, style, root }) {
612
+ let [nodes, details] = await Promise.all([readJson(path.join(directory, `tabler-nodes-${style}.json`)), readJson(path.join(directory, "icons.json"))]);
613
+ if (!isRecord(nodes)) return [];
614
+ let attributes = style === "filled" ? {
615
+ viewBox: "0 0 24 24",
616
+ fill: "currentColor"
617
+ } : roundStrokeRoot;
618
+ return Object.entries(nodes).flatMap(([name, value]) => {
619
+ let svg = writeElementPairs(root, attributes, value);
620
+ if (!isDefined(svg)) return [];
621
+ let detail = isRecord(details) ? details[name] : void 0;
622
+ return [{
623
+ name,
624
+ keywords: isRecord(detail) && Array.isArray(detail.tags) ? detail.tags.map(String) : [],
625
+ svg
626
+ }];
627
+ });
628
+ }
629
+ }
630
+ ];
631
+ export { readDeclaredPackages as a, convertIcon as c, listPluginFiles as i, createCustomAdapter as n, readJson as o, findPackage as r, readPluginBuild as s, iconAdapters as t };
632
+
633
+ //# sourceMappingURL=adapters-Bx_MyEX_.js.map