@driftime/sanity-plugin-icon 0.4.1 → 0.4.3

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 CHANGED
@@ -278,6 +278,37 @@ export const contactIcons: SanityIconName<"lucide">[] = ["mail", "phone", "globe
278
278
 
279
279
  <br />
280
280
 
281
+ ### Initial Values
282
+
283
+ A field's `initialValue` names the icon a new document starts with. Once the build step has run, the name completes as it's typed.
284
+
285
+ ```typescript
286
+ defineField({
287
+ name: "icon",
288
+ type: "icon",
289
+ description: "Icon shown beside the contact method.",
290
+ options: { library: "lucide", icons: ["mail", "phone", "globe"] },
291
+ initialValue: { name: "mail" },
292
+ });
293
+ ```
294
+
295
+ The initial value holds only the name. The first time the field is shown, the Studio finds the icon in the field's icon library and stores it with its icon library, style, and drawing. Until then, the stored icon has a name but no drawing, and it fails validation like any other icon in that state. A name the field doesn't offer is left as it is, and during development a message in the console names the field.
296
+
297
+ Names complete from every icon library the build step listed, not only the field's. A function that returns the initial value needs `SanityIconInitialValue` as its return type, so the name is checked rather than widened to a string.
298
+
299
+ ```typescript
300
+ import type { SanityIconInitialValue } from "@driftime/sanity-plugin-icon";
301
+
302
+ defineField({
303
+ name: "icon",
304
+ type: "icon",
305
+ description: "Icon shown beside the contact method.",
306
+ initialValue: (): SanityIconInitialValue => ({ name: "mail" }),
307
+ });
308
+ ```
309
+
310
+ <br />
311
+
281
312
  ### The Project's Own Icons
282
313
 
283
314
  A folder of SVG files becomes an icon library of its own. It might hold a brand's marks, or a complete icon set drawn for a brand or a product. Pass the folder's path, relative to the project, to the build step under an identifier. Fields then name that identifier as their icon library.
@@ -349,7 +380,7 @@ When nothing readable is stored, it returns `undefined` and the preview falls ba
349
380
 
350
381
  ## Site
351
382
 
352
- On the site, one component draws a stored icon, and it's imported from `@driftime/sanity-plugin-icon/render`. That path carries no Studio code, so it's safe in server components and anywhere else on the site.
383
+ On the site, `Icon` draws a stored icon, and `getIcon` finds an icon the site chooses itself. Both are imported from `@driftime/sanity-plugin-icon/render`. That path carries no Studio code, so it's safe in server components and anywhere else on the site.
353
384
 
354
385
  <br />
355
386
 
@@ -400,6 +431,41 @@ An icon needs nothing special in a query. It comes back as a plain object with t
400
431
 
401
432
  <br />
402
433
 
434
+ ### Looking Up Icons
435
+
436
+ Some icons are chosen by the site rather than by an author, such as a default for an icon field left empty. `getIcon` finds an icon by name in an installed icon library and returns it as the Studio stores it, so `Icon` draws it the same way as an icon an author chose.
437
+
438
+ ```tsx
439
+ import { getIcon, Icon } from "@driftime/sanity-plugin-icon/render";
440
+ import type { SanityIcon } from "@driftime/sanity-plugin-icon/render";
441
+
442
+ interface FeatureProps {
443
+ icon: SanityIcon | undefined;
444
+ title: string;
445
+ }
446
+
447
+ export async function Feature({ icon, title }: FeatureProps) {
448
+ const value = icon ?? (await getIcon({ library: "lucide", name: "house" }));
449
+
450
+ return (
451
+ <article>
452
+ <Icon value={value} className="size-8" />
453
+ <h3>{title}</h3>
454
+ </article>
455
+ );
456
+ }
457
+ ```
458
+
459
+ | Input | Type | Default | Purpose |
460
+ | --------- | ------------------- | ------------------- | --------------------------------------------------------------------------- |
461
+ | `library` | `SanityIconLibrary` | required | The identifier of the icon library. |
462
+ | `style` | `SanityIconStyle` | the library's first | The style the icon is drawn in. |
463
+ | `name` | `SanityIconName` | required | The icon's name, which completes as it's typed once the build step has run. |
464
+
465
+ It reads the icon libraries the build step converts, so the site's own build needs the build step, as [Adding the Build Step](#adding-the-build-step) describes. It returns `undefined` when the build step hasn't run, or when the icon library, style, or name isn't installed. The first call for a style loads every icon in that style, so it suits server components and images rendered on the server better than the browser.
466
+
467
+ <br />
468
+
403
469
  ## Reference
404
470
 
405
471
  The rest of this document covers the shape of a stored icon and everything the package exports.
@@ -450,6 +516,7 @@ The drawing is written with the name, which is what lets an icon render without
450
516
  | `iconLibraries(options?)` | `@driftime/sanity-plugin-icon/vite` | The build step as a Vite plugin, for a framework's list. |
451
517
  | `withIcons(options?)` | `@driftime/sanity-plugin-icon/next` | Adds the build step to a Next.js configuration. |
452
518
  | `Icon` | `@driftime/sanity-plugin-icon/render` | Draws a stored icon. |
519
+ | `getIcon(lookup)` | `@driftime/sanity-plugin-icon/render` | Finds an icon by name in an installed icon library. |
453
520
 
454
521
  <br />
455
522
 
@@ -460,6 +527,7 @@ The drawing is written with the name, which is what lets an icon render without
460
527
  | `SanityIconConfig` | `@driftime/sanity-plugin-icon` | Everything `iconPlugin` accepts. |
461
528
  | `SanityIconOptions` | `@driftime/sanity-plugin-icon` | The `options` an icon field accepts. |
462
529
  | `SanityIconDefinition` | `@driftime/sanity-plugin-icon` | A field or array member of type `icon`. |
530
+ | `SanityIconInitialValue` | `@driftime/sanity-plugin-icon` | The icon a field starts with. |
463
531
  | `SanityIconSelection` | `@driftime/sanity-plugin-icon` | An icon library with a style and icons checked against it. |
464
532
  | `SanityIconLibrary` | `@driftime/sanity-plugin-icon` | The identifier of a supported icon library. |
465
533
  | `SanityIconStyle` | `@driftime/sanity-plugin-icon` | The styles of an icon library, given its identifier. |
@@ -471,6 +539,7 @@ The drawing is written with the name, which is what lets an icon render without
471
539
  | `SanityIconWebpackCustomizer` | `@driftime/sanity-plugin-icon/next` | A Next.js `webpack` option the build step runs first. |
472
540
  | `SanityIconProps` | `@driftime/sanity-plugin-icon/render` | Everything `Icon` accepts: an `svg` element's props and `value`. |
473
541
  | `SanityIcon` | `@driftime/sanity-plugin-icon/render` | A stored icon, with its icon library, its name, and its drawing. |
542
+ | `SanityIconLookup` | `@driftime/sanity-plugin-icon/render` | Everything `getIcon` accepts: an icon library, a style, and a name. |
474
543
 
475
544
  <br />
476
545
 
@@ -1,5 +1,3 @@
1
- import { n as isDefined, r as isRecord } from "./utils-COPacfAq.js";
2
- import { i as parseIconRoot, r as parseIconNode } from "./nodes-DAzj56Xn.js";
3
1
  /** Whether this is a development build, the only kind in which the plugin logs. */
4
2
  const isDevelopment = process.env.NODE_ENV === "development", prefixStyle = "color: #2276fc";
5
3
  /**
@@ -50,41 +48,6 @@ function createLogger(name) {
50
48
  }
51
49
  /** Package name, used as the prefix on every logged message. */
52
50
  const pluginName = "@driftime/sanity-plugin-icon", logger = createLogger(pluginName);
53
- /**
54
- * Reads one icon of a converted set, skipping it when its data isn't usable.
55
- *
56
- * @param value - The value to read.
57
- * @returns The icon, or undefined when the value isn't one.
58
- */
59
- function parseIconSetIcon(value) {
60
- if (!isRecord(value)) return;
61
- let { name, keywords, node, root } = value, parsedNode = parseIconNode(node), parsedRoot = isDefined(root) ? parseIconRoot(root) : void 0;
62
- if (typeof name == "string" && Array.isArray(keywords) && isDefined(parsedNode) && (!isDefined(root) || isDefined(parsedRoot))) return {
63
- name,
64
- keywords: keywords.filter((keyword) => typeof keyword == "string"),
65
- node: parsedNode,
66
- ...isDefined(parsedRoot) && { root: parsedRoot }
67
- };
68
- }
69
- /**
70
- * Reads a converted set, keeping only the icons whose data is usable.
71
- *
72
- * @param value - The value to read.
73
- * @returns The set, or undefined when the value isn't one.
74
- */
75
- function parseIconSet(value) {
76
- if (!isRecord(value)) return;
77
- let { library, style, root, icons } = value, parsedRoot = parseIconRoot(root);
78
- if (typeof library == "string" && typeof style == "string" && isDefined(parsedRoot) && Array.isArray(icons)) return {
79
- library,
80
- style,
81
- root: parsedRoot,
82
- icons: icons.flatMap((icon) => {
83
- let parsed = parseIconSetIcon(icon);
84
- return isDefined(parsed) ? [parsed] : [];
85
- })
86
- };
87
- }
88
- export { logger as n, pluginName as r, parseIconSet as t };
51
+ export { pluginName as n, logger as t };
89
52
 
90
- //# sourceMappingURL=sets-kepuObH8.js.map
53
+ //# sourceMappingURL=defaults-BEzCWZtH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults-BEzCWZtH.js","names":["isDevelopment","process","env","isDevelopment","prefixStyle","createLogger","name","prefix","format","message","info","console","warn","error","createLogger","pluginName","logger","\"NODE_ENV\""],"sources":["../../@repo/lib/environment.ts","../../@repo/lib/logger.ts","../src/config/defaults.ts"],"sourcesContent":["/** Whether this is a development build, the only kind in which the plugin logs. */\nexport const isDevelopment = process.env[\"NODE_ENV\"] === \"development\";\n","import { isDevelopment } from \"./environment\";\n\n/** Console style for the prefix, in the blue the Studio uses for its own messages. */\nconst prefixStyle = \"color: #2276fc\";\n\n/**\n * Creates a logger that prefixes messages with the plugin's name and only logs in development builds.\n * Browser consoles show the prefix in blue.\n *\n * @param name - The package name to prefix messages with.\n * @returns Functions that log progress, a warning, or an error, or format a message to throw.\n */\nexport function createLogger(name: string) {\n const prefix = `[${name}]`;\n\n /**\n * Prefixes a message with the package name.\n *\n * @param message - The message.\n * @returns The prefixed message.\n */\n function format(message: string) {\n return `${prefix} ${message}`;\n }\n\n return {\n /**\n * Logs progress worth seeing, such as what a build step did, in development builds only.\n *\n * @param message - What happened.\n */\n info(message: string) {\n if (isDevelopment) console.info(`%c${prefix}%c ${message}`, prefixStyle, \"\");\n },\n /**\n * Logs a warning about something the plugin recovered from, in development builds only.\n *\n * @param message - What happened and what to do about it.\n */\n warn(message: string) {\n if (isDevelopment) console.warn(`%c${prefix}%c ${message}`, prefixStyle, \"\");\n },\n /**\n * Logs an error the plugin couldn't recover from, in development builds only.\n *\n * @param message - What went wrong and what to do about it.\n */\n error(message: string) {\n if (isDevelopment) console.error(`%c${prefix}%c ${message}`, prefixStyle, \"\");\n },\n format,\n };\n}\n","import { createLogger } from \"@repo/lib/logger\";\n\n/** Package name, used as the prefix on every logged message. */\nexport const pluginName = \"@driftime/sanity-plugin-icon\";\n\n/** The package's logger. */\nexport const logger = createLogger(pluginName);\n"],"mappings":";AACA,MAAaA,gBAAgBC,QAAQC,IAAIe,aAAgB,eCEnDb,cAAc;;;;;;;;AASpB,SAAgBC,aAAaC,MAAc;CACzC,IAAMC,SAAS,IAAID,KAAI;;;;;;;CAQvB,SAASE,OAAOC,SAAiB;EAC/B,OAAO,GAAGF,OAAM,GAAIE;CACtB;CAEA,OAAO;;;;;;EAMLC,KAAKD,SAAiB;GACpB,AAAIN,iBAAeQ,QAAQD,KAAK,KAAKH,OAAM,KAAME,WAAWL,aAAa,EAAE;EAC7E;;;;;;EAMAQ,KAAKH,SAAiB;GACpB,AAAIN,iBAAeQ,QAAQC,KAAK,KAAKL,OAAM,KAAME,WAAWL,aAAa,EAAE;EAC7E;;;;;;EAMAS,MAAMJ,SAAiB;GACrB,AAAIN,iBAAeQ,QAAQE,MAAM,KAAKN,OAAM,KAAME,WAAWL,aAAa,EAAE;EAC9E;EACAI;CACF;AACF;;ACjDA,MAAaO,aAAa,gCAGbC,SAASF,aAAaC,UAAU"}
package/dist/index.d.ts CHANGED
@@ -1,52 +1,13 @@
1
- import { n as iconTypeName, t as SanityIcon } from "./types-qlHEYDoN.js";
1
+ import { a as SanityIconName, i as SanityIconLibrary, n as ListedLibraryId, o as SanityIconStyle, r as SanityIcon, s as iconTypeName, t as IconLibraryId } from "./types-D9GjPlhU.js";
2
2
  import { t as SanityIconBuildOptions } from "./vite-ifICG8y9.js";
3
- import { BaseSchemaTypeOptions, TypeAliasDefinition } from "sanity";
3
+ import { BaseSchemaTypeOptions, InitialValueProperty, TypeAliasDefinition } from "sanity";
4
4
  import { ComponentProps } from "react";
5
- import { SanityIconNames } from "@driftime/sanity-plugin-icon/names";
6
- /**
7
- * Styles of each library the plugin supports, the first being the default. For a library published as a family of
8
- * packages, its styles are the packages it publishes, and the installed ones are used.
9
- */
10
- declare const iconLibraryStyles: {
11
- 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")[];
12
- readonly heroicons: readonly ["outline", "solid", "mini", "micro"];
13
- readonly hugeicons: readonly ["stroke-rounded"];
14
- readonly iconoir: readonly ["regular", "solid"];
15
- readonly lucide: readonly ["default"];
16
- 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"];
17
- readonly phosphor: readonly ["regular", "thin", "light", "bold", "fill", "duotone"];
18
- readonly tabler: readonly ["outline", "filled"];
19
- };
20
5
  declare module "@sanity/types" {
21
6
  interface IntrinsicDefinitions {
22
7
  /** Definition of a field of type `icon`. */
23
8
  icon: SanityIconDefinition;
24
9
  }
25
10
  }
26
- /** Styles of each supported library, from the plugin's own list. */
27
- type IconLibraryStyles = typeof iconLibraryStyles;
28
- /**
29
- * Identifier of a library the plugin supports.
30
- *
31
- * @public
32
- */
33
- type SanityIconLibrary = keyof IconLibraryStyles;
34
- /**
35
- * Styles a library offers. The project's own icon folders have one style, `default`.
36
- *
37
- * @public
38
- */
39
- type SanityIconStyle<Library extends string> = Library extends SanityIconLibrary ? IconLibraryStyles[Library][number] : "default";
40
- /**
41
- * Names of a library's icons, once the build step has listed the installed version's, or any name before then.
42
- *
43
- * @public
44
- */
45
- type SanityIconName<Library extends string> = Library extends keyof SanityIconNames ? SanityIconNames[Library] : string;
46
- /** Libraries the build step has listed, or any identifier before it has, so the project's own folders can be named. */
47
- type ListedLibraryId = [keyof SanityIconNames] extends [never] ? string & NonNullable<unknown> : Extract<keyof SanityIconNames, string>;
48
- /** Libraries a field can name: the supported ones, plus the project's own folders. */
49
- type IconLibraryId = SanityIconLibrary | ListedLibraryId;
50
11
  /**
51
12
  * A choice of library, style, and icons, where the style and icons are checked against the library.
52
13
  *
@@ -72,14 +33,25 @@ type SanityIconOptions = BaseSchemaTypeOptions & (SanityIconSelection | {
72
33
  icons?: undefined;
73
34
  });
74
35
  /**
75
- * Definition of a field or array member holding an icon, so its options are type-checked like a
36
+ * Icon a field starts with. The Studio saves its drawing from the field's library the first time the field is shown.
37
+ *
38
+ * @public
39
+ */
40
+ interface SanityIconInitialValue {
41
+ /** Name of the icon, from any library the build step has listed. */
42
+ name: SanityIconName<ListedLibraryId>;
43
+ }
44
+ /**
45
+ * Definition of a field or array member holding an icon, so its options and initial value are type-checked like a
76
46
  * built-in type's.
77
47
  *
78
48
  * @public
79
49
  */
80
- interface SanityIconDefinition extends Omit<TypeAliasDefinition<typeof iconTypeName, undefined>, "options"> {
50
+ interface SanityIconDefinition extends Omit<TypeAliasDefinition<typeof iconTypeName, undefined>, "options" | "initialValue"> {
81
51
  /** Options for the field. */
82
52
  options?: SanityIconOptions;
53
+ /** Icon the field starts with, or a function that returns one. */
54
+ initialValue?: InitialValueProperty<unknown, SanityIconInitialValue>;
83
55
  }
84
56
  /**
85
57
  * Plugin configuration, naming the library every icon field uses unless it names its own.
@@ -120,5 +92,5 @@ type DrawingProps = Omit<ComponentProps<"svg">, "children"> & {
120
92
  * @public
121
93
  */
122
94
  export declare function createIconPreview(value: SanityIcon | undefined): (() => import("react").FunctionComponentElement<DrawingProps>) | undefined;
123
- export type { SanityIconBuildOptions, SanityIconConfig, SanityIconDefinition, SanityIconLibrary, SanityIconName, SanityIconOptions, SanityIconSelection, SanityIconStyle };
95
+ export type { SanityIconBuildOptions, SanityIconConfig, SanityIconDefinition, SanityIconInitialValue, SanityIconLibrary, SanityIconName, SanityIconOptions, SanityIconSelection, SanityIconStyle };
124
96
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["SanityIconNames","BaseSchemaTypeOptions","TypeAliasDefinition","iconLibraryStyles","iconTypeName","_0","SanityIconDefinition","sideEffect","IconLibraryStyles","SanityIconLibrary","SanityIconStyle","Library","SanityIconName","ListedLibraryId","NonNullable","Extract","IconLibraryId","SanityIconSelection","SanityIconOptions","Omit","SanityIconConfig","iconPlugin","IconElement","Record","IconNode","IconRoot","IconDrawing","iconSvgAttributes","findDrawingProblem","root","node","parseIconNode","parseIconRoot","resolveIconDrawing","serializeIconDrawing","ComponentProps","IconDrawing","DrawingProps","Omit","Drawing","drawing","JSX","_$__components_drawing0","SanityIcon","createIconPreview","DrawingProps","_$__components_drawing0.DrawingProps"],"sources":["../src/lib/libraries.ts","../src/plugin.ts","../src/lib/nodes.ts","../src/components/drawing.tsx","../src/lib/preview.ts"],"mappings":";;;;;;;;;cAiEa;WACX;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;YC/DU;;IAER,MAAMM;;;;KAKLE,2BAA2BL;;;;;;KAOpBM,0BAA0BD;;;;;;KAO1BE,gBAAgB,0BAA0BC,gBAAgBF,oBAClED,kBAAkBG;;;;;;KAQVC,eAAe,0BAA0BD,sBAAsBX,kBACvEA,gBAAgBW;;KAIfE,yBAAyBb,4CACjBc,uBACTC,cAAcf;;KAGbgB,gBAAgBP,oBAAoBI;;;;;;KAO7BI,yBACT,WAAWD;;EAEV,SAASL;;EAET,QAAQD,gBAAgBC;;EAExB,QAAQC,eAAeD;KAEzBK;;;;;;;KAQUE,oBAAoBjB,yBAC7BgB;EAAwB;EAAqB;EAAmB;;;;;;;;UAQlDX,6BAA6Ba,KAAKjB,2BAA2BE;;EAE5E,UAAUc;;;;;;;KAQAE,mBAAmBH;;;;;;;;;wBAiBfI,WAAW,QAAQD,oCAAgB;;KC1GvCE,eAAe,iBAAiB,YAAYC,wBAAwB,YAAYD;;KAGhFE,WAAWF;;KAGXG,WAAWF;;UAGNG;;EAEf,MAAMD;;EAEN,MAAMD;;KCuCIa,eAAeC,KAAKH;EAAuC,SAASC;;;;;;;;;wBC1ChEQ,kBAAkB,OAAOD,gDAAsB,yBAAtBD"}
1
+ {"version":3,"file":"index.d.ts","names":["BaseSchemaTypeOptions","InitialValueProperty","TypeAliasDefinition","IconLibraryId","ListedLibraryId","SanityIconName","SanityIconStyle","iconTypeName","_0","SanityIconDefinition","sideEffect","SanityIconSelection","Library","SanityIconOptions","SanityIconInitialValue","Omit","SanityIconConfig","iconPlugin","IconElement","Record","IconNode","IconRoot","IconDrawing","iconSvgAttributes","findDrawingProblem","root","node","parseIconNode","parseIconRoot","resolveIconDrawing","serializeIconDrawing","ComponentProps","IconDrawing","DrawingProps","Omit","Drawing","drawing","JSX","_$__components_drawing0","SanityIcon","createIconPreview","DrawingProps","_$__components_drawing0.DrawingProps"],"sources":["../src/plugin.ts","../src/lib/nodes.ts","../src/components/drawing.tsx","../src/lib/preview.ts"],"mappings":";;;;;YAQY;;IAER,MAAMS;;;;;;;;KASEE,yBACT,WAAWR;;EAEV,SAASS;;EAET,QAAQN,gBAAgBM;;EAExB,QAAQP,eAAeO;KAEzBT;;;;;;;KAQUU,oBAAoBb,yBAC7BW;EAAwB;EAAqB;EAAmB;;;;;;;UAOlDG;;EAEf,MAAMT,eAAeD;;;;;;;;UASNK,6BAA6BM,KAC5Cb,2BAA2BK;;EAI3B,UAAUM;;EAEV,eAAeZ,8BAA8Ba;;;;;;;KAQnCE,mBAAmBL;;;;;;;;;wBAiBfM,WAAW,QAAQD,oCAAgB;;KCnFvCE,eAAe,iBAAiB,YAAYC,wBAAwB,YAAYD;;KAGhFE,WAAWF;;KAGXG,WAAWF;;UAGNG;;EAEf,MAAMD;;EAEN,MAAMD;;KCuCIa,eAAeC,KAAKH;EAAuC,SAASC;;;;;;;;;wBC1ChEQ,kBAAkB,OAAOD,gDAAsB,yBAAtBD"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { r as pluginName, t as parseIconSet } from "./sets-kepuObH8.js";
1
+ import { n as pluginName, t as logger } from "./defaults-BEzCWZtH.js";
2
2
  import { n as isDefined, t as convertCase } from "./utils-COPacfAq.js";
3
3
  import { a as resolveIconDrawing, o as serializeIconDrawing } from "./nodes-DAzj56Xn.js";
4
- import { t as Drawing } from "./drawing-ByrcBbWB.js";
4
+ import { a as splitMatches, i as selectIcons, n as normalizeTerms, o as Drawing, r as requestLibrary, t as iconTypeName } from "./types-v7Qz7ogk.js";
5
5
  import { t as getIconSetKey } from "./registry-BEEpqK3z.js";
6
6
  import { ChangeIndicator, FieldActionsProvider, FieldActionsResolver, FormField, defineField, definePlugin, defineType, getPublishedId, set, setIfMissing, unset, useFormValue } from "sanity";
7
7
  import { c } from "react/compiler-runtime";
@@ -12,7 +12,6 @@ import { Box, Button, Card, Dialog, Flex, Grid, Spinner, Stack, Text, TextInput
12
12
  import { SearchIcon } from "@sanity/icons/Search";
13
13
  import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
14
14
  import { Popover } from "@sanity/ui/popover";
15
- import { iconRegistry } from "@driftime/sanity-plugin-icon/sets";
16
15
  /**
17
16
  * Checks whether a form node has members, as objects and arrays of objects do.
18
17
  *
@@ -326,142 +325,6 @@ function Recent(t0) {
326
325
  }), $[22] = props, $[23] = t2, $[24] = t4, $[25] = t5) : t5 = $[25], t5;
327
326
  }
328
327
  /**
329
- * Normalises text for search, so hyphenated names and multi-word keywords match the same way.
330
- *
331
- * @param value - The text.
332
- * @returns The normalised text.
333
- */
334
- function normalizeTerms(value) {
335
- return value.toLowerCase().replaceAll(/[\s-]+/gu, " ").trim();
336
- }
337
- /**
338
- * Splits text into the parts a search matches and the parts it doesn't, matching the way search does: ignoring case,
339
- * and treating spaces and hyphens alike.
340
- *
341
- * @param text - The text to split.
342
- * @param query - The normalised search.
343
- * @returns The parts in order, each with where it starts in the text and whether it matches.
344
- */
345
- function splitMatches(text, query) {
346
- if (!isDefined(query)) return [{
347
- text,
348
- start: 0,
349
- match: !1
350
- }];
351
- let pattern = query.split(" ").map((word) => word.replaceAll(/[$()*+.?[\\\]^{|}]/gu, String.raw`\$&`)).join(String.raw`[\s-]+`), parts = text.split(RegExp(`(${pattern})`, "giu"));
352
- return parts.map((part, index) => ({
353
- text: part,
354
- start: parts.slice(0, index).join("").length,
355
- match: index % 2 == 1
356
- }));
357
- }
358
- /**
359
- * Narrows the library to the named icons, in the order given. Unknown names are skipped, so a list keeps working
360
- * across library releases.
361
- *
362
- * @param library - Every icon in the library.
363
- * @param names - The icons to offer, or undefined for all of them.
364
- * @returns The icons to offer.
365
- */
366
- function selectIcons(library, names) {
367
- if (!isDefined(names)) return library;
368
- let byName = new Map(library.map((icon) => [icon.name, icon]));
369
- return [...new Set(names)].flatMap((name) => {
370
- let icon = byName.get(name);
371
- return isDefined(icon) ? [icon] : [];
372
- });
373
- }
374
- /**
375
- * Lists identifiers as inline code, separated by commas.
376
- *
377
- * @param identifiers - The identifiers.
378
- * @returns The list.
379
- */
380
- function formatList(identifiers) {
381
- return identifiers.map((identifier) => `\`${identifier}\``).join(", ");
382
- }
383
- /**
384
- * Describes why a library the project hasn't installed can't be shown, and what to add.
385
- *
386
- * @param label - Readable name of the library.
387
- * @param packageName - Package the library is read from, or an example of one for a family of packages.
388
- * @param family - Whether the library is a family of packages, one per style.
389
- * @param listed - Whether the project's `package.json` lists the package.
390
- * @param sitePackage - Another package of the library the project lists, or undefined when there's none.
391
- * @returns The problem.
392
- */
393
- function describeMissingLibrary(label, packageName, family, listed, sitePackage) {
394
- return listed ? {
395
- title: `${label} isn't installed yet`,
396
- description: `\`${packageName}\` is in \`package.json\` but not in \`node_modules\`. Reinstall the project's dependencies.`
397
- } : isDefined(sitePackage) ? {
398
- title: `${label} needs \`${packageName}\``,
399
- description: `The Studio reads ${label} from \`${packageName}\`, not \`${sitePackage}\`. Add it as a dev dependency.`
400
- } : {
401
- title: `${label} isn't installed`,
402
- description: family ? `Install a ${label} style package, such as \`${packageName}\`.` : `Install \`${packageName}\` in the project.`
403
- };
404
- }
405
- /**
406
- * Loads one library style from the sets the build step converted.
407
- *
408
- * @param library - Identifier of the library, or undefined when none is set.
409
- * @param style - Identifier of the style, or undefined for the library's default.
410
- * @returns The icons, or why they can't be shown.
411
- */
412
- async function readLibrary(library, style) {
413
- if (!isDefined(library)) return { problem: {
414
- title: "No icon library set",
415
- description: "Set `library` in the icon plugin's configuration or in the field's options."
416
- } };
417
- if (!iconRegistry.ready) return { problem: {
418
- title: "Icons aren't set up",
419
- description: "Add `withIcons()` to the Studio's build configuration, then restart the Studio."
420
- } };
421
- let info = iconRegistry.libraries[library];
422
- if (!isDefined(info)) return { problem: {
423
- title: "Unknown icon library",
424
- description: `There's no icon library called \`${library}\`. Use one of: ${formatList(Object.keys(iconRegistry.libraries))}.`
425
- } };
426
- let { label, packageName, packagePrefix, styles, listed, installed, sitePackage } = info;
427
- if (!installed) return { problem: describeMissingLibrary(label, packageName, isDefined(packagePrefix), listed, sitePackage) };
428
- let resolvedStyle = style ?? styles[0] ?? "", loader = iconRegistry.sets[getIconSetKey(library, resolvedStyle)];
429
- if (!isDefined(loader)) return { problem: isDefined(packagePrefix) ? {
430
- title: `${label} style \`${resolvedStyle}\` isn't installed`,
431
- description: `Install \`${packagePrefix}${resolvedStyle}\` in the project.`
432
- } : {
433
- title: `Unknown ${label} style`,
434
- description: `${label} has no \`${resolvedStyle}\` style. Use one of: ${formatList(styles)}.`
435
- } };
436
- let module = await loader(), set = parseIconSet(module.default);
437
- return isDefined(set) ? { icons: set.icons.map(({ name, keywords, node, root }) => ({
438
- name,
439
- label: convertCase(name, "title"),
440
- tags: keywords.join(", "),
441
- drawing: {
442
- root: root ?? set.root,
443
- node
444
- },
445
- terms: normalizeTerms([name, ...keywords].join(" "))
446
- })) } : { problem: {
447
- title: `Couldn't load ${label}`,
448
- description: "Restart the Studio and try again."
449
- } };
450
- }
451
- /** Library requests shared by every field in the session, keyed by library and style, since the data never changes. */
452
- const libraryRequests = /* @__PURE__ */ new Map();
453
- /**
454
- * Loads a library style, reusing a request already in progress.
455
- *
456
- * @param library - Identifier of the library, or undefined when none is set.
457
- * @param style - Identifier of the style, or undefined for the library's default.
458
- * @returns The icons, or why they can't be shown.
459
- */
460
- async function requestLibrary(library, style) {
461
- let key = getIconSetKey(library ?? "", style ?? ""), request = libraryRequests.get(key);
462
- return isDefined(request) || (request = readLibrary(library, style), libraryRequests.set(key, request)), await request;
463
- }
464
- /**
465
328
  * Gap between the tooltip and its cell, set through margins because `@sanity/ui` offers no other way.
466
329
  * Only the top is set, since the tooltip always appears above the cell.
467
330
  */
@@ -938,8 +801,23 @@ function resolveIconOptions(options, config) {
938
801
  icons
939
802
  };
940
803
  }
941
- /** Schema type name of the icon object. */
942
- const iconTypeName = "icon";
804
+ /**
805
+ * Creates the patches that store an icon, with the library and style it was chosen from.
806
+ *
807
+ * @param icon - The icon.
808
+ * @param library - Identifier of the library, or undefined when none is set.
809
+ * @param style - Identifier of the style, or undefined for the library's default.
810
+ * @returns The patches.
811
+ */
812
+ function createSelectionPatches(icon, library, style) {
813
+ return [
814
+ setIfMissing({ _type: iconTypeName }),
815
+ isDefined(library) ? set(library, ["library"]) : unset(["library"]),
816
+ isDefined(style) ? set(style, ["style"]) : unset(["style"]),
817
+ set(icon.name, ["name"]),
818
+ set(serializeIconDrawing(icon.drawing), ["node"])
819
+ ];
820
+ }
943
821
  /**
944
822
  * Creates the icon field input, bound to the plugin's configuration. A field's own icons replace the
945
823
  * plugin's rather than adding to them.
@@ -949,39 +827,54 @@ const iconTypeName = "icon";
949
827
  */
950
828
  function createInput(config) {
951
829
  function Input(t0) {
952
- let $ = c(35), { id, schemaType, value, onChange, readOnly } = t0, { library: storedLibrary, name, node } = value ?? {}, [open, setOpen] = useState(!1), t1;
953
- $[0] === schemaType.options ? t1 = $[1] : (t1 = resolveIconOptions(schemaType.options, config), $[0] = schemaType.options, $[1] = t1);
954
- let { library, style, icons } = t1, selectedDrawing = resolveIconDrawing(node), selectedName = storedLibrary === library ? name : void 0, selectedLabel = isDefined(name) ? convertCase(name, "title") : void 0, t2;
955
- $[2] !== library || $[3] !== onChange || $[4] !== setOpen || $[5] !== style ? (t2 = function handleSelect(icon) {
956
- onChange([
957
- setIfMissing({ _type: iconTypeName }),
958
- isDefined(library) ? set(library, ["library"]) : unset(["library"]),
959
- isDefined(style) ? set(style, ["style"]) : unset(["style"]),
960
- set(icon.name, ["name"]),
961
- set(serializeIconDrawing(icon.drawing), ["node"])
962
- ]), setOpen(!1);
963
- }, $[2] = library, $[3] = onChange, $[4] = setOpen, $[5] = style, $[6] = t2) : t2 = $[6];
964
- let handleSelect = t2, T0 = Flex, T1 = Button, t6 = isDefined(selectedDrawing) ? /* @__PURE__ */ jsx(Drawing, {
830
+ let $ = c(28), { id, schemaType, value, onChange, readOnly } = t0, { library: storedLibrary, name, node } = value ?? {}, [open, setOpen] = useState(!1), { library, style, icons } = resolveIconOptions(schemaType.options, config), selectedDrawing = resolveIconDrawing(node), selectedName = storedLibrary === library ? name : void 0, selectedLabel = isDefined(name) ? convertCase(name, "title") : void 0, undrawnName = isDefined(node) ? void 0 : name;
831
+ useEffect(() => {
832
+ let active = !0;
833
+ return (async function saveDrawing() {
834
+ if (!isDefined(undrawnName) || readOnly === !0) return;
835
+ let { icons: libraryIcons } = await requestLibrary(library, style);
836
+ if (!active || !isDefined(libraryIcons)) return;
837
+ let icon = selectIcons(libraryIcons, icons).find((candidate) => candidate.name === undrawnName);
838
+ if (!isDefined(icon)) {
839
+ logger.warn(`The icon field "${id}" starts with "${undrawnName}", which isn't one of its icons. Change its initialValue.`);
840
+ return;
841
+ }
842
+ onChange(createSelectionPatches(icon, library, style));
843
+ })(), () => {
844
+ active = !1;
845
+ };
846
+ }, [
847
+ id,
848
+ undrawnName,
849
+ readOnly,
850
+ library,
851
+ style,
852
+ icons,
853
+ onChange
854
+ ]);
855
+ let handleSelect = function handleSelect(icon_0) {
856
+ onChange(createSelectionPatches(icon_0, library, style)), setOpen(!1);
857
+ }, T0 = Flex, T1 = Button, t4 = isDefined(selectedDrawing) ? /* @__PURE__ */ jsx(Drawing, {
965
858
  drawing: selectedDrawing,
966
859
  width: "1em",
967
860
  height: "1em"
968
- }) : /* @__PURE__ */ jsx(SquareDashedIcon, { ...defaultIconProps }), t7 = selectedLabel ?? "Select icon", t8;
969
- $[7] === setOpen ? t8 = $[8] : (t8 = () => {
861
+ }) : /* @__PURE__ */ jsx(SquareDashedIcon, { ...defaultIconProps }), t5 = selectedLabel ?? "Select icon", t6;
862
+ $[0] === setOpen ? t6 = $[1] : (t6 = () => {
970
863
  setOpen(!0);
971
- }, $[7] = setOpen, $[8] = t8);
972
- let t9 = isDefined(selectedLabel) ? `${selectedLabel} currently selected` : "Select icon", t10;
973
- $[9] !== T1 || $[10] !== id || $[11] !== readOnly || $[12] !== t6 || $[13] !== t7 || $[14] !== t8 || $[15] !== t9 ? (t10 = /* @__PURE__ */ jsx(T1, {
864
+ }, $[0] = setOpen, $[1] = t6);
865
+ let t7 = isDefined(selectedLabel) ? `${selectedLabel} currently selected` : "Select icon", t8;
866
+ $[2] !== T1 || $[3] !== id || $[4] !== readOnly || $[5] !== t4 || $[6] !== t5 || $[7] !== t6 || $[8] !== t7 ? (t8 = /* @__PURE__ */ jsx(T1, {
974
867
  id,
975
868
  type: "button",
976
869
  mode: "ghost",
977
- icon: t6,
978
- text: t7,
870
+ icon: t4,
871
+ text: t5,
979
872
  disabled: readOnly,
980
- onClick: t8,
981
- "aria-label": t9
982
- }), $[9] = T1, $[10] = id, $[11] = readOnly, $[12] = t6, $[13] = t7, $[14] = t8, $[15] = t9, $[16] = t10) : t10 = $[16];
983
- let t11;
984
- $[17] !== onChange || $[18] !== readOnly || $[19] !== value ? (t11 = isDefined(value) && /* @__PURE__ */ jsx(Button, {
873
+ onClick: t6,
874
+ "aria-label": t7
875
+ }), $[2] = T1, $[3] = id, $[4] = readOnly, $[5] = t4, $[6] = t5, $[7] = t6, $[8] = t7, $[9] = t8) : t8 = $[9];
876
+ let t9;
877
+ $[10] !== onChange || $[11] !== readOnly || $[12] !== value ? (t9 = isDefined(value) && /* @__PURE__ */ jsx(Button, {
985
878
  type: "button",
986
879
  mode: "ghost",
987
880
  tone: "critical",
@@ -992,9 +885,9 @@ function createInput(config) {
992
885
  onChange(unset());
993
886
  },
994
887
  "aria-label": "Clear the selected icon"
995
- }), $[17] = onChange, $[18] = readOnly, $[19] = value, $[20] = t11) : t11 = $[20];
996
- let t12;
997
- $[21] !== handleSelect || $[22] !== icons || $[23] !== id || $[24] !== library || $[25] !== open || $[26] !== selectedName || $[27] !== setOpen || $[28] !== style ? (t12 = open && /* @__PURE__ */ jsx(Picker, {
888
+ }), $[10] = onChange, $[11] = readOnly, $[12] = value, $[13] = t9) : t9 = $[13];
889
+ let t10;
890
+ $[14] !== handleSelect || $[15] !== icons || $[16] !== id || $[17] !== library || $[18] !== open || $[19] !== selectedName || $[20] !== setOpen || $[21] !== style ? (t10 = open && /* @__PURE__ */ jsx(Picker, {
998
891
  id: `${id}-library`,
999
892
  library,
1000
893
  iconStyle: style,
@@ -1007,16 +900,16 @@ function createInput(config) {
1007
900
  onClickOutside: () => {
1008
901
  setOpen(!1);
1009
902
  }
1010
- }), $[21] = handleSelect, $[22] = icons, $[23] = id, $[24] = library, $[25] = open, $[26] = selectedName, $[27] = setOpen, $[28] = style, $[29] = t12) : t12 = $[29];
1011
- let t13;
1012
- return $[30] !== T0 || $[31] !== t10 || $[32] !== t11 || $[33] !== t12 ? (t13 = /* @__PURE__ */ jsxs(T0, {
903
+ }), $[14] = handleSelect, $[15] = icons, $[16] = id, $[17] = library, $[18] = open, $[19] = selectedName, $[20] = setOpen, $[21] = style, $[22] = t10) : t10 = $[22];
904
+ let t11;
905
+ return $[23] !== T0 || $[24] !== t10 || $[25] !== t8 || $[26] !== t9 ? (t11 = /* @__PURE__ */ jsxs(T0, {
1013
906
  gap: 2,
1014
907
  children: [
1015
- t10,
1016
- t11,
1017
- t12
908
+ t8,
909
+ t9,
910
+ t10
1018
911
  ]
1019
- }), $[30] = T0, $[31] = t10, $[32] = t11, $[33] = t12, $[34] = t13) : t13 = $[34], t13;
912
+ }), $[23] = T0, $[24] = t10, $[25] = t8, $[26] = t9, $[27] = t11) : t11 = $[27], t11;
1020
913
  }
1021
914
  return Input;
1022
915
  }