@driftime/sanity-plugin-icon 0.1.0 → 0.2.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
@@ -61,6 +61,66 @@ function Cell(t0) {
61
61
  ...props
62
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;
63
63
  }
64
+ function Library(t0) {
65
+ let $ = c(27), activeCell, activeIndex, icons, onClearSearch, onSelect, props, rows, search, selected;
66
+ $[0] === t0 ? (activeCell = $[1], activeIndex = $[2], icons = $[3], onClearSearch = $[4], onSelect = $[5], props = $[6], rows = $[7], search = $[8], selected = $[9]) : ({icons, rows, selected, activeIndex, activeCell, search, onSelect, onClearSearch, ...props} = t0, $[0] = t0, $[1] = activeCell, $[2] = activeIndex, $[3] = icons, $[4] = onClearSearch, $[5] = onSelect, $[6] = props, $[7] = rows, $[8] = search, $[9] = selected);
67
+ let { totalRows, firstRow, lastRow } = rows, t1;
68
+ if ($[10] !== activeCell || $[11] !== activeIndex || $[12] !== firstRow || $[13] !== icons || $[14] !== lastRow || $[15] !== onClearSearch || $[16] !== onSelect || $[17] !== props || $[18] !== search || $[19] !== selected || $[20] !== totalRows) {
69
+ let visible = icons.slice(firstRow * 8, lastRow * 8), t2;
70
+ $[22] === Symbol.for("react.memo_cache_sentinel") ? (t2 = {
71
+ height: 348,
72
+ overflowY: "auto"
73
+ }, $[22] = t2) : t2 = $[22];
74
+ let t3;
75
+ $[23] !== icons.length || $[24] !== onClearSearch || $[25] !== search ? (t3 = icons.length === 0 && /* @__PURE__ */ jsxs(Flex, {
76
+ align: "center",
77
+ justify: "center",
78
+ direction: "column",
79
+ gap: 3,
80
+ style: { height: 348 },
81
+ children: [/* @__PURE__ */ jsxs(Text, {
82
+ size: 1,
83
+ muted: !0,
84
+ children: [
85
+ "Nothing matches “",
86
+ search,
87
+ "”."
88
+ ]
89
+ }), /* @__PURE__ */ jsx(Button, {
90
+ type: "button",
91
+ mode: "ghost",
92
+ text: "Clear search",
93
+ onClick: onClearSearch
94
+ })]
95
+ }), $[23] = icons.length, $[24] = onClearSearch, $[25] = search, $[26] = t3) : t3 = $[26], t1 = /* @__PURE__ */ jsxs(Box, {
96
+ role: "listbox",
97
+ "aria-label": "Icon library",
98
+ style: t2,
99
+ ...props,
100
+ children: [t3, icons.length > 0 && /* @__PURE__ */ jsx(Grid, {
101
+ gridTemplateColumns: 8,
102
+ style: {
103
+ ...gridLayoutStyle,
104
+ paddingTop: firstRow * 44,
105
+ paddingBottom: (totalRows - lastRow) * 44
106
+ },
107
+ children: visible.map((icon, offset) => {
108
+ let index = firstRow * 8 + offset;
109
+ return /* @__PURE__ */ jsx(Cell, {
110
+ ref: index === activeIndex ? activeCell : void 0,
111
+ icon,
112
+ selected: icon.name === selected,
113
+ focusable: index === activeIndex,
114
+ position: index + 1,
115
+ total: icons.length,
116
+ onSelect
117
+ }, icon.name);
118
+ })
119
+ })]
120
+ }), $[10] = activeCell, $[11] = activeIndex, $[12] = firstRow, $[13] = icons, $[14] = lastRow, $[15] = onClearSearch, $[16] = onSelect, $[17] = props, $[18] = search, $[19] = selected, $[20] = totalRows, $[21] = t1;
121
+ } else t1 = $[21];
122
+ return t1;
123
+ }
64
124
  function Recent(t0) {
65
125
  let $ = c(23), icons, onForget, onSelect, props, selected;
66
126
  $[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);
@@ -169,6 +229,22 @@ function normaliseTerms(value) {
169
229
  return value.toLowerCase().replaceAll(/[\s-]+/gu, " ").trim();
170
230
  }
171
231
  /**
232
+ * Narrows the library to a chosen set of icons, in the order they were named. A name the library does
233
+ * not recognise is skipped, so a set outlives the release it was written against.
234
+ *
235
+ * @param library - Every icon the library offers.
236
+ * @param names - Names of the icons to offer, or nothing to offer them all.
237
+ * @returns The icons on offer.
238
+ */
239
+ function selectIcons(library, names) {
240
+ if (!isDefined(names)) return library;
241
+ let byName = new Map(library.map((icon) => [icon.name, icon]));
242
+ return [...new Set(names)].flatMap((name) => {
243
+ let icon = byName.get(name);
244
+ return isDefined(icon) ? [icon] : [];
245
+ });
246
+ }
247
+ /**
172
248
  * Reads the icon library, pairing each drawing with the terms it can be found by. Both files come
173
249
  * from the same release as the icons themselves, so the drawings and their terms never disagree.
174
250
  *
@@ -218,6 +294,53 @@ function useIconLibrary() {
218
294
  };
219
295
  }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1), library;
220
296
  }
297
+ /**
298
+ * Tracks which icon the cursor rests on, holding a tooltip back until it has settled somewhere.
299
+ *
300
+ * @param byName - Every icon the library offers, keyed by the name it goes by.
301
+ * @param scrolling - Whether the grid is currently moving under the cursor.
302
+ * @returns The icon being hovered, alongside ways to follow the cursor and to dismiss it.
303
+ */
304
+ function useIconTooltip(byName, scrolling) {
305
+ let $ = c(12), [hovered, setHovered] = useState(), hoverStart = useRef(void 0), t0, t1;
306
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => () => {
307
+ isDefined(hoverStart.current) && clearTimeout(hoverStart.current);
308
+ }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
309
+ let t2;
310
+ $[2] === hovered ? t2 = $[3] : (t2 = function clearHover() {
311
+ isDefined(hoverStart.current) && clearTimeout(hoverStart.current), isDefined(hovered) && setHovered(void 0);
312
+ }, $[2] = hovered, $[3] = t2);
313
+ let clearHover = t2, t3;
314
+ $[4] !== byName || $[5] !== hovered || $[6] !== scrolling ? (t3 = function handleHover(event) {
315
+ if (scrolling) return;
316
+ let target = event.target instanceof Element ? event.target.closest("[data-icon]") : void 0, cell = target instanceof HTMLElement ? target : void 0;
317
+ if (cell === hovered?.element) return;
318
+ let name = cell?.dataset.icon, icon = isDefined(name) ? byName.get(name) : void 0;
319
+ if (isDefined(hoverStart.current) && clearTimeout(hoverStart.current), !isDefined(icon) || !isDefined(cell)) {
320
+ setHovered(void 0);
321
+ return;
322
+ }
323
+ if (isDefined(hovered)) {
324
+ setHovered({
325
+ icon,
326
+ element: cell
327
+ });
328
+ return;
329
+ }
330
+ hoverStart.current = setTimeout(() => {
331
+ setHovered({
332
+ icon,
333
+ element: cell
334
+ });
335
+ }, 200);
336
+ }, $[4] = byName, $[5] = hovered, $[6] = scrolling, $[7] = t3) : t3 = $[7];
337
+ let handleHover = t3, t4;
338
+ return $[8] !== clearHover || $[9] !== handleHover || $[10] !== hovered ? (t4 = {
339
+ hovered,
340
+ handleHover,
341
+ clearHover
342
+ }, $[8] = clearHover, $[9] = handleHover, $[10] = hovered, $[11] = t4) : t4 = $[11], t4;
343
+ }
221
344
  /** Where the icons an author reached for last are kept, in the browser rather than the dataset. */
222
345
  const storageKey = "driftime:sanity-plugin-icon:recent";
223
346
  /**
@@ -306,36 +429,61 @@ function getVisibleRows(scrollRow, count) {
306
429
  lastRow: Math.min(totalRows, firstRow + 8 + 16)
307
430
  };
308
431
  }
432
+ /**
433
+ * Works out where the scrolling area sits to show a given icon in the middle, for opening on the
434
+ * icon already chosen.
435
+ *
436
+ * @param index - Index of the icon to show.
437
+ * @returns The position to scroll to.
438
+ */
439
+ function getCentredScrollTop(index) {
440
+ return Math.max(0, Math.floor(index / 8) * 44 - 174);
441
+ }
442
+ /**
443
+ * Works out where the scrolling area moves to bring a given icon into view, staying put when the
444
+ * icon already shows. Taken from the index rather than the icon's own cell, since Home and End can
445
+ * land outside the rows that are mounted.
446
+ *
447
+ * @param index - Index of the icon to reveal.
448
+ * @param scrollTop - Position the scrolling area has reached.
449
+ * @returns The position to scroll to.
450
+ */
451
+ function getRevealedScrollTop(index, scrollTop) {
452
+ let top = Math.floor(index / 8) * 44;
453
+ return top < scrollTop ? top : top + 44 > scrollTop + 348 ? top + 44 - 348 : scrollTop;
454
+ }
309
455
  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) => {
456
+ let $ = c(35), allowed, onSelect, props, selected;
457
+ $[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);
458
+ 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), focusActiveCell = useRef(!1), scrollFrame = useRef(void 0), scrollStop = useRef(void 0), query = normaliseTerms(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
459
  let icon_1 = byName.get(entry);
314
460
  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 = () => {
461
+ }), { hovered, handleHover, clearHover } = useIconTooltip(byName, 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);
462
+ useEffect(() => {
317
463
  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);
320
- 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);
324
- let t5;
325
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t5 = () => {
464
+ isDefined(element) && selectedIndex !== -1 && (element.scrollTop = getCentredScrollTop(selectedIndex));
465
+ }, [selectedIndex]);
466
+ let t1, t2;
467
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => () => {
468
+ isDefined(scrollFrame.current) && cancelAnimationFrame(scrollFrame.current), isDefined(scrollStop.current) && clearTimeout(scrollStop.current);
469
+ }, t2 = [], $[5] = t1, $[6] = t2) : (t1 = $[5], t2 = $[6]), useEffect(t1, t2);
470
+ let t3;
471
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => {
326
472
  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) {
473
+ }, $[7] = t3) : t3 = $[7];
474
+ let t4;
475
+ $[8] === activeIndex ? t4 = $[9] : (t4 = [activeIndex], $[8] = activeIndex, $[9] = t4), useEffect(t3, t4);
476
+ let t5;
477
+ $[10] !== onSelect || $[11] !== remember ? (t5 = function handleSelect(icon_3) {
332
478
  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) {
479
+ }, $[10] = onSelect, $[11] = remember, $[12] = t5) : t5 = $[12];
480
+ let handleSelect = t5, t6;
481
+ $[13] === Symbol.for("react.memo_cache_sentinel") ? (t6 = function clearSearch() {
482
+ setSearch(""), setMovedIndex(void 0);
483
+ }, $[13] = t6) : t6 = $[13];
484
+ let clearSearch = t6, handleSearch = function handleSearch(event) {
336
485
  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() {
486
+ }, selectActive = function selectActive() {
339
487
  let icon_4 = results[activeIndex];
340
488
  isDefined(icon_4) && handleSelect(icon_4);
341
489
  }, handleSearchKeyDown = function handleSearchKeyDown(event_0) {
@@ -344,71 +492,83 @@ function Picker(t0) {
344
492
  return;
345
493
  }
346
494
  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(() => {
495
+ }, handleScroll = function handleScroll() {
496
+ clearHover(), scrolling || setScrolling(!0), isDefined(scrollStop.current) && clearTimeout(scrollStop.current), scrollStop.current = setTimeout(() => {
350
497
  setScrolling(!1);
351
498
  }, 150), !isDefined(scrollFrame.current) && (scrollFrame.current = requestAnimationFrame(() => {
352
499
  scrollFrame.current = void 0;
353
500
  let element_0 = scroller.current;
354
501
  isDefined(element_0) && setScrollRow(Math.floor(element_0.scrollTop / 44));
355
502
  }));
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) {
503
+ }, handleGridKeyDown = function handleGridKeyDown(event_1) {
384
504
  let last = results.length - 1;
385
505
  if (last < 0) return;
386
- if (event_2.key === "Enter" || event_2.key === " ") {
387
- event_2.preventDefault(), selectActive();
506
+ if (event_1.key === "Enter" || event_1.key === " ") {
507
+ event_1.preventDefault(), selectActive();
388
508
  return;
389
509
  }
390
- let next = getNextIndex(event_2.key, activeIndex, last);
510
+ let next = getNextIndex(event_1.key, activeIndex, last);
391
511
  if (!isDefined(next)) return;
392
- event_2.preventDefault();
512
+ event_1.preventDefault();
393
513
  let index = Math.min(Math.max(next, 0), last);
394
514
  focusActiveCell.current = !0, setMovedIndex(index);
395
515
  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, {
516
+ isDefined(element_1) && (element_1.scrollTop = getRevealedScrollTop(index, element_1.scrollTop));
517
+ }, t7;
518
+ $[14] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(SearchIcon, { ...defaultIconProps }), $[14] = t7) : t7 = $[14];
519
+ let t8;
520
+ $[15] === library ? t8 = $[16] : (t8 = !isDefined(library) && /* @__PURE__ */ jsx(Flex, {
405
521
  align: "center",
406
522
  justify: "center",
407
523
  style: { height: 348 },
408
524
  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, {
525
+ }), $[15] = library, $[16] = t8);
526
+ let t9;
527
+ $[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, {
528
+ gap: 3,
529
+ children: [
530
+ /* @__PURE__ */ jsx(Box, {
531
+ paddingY: 2,
532
+ children: /* @__PURE__ */ jsxs(Text, {
533
+ size: 1,
534
+ weight: "medium",
535
+ muted: !0,
536
+ children: [
537
+ "All icons (",
538
+ results.length.toLocaleString("en-GB"),
539
+ ")"
540
+ ]
541
+ })
542
+ }),
543
+ icons.length === 0 && /* @__PURE__ */ jsx(Flex, {
544
+ align: "center",
545
+ justify: "center",
546
+ style: { height: 348 },
547
+ children: /* @__PURE__ */ jsx(Text, {
548
+ size: 1,
549
+ muted: !0,
550
+ children: "No icons are available to choose from."
551
+ })
552
+ }),
553
+ icons.length > 0 && /* @__PURE__ */ jsx(Library, {
554
+ ref: scroller,
555
+ icons: results,
556
+ rows,
557
+ selected,
558
+ activeIndex,
559
+ activeCell,
560
+ search,
561
+ onSelect: handleSelect,
562
+ onClearSearch: clearSearch,
563
+ onScroll: handleScroll,
564
+ onMouseOver: handleHover,
565
+ onMouseLeave: clearHover,
566
+ onKeyDown: handleGridKeyDown
567
+ })
568
+ ]
569
+ }), $[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];
570
+ let t10 = hovered?.icon.name, t11;
571
+ return $[32] !== hovered || $[33] !== t10 ? (t11 = /* @__PURE__ */ jsx(Tooltip, { hovered }, t10), $[32] = hovered, $[33] = t10, $[34] = t11) : t11 = $[34], /* @__PURE__ */ jsx(Dialog, {
412
572
  header: "Select icon",
413
573
  width: 1,
414
574
  ...props,
@@ -417,15 +577,15 @@ function Picker(t0) {
417
577
  padding: 4,
418
578
  children: [
419
579
  /* @__PURE__ */ jsx(TextInput, {
420
- icon: t11,
580
+ icon: t7,
421
581
  placeholder: "Search by name or by what the icon depicts",
422
582
  value: search,
423
583
  onChange: handleSearch,
424
584
  onKeyDown: handleSearchKeyDown,
425
- disabled: !t12,
585
+ disabled: !isDefined(library) || icons.length === 0,
426
586
  "aria-label": "Search the icon library"
427
587
  }),
428
- t13,
588
+ t8,
429
589
  isDefined(recentIcons) && /* @__PURE__ */ jsx(Recent, {
430
590
  icons: recentIcons,
431
591
  selected,
@@ -434,77 +594,8 @@ function Picker(t0) {
434
594
  onMouseOver: handleHover,
435
595
  onMouseLeave: clearHover
436
596
  }),
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
597
+ t9,
598
+ t11
508
599
  ]
509
600
  })
510
601
  });
@@ -514,84 +605,78 @@ function _temp(icon_0) {
514
605
  }
515
606
  /** Type name of the icon object. */
516
607
  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
608
  /**
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.
609
+ * Creates the input an icon field is drawn with, holding the icons the plugin was configured with so
610
+ * a field naming its own replaces them rather than adding to them.
582
611
  *
583
- * @param value - The stored icon.
584
- * @returns The media component, or undefined when nothing readable was stored.
585
- * @public
612
+ * @param icons - Icons every field offers, or nothing to offer them all.
613
+ * @returns The input component.
586
614
  */
587
- function createIconPreview(value) {
588
- let node = resolveIconNode(value?.node);
589
- if (isDefined(node)) return function IconPreview() {
590
- return /* @__PURE__ */ jsx(Drawing, {
591
- node,
615
+ function createInput(icons) {
616
+ function Input(t0) {
617
+ let $ = c(29), { id, schemaType, value, onChange, readOnly } = t0, { name, node } = value ?? {}, [open, setOpen] = useState(!1), allowed = schemaType.options?.icons ?? icons, selectedNode = resolveIconNode(node), selectedLabel = isDefined(name) ? convertCase(name, "sentence") : void 0, t1;
618
+ $[0] !== onChange || $[1] !== setOpen ? (t1 = function handleSelect(icon) {
619
+ onChange([
620
+ setIfMissing({ _type: iconTypeName }),
621
+ set(icon.name, ["name"]),
622
+ set(serialiseIconNode(icon.node), ["node"])
623
+ ]), setOpen(!1);
624
+ }, $[0] = onChange, $[1] = setOpen, $[2] = t1) : t1 = $[2];
625
+ let handleSelect = t1, T0 = Flex, T1 = Button, t5 = isDefined(selectedNode) ? /* @__PURE__ */ jsx(Drawing, {
626
+ node: selectedNode,
592
627
  ...defaultIconProps
593
- });
594
- };
628
+ }) : void 0, t6 = selectedLabel ?? "Select icon", t7;
629
+ $[3] === setOpen ? t7 = $[4] : (t7 = () => {
630
+ setOpen(!0);
631
+ }, $[3] = setOpen, $[4] = t7);
632
+ let t8 = isDefined(selectedLabel) ? `${selectedLabel} currently selected` : "Select icon", t9;
633
+ $[5] !== T1 || $[6] !== id || $[7] !== readOnly || $[8] !== t5 || $[9] !== t6 || $[10] !== t7 || $[11] !== t8 ? (t9 = /* @__PURE__ */ jsx(T1, {
634
+ id,
635
+ type: "button",
636
+ mode: "ghost",
637
+ icon: t5,
638
+ text: t6,
639
+ disabled: readOnly,
640
+ onClick: t7,
641
+ "aria-label": t8
642
+ }), $[5] = T1, $[6] = id, $[7] = readOnly, $[8] = t5, $[9] = t6, $[10] = t7, $[11] = t8, $[12] = t9) : t9 = $[12];
643
+ let t10;
644
+ $[13] !== onChange || $[14] !== readOnly || $[15] !== value ? (t10 = isDefined(value) && /* @__PURE__ */ jsx(Button, {
645
+ type: "button",
646
+ mode: "ghost",
647
+ tone: "critical",
648
+ icon: /* @__PURE__ */ jsx(CloseIcon, { ...defaultIconProps }),
649
+ text: "Clear",
650
+ disabled: readOnly,
651
+ onClick: () => {
652
+ onChange(unset());
653
+ },
654
+ "aria-label": "Clear the currently selected icon."
655
+ }), $[13] = onChange, $[14] = readOnly, $[15] = value, $[16] = t10) : t10 = $[16];
656
+ let t11;
657
+ $[17] !== allowed || $[18] !== handleSelect || $[19] !== id || $[20] !== name || $[21] !== open || $[22] !== setOpen ? (t11 = open && /* @__PURE__ */ jsx(Picker, {
658
+ id: `${id}-library`,
659
+ allowed,
660
+ selected: name,
661
+ onSelect: handleSelect,
662
+ onClose: () => {
663
+ setOpen(!1);
664
+ },
665
+ onClickOutside: () => {
666
+ setOpen(!1);
667
+ }
668
+ }), $[17] = allowed, $[18] = handleSelect, $[19] = id, $[20] = name, $[21] = open, $[22] = setOpen, $[23] = t11) : t11 = $[23];
669
+ let t12;
670
+ return $[24] !== T0 || $[25] !== t10 || $[26] !== t11 || $[27] !== t9 ? (t12 = /* @__PURE__ */ jsxs(T0, {
671
+ gap: 2,
672
+ children: [
673
+ t9,
674
+ t10,
675
+ t11
676
+ ]
677
+ }), $[24] = T0, $[25] = t10, $[26] = t11, $[27] = t9, $[28] = t12) : t12 = $[28], t12;
678
+ }
679
+ return Input;
595
680
  }
596
681
  function SquareDashedIcon(props) {
597
682
  let $ = c(14), t0, t1, t10, t11, t2, t3, t4, t5, t6, t7, t8, t9;
@@ -641,45 +726,87 @@ function createSanityIcon(icon, props) {
641
726
  }
642
727
  return SanityIcon;
643
728
  }
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"
729
+ /**
730
+ * Builds the media a stored icon previews with, so a document lists the drawing an author chose
731
+ * rather than one placeholder standing in for every icon alike.
732
+ *
733
+ * @param value - The stored icon.
734
+ * @returns The media component, or undefined when nothing readable was stored.
735
+ * @public
736
+ */
737
+ function createIconPreview(value) {
738
+ let node = resolveIconNode(value?.node);
739
+ if (isDefined(node)) return function IconPreview() {
740
+ return createElement(Drawing, {
741
+ node,
742
+ ...defaultIconProps
743
+ });
744
+ };
745
+ }
746
+ /**
747
+ * Creates the object type an icon is stored as, offering the icons it is given to every field that
748
+ * does not name its own.
749
+ *
750
+ * @param icons - Icons every field offers, or nothing to offer them all.
751
+ * @returns An object type definition for a stored icon.
752
+ */
753
+ function createIconType(icons) {
754
+ return defineType({
755
+ name: iconTypeName,
756
+ type: "object",
757
+ icon: createSanityIcon(SquareDashedIcon),
758
+ description: "Icon chosen from the Lucide library.",
759
+ components: {
760
+ field: Field,
761
+ input: createInput(icons)
657
762
  },
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({
680
- name: "@driftime/sanity-plugin-icon",
681
- schema: { types: [iconType] }
763
+ preview: {
764
+ select: {
765
+ name: "name",
766
+ node: "node"
767
+ },
768
+ prepare(selection) {
769
+ let { name, node } = selection;
770
+ return {
771
+ title: isDefined(name) ? convertCase(name, "sentence") : "No icon",
772
+ media: createIconPreview({
773
+ _type: iconTypeName,
774
+ name,
775
+ node
776
+ })
777
+ };
778
+ }
779
+ },
780
+ fields: [defineField({
781
+ name: "name",
782
+ type: "string",
783
+ description: "Name of the chosen icon in the library it was taken from."
784
+ }), defineField({
785
+ name: "node",
786
+ type: "text",
787
+ description: "Shapes the icon is drawn from, written when the icon is chosen."
788
+ })]
789
+ });
790
+ }
791
+ /** The plugin as Sanity defines it, wrapped below so that its configuration can genuinely be left out. */
792
+ const plugin = definePlugin((config) => {
793
+ let { icons } = config;
794
+ return {
795
+ name: "@driftime/sanity-plugin-icon",
796
+ schema: { types: [createIconType(icons)] }
797
+ };
682
798
  });
799
+ /**
800
+ * Creates the icon field type for Sanity Studio, offering the Lucide library through a searchable
801
+ * picker and storing the chosen drawing ready to render.
802
+ *
803
+ * @param config - Plugin configuration.
804
+ * @returns Sanity plugin definition.
805
+ * @public
806
+ */
807
+ function iconPlugin(config = {}) {
808
+ return plugin(config);
809
+ }
683
810
  export { createIconPreview, iconPlugin };
684
811
 
685
812
  //# sourceMappingURL=index.js.map