@driftime/sanity-plugin-icon 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,22 +1,116 @@
1
- import { a as convertCase, i as serialiseIconNode, n as parseIconNode, o as isDefined, r as resolveIconNode, t as Drawing } from "./drawing-Bo0HTICv.js";
2
- import { FormField, defineField, definePlugin, defineType, set, setIfMissing, unset } from "sanity";
1
+ import { a as convertCase, i as serializeIconNode, n as parseIconNode, o as isDefined, r as resolveIconNode, t as Drawing } from "./drawing-BThiR2bN.js";
2
+ import { ChangeIndicator, FieldActionsProvider, FieldActionsResolver, FormField, defineField, definePlugin, defineType, getPublishedId, set, setIfMissing, unset, useFormValue } from "sanity";
3
3
  import { c } from "react/compiler-runtime";
4
- import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { createElement, useEffect, useRef, useState } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
6
  import { CloseIcon } from "@sanity/icons/Close";
6
7
  import { Box, Button, Dialog, Flex, Grid, Spinner, Stack, Text, TextInput } from "@sanity/ui";
7
- import { createElement, useEffect, useRef, useState } from "react";
8
8
  import { SearchIcon } from "@sanity/icons/Search";
9
9
  import { Popover } from "@sanity/ui/popover";
10
+ /**
11
+ * Checks whether a form node holds members of its own, as an object or an array of objects does.
12
+ *
13
+ * @param node - The form node to check.
14
+ * @returns True if the node holds members.
15
+ */
16
+ function hasMembers(node) {
17
+ return "members" in node;
18
+ }
19
+ /**
20
+ * Gathers the validation reported on a form node and on anything inside it.
21
+ *
22
+ * @param node - The form node to gather validation from.
23
+ * @returns Every validation reported on the node or within it.
24
+ */
25
+ function collectNodeValidation(node) {
26
+ return [...node.validation, ...hasMembers(node) ? collectMemberValidation(node.members) : []];
27
+ }
28
+ /**
29
+ * Gathers the validation reported anywhere inside a field's members. The form hands a field only what
30
+ * is reported at its own path, which suits a frame drawing its members inline but leaves one that
31
+ * hides them showing nothing they report.
32
+ *
33
+ * @param members - The members to gather validation from.
34
+ * @returns Every validation reported on a member or within one.
35
+ */
36
+ function collectMemberValidation(members) {
37
+ return members.flatMap((member) => member.kind === "field" ? collectNodeValidation(member.field) : member.kind === "fieldSet" ? collectMemberValidation(member.fieldSet.members) : member.kind === "item" ? collectNodeValidation(member.item) : []);
38
+ }
10
39
  function Field(t0) {
11
- let $ = c(7), { title, description, inputId, validation, path, children } = t0, t1;
12
- return $[0] !== children || $[1] !== description || $[2] !== inputId || $[3] !== path || $[4] !== title || $[5] !== validation ? (t1 = /* @__PURE__ */ jsx(FormField, {
13
- title,
40
+ let $ = c(40), { actions, schemaType, title, description, presence, validation, level, inputId, path, changed, children, inputProps } = t0, t1;
41
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = [], $[0] = t1) : t1 = $[0];
42
+ let [headerActions, setHeaderActions] = useState(t1), t2;
43
+ $[1] === Symbol.for("react.memo_cache_sentinel") ? (t2 = ["_id"], $[1] = t2) : t2 = $[1];
44
+ let documentId = useFormValue(t2), fieldValidation, focused, t3;
45
+ if ($[2] !== actions || $[3] !== documentId || $[4] !== inputProps.focused || $[5] !== inputProps.members || $[6] !== path || $[7] !== schemaType || $[8] !== validation) {
46
+ let publishedId = typeof documentId == "string" ? getPublishedId(documentId) : void 0;
47
+ focused = inputProps.focused === !0;
48
+ let t4;
49
+ $[12] !== inputProps.members || $[13] !== validation ? (t4 = [...validation, ...collectMemberValidation(inputProps.members)], $[12] = inputProps.members, $[13] = validation, $[14] = t4) : t4 = $[14], fieldValidation = t4, t3 = isDefined(publishedId) && isDefined(actions) && /* @__PURE__ */ jsx(FieldActionsResolver, {
50
+ actions,
51
+ documentId: publishedId,
52
+ documentType: schemaType.name,
53
+ onActions: setHeaderActions,
54
+ path,
55
+ schemaType
56
+ }), $[2] = actions, $[3] = documentId, $[4] = inputProps.focused, $[5] = inputProps.members, $[6] = path, $[7] = schemaType, $[8] = validation, $[9] = fieldValidation, $[10] = focused, $[11] = t3;
57
+ } else fieldValidation = $[9], focused = $[10], t3 = $[11];
58
+ let t4;
59
+ $[15] !== changed || $[16] !== children || $[17] !== focused || $[18] !== path ? (t4 = /* @__PURE__ */ jsx(ChangeIndicator, {
60
+ path,
61
+ hasFocus: focused,
62
+ isChanged: changed,
63
+ children
64
+ }), $[15] = changed, $[16] = children, $[17] = focused, $[18] = path, $[19] = t4) : t4 = $[19];
65
+ let t5;
66
+ $[20] !== description || $[21] !== fieldValidation || $[22] !== headerActions || $[23] !== inputId || $[24] !== inputProps.readOnly || $[25] !== level || $[26] !== path || $[27] !== presence || $[28] !== schemaType.deprecated || $[29] !== t4 || $[30] !== title ? (t5 = /* @__PURE__ */ jsx(FormField, {
67
+ __unstable_headerActions: headerActions,
68
+ __unstable_presence: presence,
14
69
  description,
15
70
  inputId,
16
- validation,
71
+ level,
72
+ title,
73
+ validation: fieldValidation,
74
+ deprecated: schemaType.deprecated,
17
75
  path,
18
- children
19
- }), $[0] = children, $[1] = description, $[2] = inputId, $[3] = path, $[4] = title, $[5] = validation, $[6] = t1) : t1 = $[6], t1;
76
+ readOnly: inputProps.readOnly,
77
+ children: t4
78
+ }), $[20] = description, $[21] = fieldValidation, $[22] = headerActions, $[23] = inputId, $[24] = inputProps.readOnly, $[25] = level, $[26] = path, $[27] = presence, $[28] = schemaType.deprecated, $[29] = t4, $[30] = title, $[31] = t5) : t5 = $[31];
79
+ let t6;
80
+ $[32] !== focused || $[33] !== headerActions || $[34] !== path || $[35] !== t5 ? (t6 = /* @__PURE__ */ jsx(FieldActionsProvider, {
81
+ actions: headerActions,
82
+ focused,
83
+ path,
84
+ children: t5
85
+ }), $[32] = focused, $[33] = headerActions, $[34] = path, $[35] = t5, $[36] = t6) : t6 = $[36];
86
+ let t7;
87
+ return $[37] !== t3 || $[38] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t6] }), $[37] = t3, $[38] = t6, $[39] = t7) : t7 = $[39], t7;
88
+ }
89
+ /**
90
+ * Properties the plugin's own icons are drawn with. Icons taken from `@sanity/icons` are left alone,
91
+ * since they already carry the sizing and stroke the rest of the Studio uses.
92
+ */
93
+ const defaultIconProps = {
94
+ width: "1em",
95
+ height: "1em",
96
+ strokeWidth: 1.5
97
+ };
98
+ /**
99
+ * Creates a Sanity Studio icon component from an SVG icon.
100
+ *
101
+ * @param icon - The icon component to wrap.
102
+ * @param props - Additional props merged over the default properties a Studio icon is drawn with.
103
+ * @returns A Studio icon component.
104
+ */
105
+ function createSanityIcon(icon, props) {
106
+ let Icon = icon;
107
+ function SanityIcon() {
108
+ return createElement(Icon, {
109
+ ...defaultIconProps,
110
+ ...props
111
+ });
112
+ }
113
+ return SanityIcon;
20
114
  }
21
115
  /** Space between rows, in pixels. */
22
116
  const gridLayoutStyle = {
@@ -24,26 +118,30 @@ const gridLayoutStyle = {
24
118
  rowGap: 4
25
119
  };
26
120
  function Cell(t0) {
27
- let $ = c(24), focusable, icon, onSelect, position, props, selected, total;
28
- $[0] === t0 ? (focusable = $[1], icon = $[2], onSelect = $[3], position = $[4], props = $[5], selected = $[6], total = $[7]) : ({icon, selected, focusable, position, total, onSelect, ...props} = t0, $[0] = t0, $[1] = focusable, $[2] = icon, $[3] = onSelect, $[4] = position, $[5] = props, $[6] = selected, $[7] = total);
121
+ let $ = c(28), focusable, icon, onHover, onSelect, position, props, selected, total;
122
+ $[0] === t0 ? (focusable = $[1], icon = $[2], onHover = $[3], onSelect = $[4], position = $[5], props = $[6], selected = $[7], total = $[8]) : ({icon, selected, focusable, position, total, onSelect, onHover, ...props} = t0, $[0] = t0, $[1] = focusable, $[2] = icon, $[3] = onHover, $[4] = onSelect, $[5] = position, $[6] = props, $[7] = selected, $[8] = total);
29
123
  let t1 = focusable ? 0 : -1, t2;
30
- $[8] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
124
+ $[9] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
31
125
  width: 40,
32
126
  height: 40
33
- }, $[8] = t2) : t2 = $[8];
127
+ }, $[9] = t2) : t2 = $[9];
34
128
  let t3;
35
- $[9] === icon.node ? t3 = $[10] : (t3 = /* @__PURE__ */ jsx(Drawing, {
129
+ $[10] === icon.node ? t3 = $[11] : (t3 = /* @__PURE__ */ jsx(Drawing, {
36
130
  node: icon.node,
37
131
  width: "1.25em",
38
132
  height: "1.25em",
39
133
  strokeWidth: 1.5
40
- }), $[9] = icon.node, $[10] = t3);
134
+ }), $[10] = icon.node, $[11] = t3);
41
135
  let t4;
42
- $[11] !== icon || $[12] !== onSelect ? (t4 = () => {
136
+ $[12] !== icon || $[13] !== onSelect ? (t4 = () => {
43
137
  onSelect(icon);
44
- }, $[11] = icon, $[12] = onSelect, $[13] = t4) : t4 = $[13];
138
+ }, $[12] = icon, $[13] = onSelect, $[14] = t4) : t4 = $[14];
45
139
  let t5;
46
- return $[14] !== icon.label || $[15] !== icon.name || $[16] !== position || $[17] !== props || $[18] !== selected || $[19] !== t1 || $[20] !== t3 || $[21] !== t4 || $[22] !== total ? (t5 = /* @__PURE__ */ jsx(Button, {
140
+ $[15] !== icon || $[16] !== onHover ? (t5 = (event) => {
141
+ onHover(icon, event.currentTarget);
142
+ }, $[15] = icon, $[16] = onHover, $[17] = t5) : t5 = $[17];
143
+ let t6;
144
+ return $[18] !== icon.label || $[19] !== position || $[20] !== props || $[21] !== selected || $[22] !== t1 || $[23] !== t3 || $[24] !== t4 || $[25] !== t5 || $[26] !== total ? (t6 = /* @__PURE__ */ jsx(Button, {
47
145
  type: "button",
48
146
  role: "option",
49
147
  "aria-selected": selected,
@@ -56,23 +154,80 @@ function Cell(t0) {
56
154
  style: t2,
57
155
  icon: t3,
58
156
  "aria-label": icon.label,
59
- "data-icon": icon.name,
60
157
  onClick: t4,
158
+ onMouseEnter: t5,
61
159
  ...props
62
- }), $[14] = icon.label, $[15] = icon.name, $[16] = position, $[17] = props, $[18] = selected, $[19] = t1, $[20] = t3, $[21] = t4, $[22] = total, $[23] = t5) : t5 = $[23], t5;
160
+ }), $[18] = icon.label, $[19] = position, $[20] = props, $[21] = selected, $[22] = t1, $[23] = t3, $[24] = t4, $[25] = t5, $[26] = total, $[27] = t6) : t6 = $[27], t6;
161
+ }
162
+ function Library(t0) {
163
+ let $ = c(29), activeCell, activeIndex, icons, onClearSearch, onHover, onSelect, props, rows, search, selected;
164
+ $[0] === t0 ? (activeCell = $[1], activeIndex = $[2], icons = $[3], onClearSearch = $[4], onHover = $[5], onSelect = $[6], props = $[7], rows = $[8], search = $[9], selected = $[10]) : ({icons, rows, selected, activeIndex, activeCell, search, onSelect, onHover, onClearSearch, ...props} = t0, $[0] = t0, $[1] = activeCell, $[2] = activeIndex, $[3] = icons, $[4] = onClearSearch, $[5] = onHover, $[6] = onSelect, $[7] = props, $[8] = rows, $[9] = search, $[10] = selected);
165
+ let { totalRows, firstRow, lastRow } = rows, t1;
166
+ if ($[11] !== activeCell || $[12] !== activeIndex || $[13] !== firstRow || $[14] !== icons || $[15] !== lastRow || $[16] !== onClearSearch || $[17] !== onHover || $[18] !== onSelect || $[19] !== props || $[20] !== search || $[21] !== selected || $[22] !== totalRows) {
167
+ let visible = icons.slice(firstRow * 8, lastRow * 8), t2;
168
+ $[24] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
169
+ height: 348,
170
+ overflowY: "auto"
171
+ }, $[24] = t2) : t2 = $[24];
172
+ let t3;
173
+ $[25] !== icons.length || $[26] !== onClearSearch || $[27] !== search ? (t3 = icons.length === 0 && /* @__PURE__ */ jsxs(Flex, {
174
+ align: "center",
175
+ justify: "center",
176
+ direction: "column",
177
+ gap: 3,
178
+ style: { height: 348 },
179
+ children: [/* @__PURE__ */ jsx(Text, {
180
+ size: 1,
181
+ muted: !0,
182
+ children: `Nothing matches "${search}".`
183
+ }), /* @__PURE__ */ jsx(Button, {
184
+ type: "button",
185
+ mode: "ghost",
186
+ text: "Clear search",
187
+ onClick: onClearSearch
188
+ })]
189
+ }), $[25] = icons.length, $[26] = onClearSearch, $[27] = search, $[28] = t3) : t3 = $[28], t1 = /* @__PURE__ */ jsxs(Box, {
190
+ role: "listbox",
191
+ "aria-label": "Icon library",
192
+ style: t2,
193
+ ...props,
194
+ children: [t3, icons.length > 0 && /* @__PURE__ */ jsx(Grid, {
195
+ gridTemplateColumns: 8,
196
+ style: {
197
+ ...gridLayoutStyle,
198
+ paddingTop: firstRow * 44,
199
+ paddingBottom: (totalRows - lastRow) * 44
200
+ },
201
+ children: visible.map((icon, offset) => {
202
+ let index = firstRow * 8 + offset;
203
+ return /* @__PURE__ */ jsx(Cell, {
204
+ ref: index === activeIndex ? activeCell : void 0,
205
+ icon,
206
+ selected: icon.name === selected,
207
+ focusable: index === activeIndex,
208
+ position: index + 1,
209
+ total: icons.length,
210
+ onSelect,
211
+ onHover
212
+ }, icon.name);
213
+ })
214
+ })]
215
+ }), $[11] = activeCell, $[12] = activeIndex, $[13] = firstRow, $[14] = icons, $[15] = lastRow, $[16] = onClearSearch, $[17] = onHover, $[18] = onSelect, $[19] = props, $[20] = search, $[21] = selected, $[22] = totalRows, $[23] = t1;
216
+ } else t1 = $[23];
217
+ return t1;
63
218
  }
64
219
  function Recent(t0) {
65
- let $ = c(23), icons, onForget, onSelect, props, selected;
66
- $[0] === t0 ? (icons = $[1], onForget = $[2], onSelect = $[3], props = $[4], selected = $[5]) : ({icons, selected, onSelect, onForget, ...props} = t0, $[0] = t0, $[1] = icons, $[2] = onForget, $[3] = onSelect, $[4] = props, $[5] = selected);
220
+ let $ = c(26), icons, onForget, onHover, onSelect, props, selected;
221
+ $[0] === t0 ? (icons = $[1], onForget = $[2], onHover = $[3], onSelect = $[4], props = $[5], selected = $[6]) : ({icons, selected, onSelect, onHover, onForget, ...props} = t0, $[0] = t0, $[1] = icons, $[2] = onForget, $[3] = onHover, $[4] = onSelect, $[5] = props, $[6] = selected);
67
222
  let t1;
68
- $[6] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(Text, {
223
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(Text, {
69
224
  size: 1,
70
225
  weight: "medium",
71
226
  muted: !0,
72
227
  children: "Recent icons"
73
- }), $[6] = t1) : t1 = $[6];
228
+ }), $[7] = t1) : t1 = $[7];
74
229
  let t2;
75
- $[7] === onForget ? t2 = $[8] : (t2 = /* @__PURE__ */ jsxs(Flex, {
230
+ $[8] === onForget ? t2 = $[9] : (t2 = /* @__PURE__ */ jsxs(Flex, {
76
231
  align: "center",
77
232
  justify: "space-between",
78
233
  gap: 2,
@@ -83,50 +238,56 @@ function Recent(t0) {
83
238
  padding: 2,
84
239
  text: "Clear",
85
240
  onClick: onForget,
86
- "aria-label": "Forget the recently used icons."
241
+ "aria-label": "Forget the recently used icons"
87
242
  })]
88
- }), $[7] = onForget, $[8] = t2);
243
+ }), $[8] = onForget, $[9] = t2);
89
244
  let t3;
90
- if ($[9] !== icons || $[10] !== onSelect || $[11] !== selected) {
245
+ if ($[10] !== icons || $[11] !== onHover || $[12] !== onSelect || $[13] !== selected) {
91
246
  let t4;
92
- $[13] !== icons.length || $[14] !== onSelect || $[15] !== selected ? (t4 = (icon, index) => /* @__PURE__ */ jsx(Cell, {
247
+ $[15] !== icons.length || $[16] !== onHover || $[17] !== onSelect || $[18] !== selected ? (t4 = (icon, index) => /* @__PURE__ */ jsx(Cell, {
93
248
  icon,
94
249
  selected: icon.name === selected,
95
250
  focusable: !0,
96
251
  position: index + 1,
97
252
  total: icons.length,
98
- onSelect
99
- }, icon.name), $[13] = icons.length, $[14] = onSelect, $[15] = selected, $[16] = t4) : t4 = $[16], t3 = icons.map(t4), $[9] = icons, $[10] = onSelect, $[11] = selected, $[12] = t3;
100
- } else t3 = $[12];
253
+ onSelect,
254
+ onHover
255
+ }, icon.name), $[15] = icons.length, $[16] = onHover, $[17] = onSelect, $[18] = selected, $[19] = t4) : t4 = $[19], t3 = icons.map(t4), $[10] = icons, $[11] = onHover, $[12] = onSelect, $[13] = selected, $[14] = t3;
256
+ } else t3 = $[14];
101
257
  let t4;
102
- $[17] === t3 ? t4 = $[18] : (t4 = /* @__PURE__ */ jsx(Grid, {
258
+ $[20] === t3 ? t4 = $[21] : (t4 = /* @__PURE__ */ jsx(Grid, {
103
259
  role: "listbox",
104
260
  "aria-label": "Recent icons",
105
261
  gridTemplateColumns: 8,
106
262
  style: gridLayoutStyle,
107
263
  children: t3
108
- }), $[17] = t3, $[18] = t4);
264
+ }), $[20] = t3, $[21] = t4);
109
265
  let t5;
110
- return $[19] !== props || $[20] !== t2 || $[21] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, {
266
+ return $[22] !== props || $[23] !== t2 || $[24] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, {
111
267
  gap: 3,
112
268
  ...props,
113
269
  children: [t2, t4]
114
- }), $[19] = props, $[20] = t2, $[21] = t4, $[22] = t5) : t5 = $[22], t5;
270
+ }), $[22] = props, $[23] = t2, $[24] = t4, $[25] = t5) : t5 = $[25], t5;
115
271
  }
272
+ /**
273
+ * Gap between a tooltip and the cell it points at, given as margins because that is the only lever
274
+ * `@sanity/ui` offers for it. Top only, since a tooltip always sits above.
275
+ */
276
+ const tooltipMargins = [
277
+ -4,
278
+ 0,
279
+ 0,
280
+ 0
281
+ ];
116
282
  function Tooltip(t0) {
117
- let $ = c(14), hovered, props;
283
+ let $ = c(13), hovered, props;
118
284
  $[0] === t0 ? (hovered = $[1], props = $[2]) : ({hovered, ...props} = t0, $[0] = t0, $[1] = hovered, $[2] = props);
119
285
  let t1;
120
286
  $[3] === hovered ? t1 = $[4] : (t1 = isDefined(hovered), $[3] = hovered, $[4] = t1);
121
- let t2 = hovered?.element ?? null, t3, t4;
122
- $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = [
123
- -4,
124
- 0,
125
- 0,
126
- 0
127
- ], t4 = { pointerEvents: "none" }, $[5] = t3, $[6] = t4) : (t3 = $[5], t4 = $[6]);
128
- let t5;
129
- $[7] === hovered ? t5 = $[8] : (t5 = isDefined(hovered) && /* @__PURE__ */ jsxs(Stack, {
287
+ let t2 = hovered?.element ?? null, t3;
288
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = { pointerEvents: "none" }, $[5] = t3) : t3 = $[5];
289
+ let t4;
290
+ $[6] === hovered ? t4 = $[7] : (t4 = isDefined(hovered) && /* @__PURE__ */ jsxs(Stack, {
130
291
  gap: 3,
131
292
  style: { maxWidth: "16rem" },
132
293
  children: [/* @__PURE__ */ jsx(Text, {
@@ -138,26 +299,20 @@ function Tooltip(t0) {
138
299
  muted: !0,
139
300
  children: hovered.icon.tags
140
301
  })]
141
- }), $[7] = hovered, $[8] = t5);
142
- let t6;
143
- return $[9] !== props || $[10] !== t1 || $[11] !== t2 || $[12] !== t5 ? (t6 = /* @__PURE__ */ jsx(Popover, {
302
+ }), $[6] = hovered, $[7] = t4);
303
+ let t5;
304
+ return $[8] !== props || $[9] !== t1 || $[10] !== t2 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsx(Popover, {
144
305
  open: t1,
145
306
  referenceElement: t2,
146
307
  placement: "top",
147
308
  portal: !0,
148
309
  padding: 3,
149
- __unstable_margins: t3,
150
- style: t4,
151
- content: t5,
310
+ __unstable_margins: tooltipMargins,
311
+ style: t3,
312
+ content: t4,
152
313
  ...props
153
- }), $[9] = props, $[10] = t1, $[11] = t2, $[12] = t5, $[13] = t6) : t6 = $[13], t6;
314
+ }), $[8] = props, $[9] = t1, $[10] = t2, $[11] = t4, $[12] = t5) : t5 = $[12], t5;
154
315
  }
155
- /** Properties every icon the Studio draws is rendered with. */
156
- const defaultIconProps = {
157
- width: "1em",
158
- height: "1em",
159
- strokeWidth: 1.5
160
- };
161
316
  /**
162
317
  * Flattens text into the form a search compares against, so a hyphenated icon name and a multi-word
163
318
  * tag are matched the same way.
@@ -165,10 +320,26 @@ const defaultIconProps = {
165
320
  * @param value - The text to flatten.
166
321
  * @returns The text in comparable form.
167
322
  */
168
- function normaliseTerms(value) {
323
+ function normalizeTerms(value) {
169
324
  return value.toLowerCase().replaceAll(/[\s-]+/gu, " ").trim();
170
325
  }
171
326
  /**
327
+ * Narrows the library to a chosen set of icons, in the order they were named. A name the library does
328
+ * not recognise is skipped, so a set outlives the release it was written against.
329
+ *
330
+ * @param library - Every icon the library offers.
331
+ * @param names - Names of the icons to offer, or nothing to offer them all.
332
+ * @returns The icons on offer.
333
+ */
334
+ function selectIcons(library, names) {
335
+ if (!isDefined(names)) return library;
336
+ let byName = new Map(library.map((icon) => [icon.name, icon]));
337
+ return [...new Set(names)].flatMap((name) => {
338
+ let icon = byName.get(name);
339
+ return isDefined(icon) ? [icon] : [];
340
+ });
341
+ }
342
+ /**
172
343
  * Reads the icon library, pairing each drawing with the terms it can be found by. Both files come
173
344
  * from the same release as the icons themselves, so the drawings and their terms never disagree.
174
345
  *
@@ -185,15 +356,17 @@ async function readLibrary() {
185
356
  label: convertCase(name, "sentence"),
186
357
  tags: iconTags.join(", "),
187
358
  node,
188
- terms: normaliseTerms([name, ...iconTags].join(" "))
359
+ terms: normalizeTerms([name, ...iconTags].join(" "))
189
360
  }];
190
361
  });
191
362
  }
192
- /** The library once asked for, held so every field in a Studio session shares the one request. */
363
+ /**
364
+ * The library once asked for, held so every field in a Studio session shares the one request. It is a
365
+ * megabyte of data that never changes within a release, so asking twice only ever costs.
366
+ */
193
367
  let libraryRequest;
194
368
  /**
195
- * Reads the icon library, sharing a single request across every field opened in the session. The
196
- * library is a megabyte of data that never changes within a release, so asking twice only ever costs.
369
+ * Reads the icon library, waiting on whatever request is already under way.
197
370
  *
198
371
  * @returns Every icon the library offers.
199
372
  */
@@ -201,8 +374,8 @@ async function requestLibrary() {
201
374
  return libraryRequest ??= readLibrary(), await libraryRequest;
202
375
  }
203
376
  /**
204
- * Reads the icon library, sharing one request with every other field in the session. Callers mount
205
- * only while a picker is open, so a Studio that never opens one never pays the megabyte it costs.
377
+ * Reads the icon library. Callers mount only while a picker is open, so a Studio that never opens one
378
+ * never pays what it costs to read.
206
379
  *
207
380
  * @returns Every icon the library offers, or undefined while it is still being read.
208
381
  */
@@ -218,6 +391,46 @@ function useIconLibrary() {
218
391
  };
219
392
  }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1), library;
220
393
  }
394
+ /**
395
+ * Tracks which icon the cursor rests on, holding a tooltip back until it has settled somewhere.
396
+ *
397
+ * @param scrolling - Whether the grid is currently moving under the cursor.
398
+ * @returns The icon being hovered, alongside ways to follow the cursor and to dismiss it.
399
+ */
400
+ function useIconTooltip(scrolling) {
401
+ let $ = c(11), [hovered, setHovered] = useState(), hoverStart = useRef(void 0), t0, t1;
402
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => () => {
403
+ isDefined(hoverStart.current) && clearTimeout(hoverStart.current);
404
+ }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
405
+ let t2;
406
+ $[2] === hovered ? t2 = $[3] : (t2 = function clearHover() {
407
+ isDefined(hoverStart.current) && clearTimeout(hoverStart.current), isDefined(hovered) && setHovered(void 0);
408
+ }, $[2] = hovered, $[3] = t2);
409
+ let clearHover = t2, t3;
410
+ $[4] !== hovered || $[5] !== scrolling ? (t3 = function handleHover(icon, element) {
411
+ if (!(scrolling || element === hovered?.element)) {
412
+ if (isDefined(hoverStart.current) && clearTimeout(hoverStart.current), isDefined(hovered)) {
413
+ setHovered({
414
+ icon,
415
+ element
416
+ });
417
+ return;
418
+ }
419
+ hoverStart.current = setTimeout(() => {
420
+ setHovered({
421
+ icon,
422
+ element
423
+ });
424
+ }, 200);
425
+ }
426
+ }, $[4] = hovered, $[5] = scrolling, $[6] = t3) : t3 = $[6];
427
+ let handleHover = t3, t4;
428
+ return $[7] !== clearHover || $[8] !== handleHover || $[9] !== hovered ? (t4 = {
429
+ hovered,
430
+ handleHover,
431
+ clearHover
432
+ }, $[7] = clearHover, $[8] = handleHover, $[9] = hovered, $[10] = t4) : t4 = $[10], t4;
433
+ }
221
434
  /** Where the icons an author reached for last are kept, in the browser rather than the dataset. */
222
435
  const storageKey = "driftime:sanity-plugin-icon:recent";
223
436
  /**
@@ -306,36 +519,59 @@ function getVisibleRows(scrollRow, count) {
306
519
  lastRow: Math.min(totalRows, firstRow + 8 + 16)
307
520
  };
308
521
  }
522
+ /**
523
+ * Works out where the scrolling area sits to show a given icon in the middle, for opening on the
524
+ * icon already chosen.
525
+ *
526
+ * @param index - Index of the icon to show.
527
+ * @returns The position to scroll to.
528
+ */
529
+ function getCenteredScrollTop(index) {
530
+ return Math.max(0, Math.floor(index / 8) * 44 - 174);
531
+ }
532
+ /**
533
+ * Works out where the scrolling area moves to bring a given icon into view, staying put when the
534
+ * icon already shows. Taken from the index rather than the icon's own cell, since Home and End can
535
+ * land outside the rows that are mounted.
536
+ *
537
+ * @param index - Index of the icon to reveal.
538
+ * @param scrollTop - Position the scrolling area has reached.
539
+ * @returns The position to scroll to.
540
+ */
541
+ function getRevealedScrollTop(index, scrollTop) {
542
+ let top = Math.floor(index / 8) * 44;
543
+ return top < scrollTop ? top : top + 44 > scrollTop + 348 ? top + 44 - 348 : scrollTop;
544
+ }
309
545
  function Picker(t0) {
310
- let $ = c(28), onSelect, props, selected;
311
- $[0] === t0 ? (onSelect = $[1], props = $[2], selected = $[3]) : ({selected, onSelect, ...props} = t0, $[0] = t0, $[1] = onSelect, $[2] = props, $[3] = selected);
312
- let library = useIconLibrary(), { recent, remember, forget } = useRecentIcons(), [search, setSearch] = useState(""), [scrollRow, setScrollRow] = useState(0), [movedIndex, setMovedIndex] = useState(), [hovered, setHovered] = useState(), [scrolling, setScrolling] = useState(!1), scroller = useRef(null), activeCell = useRef(null), focusActiveCell = useRef(!1), scrollFrame = useRef(void 0), scrollStop = useRef(void 0), hoverStart = useRef(void 0), query = normaliseTerms(search), searching = isDefined(query), results = (library ?? []).filter((icon) => !searching || icon.terms.includes(query)), byName = new Map((library ?? []).map(_temp)), recentIcons = searching ? [] : recent.flatMap((entry) => {
546
+ let $ = c(35), allowed, onSelect, props, selected;
547
+ $[0] === t0 ? (allowed = $[1], onSelect = $[2], props = $[3], selected = $[4]) : ({allowed, selected, onSelect, ...props} = t0, $[0] = t0, $[1] = allowed, $[2] = onSelect, $[3] = props, $[4] = selected);
548
+ let library = useIconLibrary(), icons = selectIcons(library ?? [], allowed), { recent, remember, forget } = useRecentIcons(), [search, setSearch] = useState(""), [scrollRow, setScrollRow] = useState(0), [movedIndex, setMovedIndex] = useState(), [scrolling, setScrolling] = useState(!1), scroller = useRef(null), activeCell = useRef(null), focusIndex = useRef(void 0), scrollFrame = useRef(void 0), scrollStop = useRef(void 0), query = normalizeTerms(search), searching = isDefined(query), results = icons.filter((icon) => !searching || icon.terms.includes(query)), byName = new Map(icons.map(_temp)), recentIcons = searching ? [] : recent.flatMap((entry) => {
313
549
  let icon_1 = byName.get(entry);
314
550
  return isDefined(icon_1) ? [icon_1] : [];
315
- }), { totalRows, firstRow, lastRow } = getVisibleRows(scrollRow, results.length), visible = results.slice(firstRow * 8, lastRow * 8), selectedIndex = searching || !isDefined(library) || !isDefined(selected) ? -1 : library.findIndex((icon_2) => icon_2.name === selected), activeIndex = movedIndex ?? Math.max(0, selectedIndex), t1, t2;
316
- $[4] === selectedIndex ? (t1 = $[5], t2 = $[6]) : (t1 = () => {
551
+ }), { hovered, handleHover, clearHover } = useIconTooltip(scrolling), rows = getVisibleRows(scrollRow, results.length), selectedIndex = searching || !isDefined(selected) ? -1 : icons.findIndex((icon_2) => icon_2.name === selected), activeIndex = movedIndex ?? Math.max(0, selectedIndex);
552
+ useEffect(() => {
317
553
  let element = scroller.current;
318
- isDefined(element) && selectedIndex !== -1 && (element.scrollTop = Math.max(0, Math.floor(selectedIndex / 8) * 44 - 174));
319
- }, t2 = [selectedIndex], $[4] = selectedIndex, $[5] = t1, $[6] = t2), useEffect(t1, t2);
554
+ isDefined(element) && selectedIndex !== -1 && (element.scrollTop = getCenteredScrollTop(selectedIndex));
555
+ }, [scroller, selectedIndex]);
556
+ let t1, t2;
557
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => () => {
558
+ isDefined(scrollFrame.current) && cancelAnimationFrame(scrollFrame.current), isDefined(scrollStop.current) && clearTimeout(scrollStop.current);
559
+ }, t2 = [], $[5] = t1, $[6] = t2) : (t1 = $[5], t2 = $[6]), useEffect(t1, t2);
320
560
  let t3, t4;
321
- $[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => () => {
322
- isDefined(scrollFrame.current) && cancelAnimationFrame(scrollFrame.current), isDefined(scrollStop.current) && clearTimeout(scrollStop.current), isDefined(hoverStart.current) && clearTimeout(hoverStart.current);
323
- }, t4 = [], $[7] = t3, $[8] = t4) : (t3 = $[7], t4 = $[8]), useEffect(t3, t4);
561
+ $[7] === activeIndex ? (t3 = $[8], t4 = $[9]) : (t3 = () => {
562
+ focusIndex.current === activeIndex && (focusIndex.current = void 0, isDefined(activeCell.current) && activeCell.current.focus());
563
+ }, t4 = [activeIndex], $[7] = activeIndex, $[8] = t3, $[9] = t4), useEffect(t3, t4);
324
564
  let t5;
325
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t5 = () => {
326
- focusActiveCell.current && (focusActiveCell.current = !1, isDefined(activeCell.current) && activeCell.current.focus());
327
- }, $[9] = t5) : t5 = $[9];
328
- let t6;
329
- $[10] === activeIndex ? t6 = $[11] : (t6 = [activeIndex], $[10] = activeIndex, $[11] = t6), useEffect(t5, t6);
330
- let t7;
331
- $[12] !== onSelect || $[13] !== remember ? (t7 = function handleSelect(icon_3) {
565
+ $[10] !== onSelect || $[11] !== remember ? (t5 = function handleSelect(icon_3) {
332
566
  remember(icon_3.name), onSelect(icon_3);
333
- }, $[12] = onSelect, $[13] = remember, $[14] = t7) : t7 = $[14];
334
- let handleSelect = t7, t8;
335
- $[15] === Symbol.for("react.memo_cache_sentinel") ? (t8 = function handleSearch(event) {
567
+ }, $[10] = onSelect, $[11] = remember, $[12] = t5) : t5 = $[12];
568
+ let handleSelect = t5, t6;
569
+ $[13] === Symbol.for("react.memo_cache_sentinel") ? (t6 = function clearSearch() {
570
+ setSearch(""), setMovedIndex(void 0);
571
+ }, $[13] = t6) : t6 = $[13];
572
+ let clearSearch = t6, handleSearch = function handleSearch(event) {
336
573
  setSearch(event.currentTarget.value), setMovedIndex(void 0), isDefined(scroller.current) && (scroller.current.scrollTop = 0);
337
- }, $[15] = t8) : t8 = $[15];
338
- let handleSearch = t8, selectActive = function selectActive() {
574
+ }, selectActive = function selectActive() {
339
575
  let icon_4 = results[activeIndex];
340
576
  isDefined(icon_4) && handleSelect(icon_4);
341
577
  }, handleSearchKeyDown = function handleSearchKeyDown(event_0) {
@@ -344,71 +580,83 @@ function Picker(t0) {
344
580
  return;
345
581
  }
346
582
  event_0.key === "ArrowDown" && (event_0.preventDefault(), isDefined(activeCell.current) && activeCell.current.focus());
347
- }, t9;
348
- $[16] === scrolling ? t9 = $[17] : (t9 = function handleScroll() {
349
- isDefined(hoverStart.current) && clearTimeout(hoverStart.current), setHovered(void 0), scrolling || setScrolling(!0), isDefined(scrollStop.current) && clearTimeout(scrollStop.current), scrollStop.current = setTimeout(() => {
583
+ }, handleScroll = function handleScroll() {
584
+ clearHover(), scrolling || setScrolling(!0), isDefined(scrollStop.current) && clearTimeout(scrollStop.current), scrollStop.current = setTimeout(() => {
350
585
  setScrolling(!1);
351
586
  }, 150), !isDefined(scrollFrame.current) && (scrollFrame.current = requestAnimationFrame(() => {
352
587
  scrollFrame.current = void 0;
353
588
  let element_0 = scroller.current;
354
589
  isDefined(element_0) && setScrollRow(Math.floor(element_0.scrollTop / 44));
355
590
  }));
356
- }, $[16] = scrolling, $[17] = t9);
357
- let handleScroll = t9, handleHover = function handleHover(event_1) {
358
- if (scrolling) return;
359
- let target = event_1.target instanceof Element ? event_1.target.closest("[data-icon]") : void 0, cell = target instanceof HTMLElement ? target : void 0;
360
- if (cell === hovered?.element) return;
361
- let name = cell?.dataset.icon, icon_5 = isDefined(name) ? byName.get(name) : void 0;
362
- if (isDefined(hoverStart.current) && clearTimeout(hoverStart.current), !isDefined(icon_5) || !isDefined(cell)) {
363
- setHovered(void 0);
364
- return;
365
- }
366
- if (isDefined(hovered)) {
367
- setHovered({
368
- icon: icon_5,
369
- element: cell
370
- });
371
- return;
372
- }
373
- hoverStart.current = setTimeout(() => {
374
- setHovered({
375
- icon: icon_5,
376
- element: cell
377
- });
378
- }, 200);
379
- }, t10;
380
- $[18] === hovered ? t10 = $[19] : (t10 = function clearHover() {
381
- isDefined(hoverStart.current) && clearTimeout(hoverStart.current), isDefined(hovered) && setHovered(void 0);
382
- }, $[18] = hovered, $[19] = t10);
383
- let clearHover = t10, handleGridKeyDown = function handleGridKeyDown(event_2) {
591
+ }, handleGridKeyDown = function handleGridKeyDown(event_1) {
384
592
  let last = results.length - 1;
385
593
  if (last < 0) return;
386
- if (event_2.key === "Enter" || event_2.key === " ") {
387
- event_2.preventDefault(), selectActive();
594
+ if (event_1.key === "Enter" || event_1.key === " ") {
595
+ event_1.preventDefault(), selectActive();
388
596
  return;
389
597
  }
390
- let next = getNextIndex(event_2.key, activeIndex, last);
598
+ let next = getNextIndex(event_1.key, activeIndex, last);
391
599
  if (!isDefined(next)) return;
392
- event_2.preventDefault();
600
+ event_1.preventDefault();
393
601
  let index = Math.min(Math.max(next, 0), last);
394
- focusActiveCell.current = !0, setMovedIndex(index);
602
+ focusIndex.current = index, setMovedIndex(index);
395
603
  let element_1 = scroller.current;
396
- if (!isDefined(element_1)) return;
397
- let top = Math.floor(index / 8) * 44;
398
- top < element_1.scrollTop ? element_1.scrollTop = top : top + 44 > element_1.scrollTop + 348 && (element_1.scrollTop = top + 44 - 348);
399
- }, t11;
400
- $[20] === Symbol.for("react.memo_cache_sentinel") ? (t11 = /* @__PURE__ */ jsx(SearchIcon, { ...defaultIconProps }), $[20] = t11) : t11 = $[20];
401
- let t12;
402
- $[21] === library ? t12 = $[22] : (t12 = isDefined(library), $[21] = library, $[22] = t12);
403
- let t13;
404
- $[23] === library ? t13 = $[24] : (t13 = !isDefined(library) && /* @__PURE__ */ jsx(Flex, {
604
+ isDefined(element_1) && (element_1.scrollTop = getRevealedScrollTop(index, element_1.scrollTop));
605
+ }, t7;
606
+ $[14] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(SearchIcon, {}), $[14] = t7) : t7 = $[14];
607
+ let t8;
608
+ $[15] === library ? t8 = $[16] : (t8 = !isDefined(library) && /* @__PURE__ */ jsx(Flex, {
405
609
  align: "center",
406
610
  justify: "center",
407
611
  style: { height: 348 },
408
612
  children: /* @__PURE__ */ jsx(Spinner, { muted: !0 })
409
- }), $[23] = library, $[24] = t13);
410
- let t14 = hovered?.icon.name, t15;
411
- return $[25] !== hovered || $[26] !== t14 ? (t15 = /* @__PURE__ */ jsx(Tooltip, { hovered }, t14), $[25] = hovered, $[26] = t14, $[27] = t15) : t15 = $[27], /* @__PURE__ */ jsx(Dialog, {
613
+ }), $[15] = library, $[16] = t8);
614
+ let t9;
615
+ $[17] !== activeIndex || $[18] !== clearHover || $[19] !== clearSearch || $[20] !== handleGridKeyDown || $[21] !== handleHover || $[22] !== handleScroll || $[23] !== handleSelect || $[24] !== icons || $[25] !== library || $[26] !== results || $[27] !== rows || $[28] !== scroller || $[29] !== search || $[30] !== selected ? (t9 = isDefined(library) && /* @__PURE__ */ jsxs(Stack, {
616
+ gap: 3,
617
+ children: [
618
+ /* @__PURE__ */ jsx(Box, {
619
+ paddingY: 2,
620
+ children: /* @__PURE__ */ jsxs(Text, {
621
+ size: 1,
622
+ weight: "medium",
623
+ muted: !0,
624
+ children: [
625
+ "All icons (",
626
+ results.length.toLocaleString("en-US"),
627
+ ")"
628
+ ]
629
+ })
630
+ }),
631
+ icons.length === 0 && /* @__PURE__ */ jsx(Flex, {
632
+ align: "center",
633
+ justify: "center",
634
+ style: { height: 348 },
635
+ children: /* @__PURE__ */ jsx(Text, {
636
+ size: 1,
637
+ muted: !0,
638
+ children: "No icons are available to choose from."
639
+ })
640
+ }),
641
+ icons.length > 0 && /* @__PURE__ */ jsx(Library, {
642
+ ref: scroller,
643
+ icons: results,
644
+ rows,
645
+ selected,
646
+ activeIndex,
647
+ activeCell,
648
+ search,
649
+ onSelect: handleSelect,
650
+ onHover: handleHover,
651
+ onClearSearch: clearSearch,
652
+ onScroll: handleScroll,
653
+ onMouseLeave: clearHover,
654
+ onKeyDown: handleGridKeyDown
655
+ })
656
+ ]
657
+ }), $[17] = activeIndex, $[18] = clearHover, $[19] = clearSearch, $[20] = handleGridKeyDown, $[21] = handleHover, $[22] = handleScroll, $[23] = handleSelect, $[24] = icons, $[25] = library, $[26] = results, $[27] = rows, $[28] = scroller, $[29] = search, $[30] = selected, $[31] = t9) : t9 = $[31];
658
+ let t10 = hovered?.icon.name, t11;
659
+ return $[32] !== hovered || $[33] !== t10 ? (t11 = /* @__PURE__ */ jsx(Tooltip, { hovered }, t10), $[32] = hovered, $[33] = t10, $[34] = t11) : t11 = $[34], /* @__PURE__ */ jsx(Dialog, {
412
660
  header: "Select icon",
413
661
  width: 1,
414
662
  ...props,
@@ -417,94 +665,25 @@ function Picker(t0) {
417
665
  padding: 4,
418
666
  children: [
419
667
  /* @__PURE__ */ jsx(TextInput, {
420
- icon: t11,
668
+ icon: t7,
421
669
  placeholder: "Search by name or by what the icon depicts",
422
670
  value: search,
423
671
  onChange: handleSearch,
424
672
  onKeyDown: handleSearchKeyDown,
425
- disabled: !t12,
673
+ disabled: !isDefined(library) || icons.length === 0,
426
674
  "aria-label": "Search the icon library"
427
675
  }),
428
- t13,
676
+ t8,
429
677
  isDefined(recentIcons) && /* @__PURE__ */ jsx(Recent, {
430
678
  icons: recentIcons,
431
679
  selected,
432
680
  onSelect: handleSelect,
681
+ onHover: handleHover,
433
682
  onForget: forget,
434
- onMouseOver: handleHover,
435
683
  onMouseLeave: clearHover
436
684
  }),
437
- isDefined(library) && /* @__PURE__ */ jsxs(Stack, {
438
- gap: 3,
439
- children: [/* @__PURE__ */ jsx(Box, {
440
- paddingY: 2,
441
- children: /* @__PURE__ */ jsxs(Text, {
442
- size: 1,
443
- weight: "medium",
444
- muted: !0,
445
- children: [
446
- "All icons (",
447
- results.length.toLocaleString("en-GB"),
448
- ")"
449
- ]
450
- })
451
- }), /* @__PURE__ */ jsxs(Box, {
452
- ref: scroller,
453
- role: "listbox",
454
- "aria-label": "Icon library",
455
- onScroll: handleScroll,
456
- onMouseOver: handleHover,
457
- onMouseLeave: clearHover,
458
- onKeyDown: handleGridKeyDown,
459
- style: {
460
- height: 348,
461
- overflowY: "auto"
462
- },
463
- children: [results.length === 0 && /* @__PURE__ */ jsxs(Flex, {
464
- align: "center",
465
- justify: "center",
466
- direction: "column",
467
- gap: 3,
468
- style: { height: 348 },
469
- children: [/* @__PURE__ */ jsxs(Text, {
470
- size: 1,
471
- muted: !0,
472
- children: [
473
- "Nothing matches “",
474
- search,
475
- "”."
476
- ]
477
- }), /* @__PURE__ */ jsx(Button, {
478
- type: "button",
479
- mode: "ghost",
480
- text: "Clear search",
481
- onClick: () => {
482
- setSearch(""), setMovedIndex(void 0);
483
- }
484
- })]
485
- }), results.length > 0 && /* @__PURE__ */ jsx(Grid, {
486
- gridTemplateColumns: 8,
487
- style: {
488
- ...gridLayoutStyle,
489
- paddingTop: firstRow * 44,
490
- paddingBottom: (totalRows - lastRow) * 44
491
- },
492
- children: visible.map((icon_6, offset) => {
493
- let index_0 = firstRow * 8 + offset;
494
- return /* @__PURE__ */ jsx(Cell, {
495
- ref: index_0 === activeIndex ? activeCell : void 0,
496
- icon: icon_6,
497
- selected: icon_6.name === selected,
498
- focusable: index_0 === activeIndex,
499
- position: index_0 + 1,
500
- total: results.length,
501
- onSelect: handleSelect
502
- }, icon_6.name);
503
- })
504
- })]
505
- })]
506
- }),
507
- t15
685
+ t9,
686
+ t11
508
687
  ]
509
688
  })
510
689
  });
@@ -512,87 +691,6 @@ function Picker(t0) {
512
691
  function _temp(icon_0) {
513
692
  return [icon_0.name, icon_0];
514
693
  }
515
- /** Type name of the icon object. */
516
- const iconTypeName = "icon";
517
- function Input(t0) {
518
- let $ = c(28), { id, value, onChange, readOnly } = t0, { name, node } = value ?? {}, [open, setOpen] = useState(!1), selectedNode = resolveIconNode(node), selectedLabel = isDefined(name) ? convertCase(name, "sentence") : void 0, t1;
519
- $[0] !== onChange || $[1] !== setOpen ? (t1 = function handleSelect(icon) {
520
- onChange([
521
- setIfMissing({ _type: iconTypeName }),
522
- set(icon.name, ["name"]),
523
- set(serialiseIconNode(icon.node), ["node"])
524
- ]), setOpen(!1);
525
- }, $[0] = onChange, $[1] = setOpen, $[2] = t1) : t1 = $[2];
526
- let handleSelect = t1, T0 = Flex, T1 = Button, t5 = isDefined(selectedNode) ? /* @__PURE__ */ jsx(Drawing, {
527
- node: selectedNode,
528
- ...defaultIconProps
529
- }) : void 0, t6 = selectedLabel ?? "Select icon", t7;
530
- $[3] === setOpen ? t7 = $[4] : (t7 = () => {
531
- setOpen(!0);
532
- }, $[3] = setOpen, $[4] = t7);
533
- let t8 = isDefined(selectedLabel) ? `${selectedLabel} currently selected` : "Select icon", t9;
534
- $[5] !== T1 || $[6] !== id || $[7] !== readOnly || $[8] !== t5 || $[9] !== t6 || $[10] !== t7 || $[11] !== t8 ? (t9 = /* @__PURE__ */ jsx(T1, {
535
- id,
536
- type: "button",
537
- mode: "ghost",
538
- icon: t5,
539
- text: t6,
540
- disabled: readOnly,
541
- onClick: t7,
542
- "aria-label": t8
543
- }), $[5] = T1, $[6] = id, $[7] = readOnly, $[8] = t5, $[9] = t6, $[10] = t7, $[11] = t8, $[12] = t9) : t9 = $[12];
544
- let t10;
545
- $[13] !== onChange || $[14] !== readOnly || $[15] !== value ? (t10 = isDefined(value) && /* @__PURE__ */ jsx(Button, {
546
- type: "button",
547
- mode: "ghost",
548
- tone: "critical",
549
- icon: /* @__PURE__ */ jsx(CloseIcon, { ...defaultIconProps }),
550
- text: "Clear",
551
- disabled: readOnly,
552
- onClick: () => {
553
- onChange(unset());
554
- },
555
- "aria-label": "Clear the currently selected icon."
556
- }), $[13] = onChange, $[14] = readOnly, $[15] = value, $[16] = t10) : t10 = $[16];
557
- let t11;
558
- $[17] !== handleSelect || $[18] !== id || $[19] !== name || $[20] !== open || $[21] !== setOpen ? (t11 = open && /* @__PURE__ */ jsx(Picker, {
559
- id: `${id}-library`,
560
- selected: name,
561
- onSelect: handleSelect,
562
- onClose: () => {
563
- setOpen(!1);
564
- },
565
- onClickOutside: () => {
566
- setOpen(!1);
567
- }
568
- }), $[17] = handleSelect, $[18] = id, $[19] = name, $[20] = open, $[21] = setOpen, $[22] = t11) : t11 = $[22];
569
- let t12;
570
- return $[23] !== T0 || $[24] !== t10 || $[25] !== t11 || $[26] !== t9 ? (t12 = /* @__PURE__ */ jsxs(T0, {
571
- gap: 2,
572
- children: [
573
- t9,
574
- t10,
575
- t11
576
- ]
577
- }), $[23] = T0, $[24] = t10, $[25] = t11, $[26] = t9, $[27] = t12) : t12 = $[27], t12;
578
- }
579
- /**
580
- * Builds the media a stored icon previews with, so a document lists the drawing an author chose
581
- * rather than one placeholder standing in for every icon alike.
582
- *
583
- * @param value - The stored icon.
584
- * @returns The media component, or undefined when nothing readable was stored.
585
- * @public
586
- */
587
- function createIconPreview(value) {
588
- let node = resolveIconNode(value?.node);
589
- if (isDefined(node)) return function IconPreview() {
590
- return /* @__PURE__ */ jsx(Drawing, {
591
- node,
592
- ...defaultIconProps
593
- });
594
- };
595
- }
596
694
  function SquareDashedIcon(props) {
597
695
  let $ = c(14), t0, t1, t10, t11, t2, t3, t4, t5, t6, t7, t8, t9;
598
696
  $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("path", { d: "M5 3a2 2 0 0 0-2 2" }), t1 = /* @__PURE__ */ jsx("path", { d: "M19 3a2 2 0 0 1 2 2" }), t2 = /* @__PURE__ */ jsx("path", { d: "M21 19a2 2 0 0 1-2 2" }), t3 = /* @__PURE__ */ jsx("path", { d: "M5 21a2 2 0 0 1-2-2" }), t4 = /* @__PURE__ */ jsx("path", { d: "M9 3h1" }), t5 = /* @__PURE__ */ jsx("path", { d: "M9 21h1" }), t6 = /* @__PURE__ */ jsx("path", { d: "M14 3h1" }), t7 = /* @__PURE__ */ jsx("path", { d: "M14 21h1" }), t8 = /* @__PURE__ */ jsx("path", { d: "M3 9v1" }), t9 = /* @__PURE__ */ jsx("path", { d: "M21 9v1" }), t10 = /* @__PURE__ */ jsx("path", { d: "M3 14v1" }), t11 = /* @__PURE__ */ jsx("path", { d: "M21 14v1" }), $[0] = t0, $[1] = t1, $[2] = t10, $[3] = t11, $[4] = t2, $[5] = t3, $[6] = t4, $[7] = t5, $[8] = t6, $[9] = t7, $[10] = t8, $[11] = t9) : (t0 = $[0], t1 = $[1], t10 = $[2], t11 = $[3], t2 = $[4], t3 = $[5], t4 = $[6], t5 = $[7], t6 = $[8], t7 = $[9], t8 = $[10], t9 = $[11]);
@@ -625,61 +723,171 @@ function SquareDashedIcon(props) {
625
723
  }), $[12] = props, $[13] = t12), t12;
626
724
  }
627
725
  /**
628
- * Creates a Sanity Studio icon component from an SVG icon.
726
+ * Settles what an icon field offers. The list says what is on and replaces whatever the plugin was
727
+ * given, so one line tells you the whole answer.
629
728
  *
630
- * @param icon - The icon component to wrap.
631
- * @param props - Additional props merged over the default properties a Studio icon is drawn with.
632
- * @returns A Studio icon component.
729
+ * @param options - Options the field itself was given.
730
+ * @param config - Configuration the plugin was given.
731
+ * @returns The settings the field runs on.
633
732
  */
634
- function createSanityIcon(icon, props) {
635
- let Icon = icon;
636
- function SanityIcon() {
637
- return createElement(Icon, {
638
- ...defaultIconProps,
639
- ...props
640
- });
733
+ function resolveIconOptions(options, config) {
734
+ return { icons: options?.icons ?? config.icons };
735
+ }
736
+ /** Type name of the icon object. */
737
+ const iconTypeName = "icon";
738
+ /**
739
+ * Creates the input an icon field is drawn with, holding the configuration the plugin was given so a
740
+ * field naming its own icons replaces them rather than adding to them.
741
+ *
742
+ * @param config - Configuration every field falls back to.
743
+ * @returns The input component.
744
+ */
745
+ function createInput(config) {
746
+ function Input(t0) {
747
+ let $ = c(31), { id, schemaType, value, onChange, readOnly } = t0, { name, node } = value ?? {}, [open, setOpen] = useState(!1), t1;
748
+ $[0] === schemaType.options ? t1 = $[1] : (t1 = resolveIconOptions(schemaType.options, config), $[0] = schemaType.options, $[1] = t1);
749
+ let { icons } = t1, selectedNode = resolveIconNode(node), selectedLabel = isDefined(name) ? convertCase(name, "sentence") : void 0, t2;
750
+ $[2] !== onChange || $[3] !== setOpen ? (t2 = function handleSelect(icon) {
751
+ onChange([
752
+ setIfMissing({ _type: iconTypeName }),
753
+ set(icon.name, ["name"]),
754
+ set(serializeIconNode(icon.node), ["node"])
755
+ ]), setOpen(!1);
756
+ }, $[2] = onChange, $[3] = setOpen, $[4] = t2) : t2 = $[4];
757
+ let handleSelect = t2, T0 = Flex, T1 = Button, t6 = isDefined(selectedNode) ? /* @__PURE__ */ jsx(Drawing, {
758
+ node: selectedNode,
759
+ ...defaultIconProps
760
+ }) : /* @__PURE__ */ jsx(SquareDashedIcon, { ...defaultIconProps }), t7 = selectedLabel ?? "Select icon", t8;
761
+ $[5] === setOpen ? t8 = $[6] : (t8 = () => {
762
+ setOpen(!0);
763
+ }, $[5] = setOpen, $[6] = t8);
764
+ let t9 = isDefined(selectedLabel) ? `${selectedLabel} currently selected` : "Select icon", t10;
765
+ $[7] !== T1 || $[8] !== id || $[9] !== readOnly || $[10] !== t6 || $[11] !== t7 || $[12] !== t8 || $[13] !== t9 ? (t10 = /* @__PURE__ */ jsx(T1, {
766
+ id,
767
+ type: "button",
768
+ mode: "ghost",
769
+ icon: t6,
770
+ text: t7,
771
+ disabled: readOnly,
772
+ onClick: t8,
773
+ "aria-label": t9
774
+ }), $[7] = T1, $[8] = id, $[9] = readOnly, $[10] = t6, $[11] = t7, $[12] = t8, $[13] = t9, $[14] = t10) : t10 = $[14];
775
+ let t11;
776
+ $[15] !== onChange || $[16] !== readOnly || $[17] !== value ? (t11 = isDefined(value) && /* @__PURE__ */ jsx(Button, {
777
+ type: "button",
778
+ mode: "ghost",
779
+ tone: "critical",
780
+ icon: /* @__PURE__ */ jsx(CloseIcon, {}),
781
+ text: "Clear",
782
+ disabled: readOnly,
783
+ onClick: () => {
784
+ onChange(unset());
785
+ },
786
+ "aria-label": "Clear the currently selected icon"
787
+ }), $[15] = onChange, $[16] = readOnly, $[17] = value, $[18] = t11) : t11 = $[18];
788
+ let t12;
789
+ $[19] !== handleSelect || $[20] !== icons || $[21] !== id || $[22] !== name || $[23] !== open || $[24] !== setOpen ? (t12 = open && /* @__PURE__ */ jsx(Picker, {
790
+ id: `${id}-library`,
791
+ allowed: icons,
792
+ selected: name,
793
+ onSelect: handleSelect,
794
+ onClose: () => {
795
+ setOpen(!1);
796
+ },
797
+ onClickOutside: () => {
798
+ setOpen(!1);
799
+ }
800
+ }), $[19] = handleSelect, $[20] = icons, $[21] = id, $[22] = name, $[23] = open, $[24] = setOpen, $[25] = t12) : t12 = $[25];
801
+ let t13;
802
+ return $[26] !== T0 || $[27] !== t10 || $[28] !== t11 || $[29] !== t12 ? (t13 = /* @__PURE__ */ jsxs(T0, {
803
+ gap: 2,
804
+ children: [
805
+ t10,
806
+ t11,
807
+ t12
808
+ ]
809
+ }), $[26] = T0, $[27] = t10, $[28] = t11, $[29] = t12, $[30] = t13) : t13 = $[30], t13;
641
810
  }
642
- return SanityIcon;
811
+ return Input;
643
812
  }
644
- const iconType = defineType({
645
- name: iconTypeName,
646
- type: "object",
647
- icon: createSanityIcon(SquareDashedIcon),
648
- description: "Icon chosen from the Lucide library.",
649
- components: {
650
- field: Field,
651
- input: Input
652
- },
653
- preview: {
654
- select: {
655
- name: "name",
656
- node: "node"
813
+ /**
814
+ * Builds the media a stored icon previews with, so a document lists the drawing an author chose
815
+ * rather than one placeholder standing in for every icon alike.
816
+ *
817
+ * @param value - The stored icon.
818
+ * @returns The media component, or undefined when nothing readable was stored.
819
+ * @public
820
+ */
821
+ function createIconPreview(value) {
822
+ let node = resolveIconNode(value?.node);
823
+ if (isDefined(node)) return function IconPreview() {
824
+ return createElement(Drawing, {
825
+ node,
826
+ ...defaultIconProps
827
+ });
828
+ };
829
+ }
830
+ /**
831
+ * Creates the object type an icon is stored as, offering the icons it is given to every field that
832
+ * does not name its own.
833
+ *
834
+ * @param config - Configuration every field falls back to.
835
+ * @returns An object type definition for a stored icon.
836
+ */
837
+ function createIconType(config) {
838
+ return defineType({
839
+ name: iconTypeName,
840
+ type: "object",
841
+ icon: createSanityIcon(SquareDashedIcon),
842
+ description: "Icon chosen from the Lucide library.",
843
+ components: {
844
+ field: Field,
845
+ input: createInput(config)
657
846
  },
658
- prepare(selection) {
659
- let { name, node } = selection;
660
- return {
661
- title: isDefined(name) ? convertCase(name, "sentence") : "No icon",
662
- media: createIconPreview({
663
- _type: iconTypeName,
664
- name,
665
- node
666
- })
667
- };
668
- }
669
- },
670
- fields: [defineField({
671
- name: "name",
672
- type: "string",
673
- description: "Name of the chosen icon in the library it was taken from."
674
- }), defineField({
675
- name: "node",
676
- type: "text",
677
- description: "Shapes the icon is drawn from, written when the icon is chosen."
678
- })]
679
- }), iconPlugin = definePlugin({
847
+ validation: (rule) => rule.custom((value) => !isDefined(value?.name) || isDefined(value.node) ? !0 : "Select the icon again so its drawing is stored."),
848
+ preview: {
849
+ select: {
850
+ name: "name",
851
+ node: "node"
852
+ },
853
+ prepare(selection) {
854
+ let { name, node } = selection;
855
+ return {
856
+ title: isDefined(name) ? convertCase(name, "sentence") : "No icon",
857
+ media: createIconPreview({
858
+ _type: iconTypeName,
859
+ name,
860
+ node
861
+ })
862
+ };
863
+ }
864
+ },
865
+ fields: [defineField({
866
+ name: "name",
867
+ type: "string",
868
+ description: "Name of the chosen icon in the library it was taken from."
869
+ }), defineField({
870
+ name: "node",
871
+ type: "text",
872
+ description: "Shapes the icon is drawn from, written when the icon is chosen."
873
+ })]
874
+ });
875
+ }
876
+ const plugin = definePlugin((config) => ({
680
877
  name: "@driftime/sanity-plugin-icon",
681
- schema: { types: [iconType] }
682
- });
878
+ schema: { types: [createIconType(config)] }
879
+ }));
880
+ /**
881
+ * Creates the icon field type for Sanity Studio, offering the Lucide library through a searchable
882
+ * picker and storing the chosen drawing ready to render.
883
+ *
884
+ * @param config - Plugin configuration.
885
+ * @returns Sanity plugin definition.
886
+ * @public
887
+ */
888
+ function iconPlugin(config = {}) {
889
+ return plugin(config);
890
+ }
683
891
  export { createIconPreview, iconPlugin };
684
892
 
685
893
  //# sourceMappingURL=index.js.map