@nice2dev/icons 1.3.8 → 1.3.9

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.
@@ -3,19 +3,45 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var uiCore = require('@nice2dev/ui-core');
5
5
  var React = require('react');
6
+ var iconHtml = require('./iconHtml.js');
6
7
  var actions = require('./icons/actions.js');
7
8
  var files = require('./icons/files.js');
8
9
  var media = require('./icons/media.js');
9
10
  var navigation = require('./icons/navigation.js');
10
11
  var ui = require('./icons/ui.js');
12
+ var iconStack = require('./iconStack.js');
13
+ var NiceIconStacker = require('./NiceIconStacker.js');
11
14
 
12
15
  const MAX_HISTORY_ITEMS = 20;
16
+ /** `useLayoutEffect` in the browser, `useEffect` on the server (no warning there). */
17
+ const useIsoLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;
13
18
  /* ─── Small icons: the package's own (until 1.2.0 these were pasted SVGs) ─── */
14
19
  const Chevron = () => jsxRuntime.jsx(navigation.NtdChevronDown, { size: 12, variant: "outline" });
15
20
  const SearchIcon = () => jsxRuntime.jsx(actions.NtdSearch, { size: 14, variant: "outline" });
16
21
  const StarIcon = ({ filled }) => (jsxRuntime.jsx(ui.NtdStar, { size: 12, variant: filled ? 'solid' : 'outline' }));
17
22
  const ClockIcon = () => jsxRuntime.jsx(ui.NtdClock, { size: 12, variant: "outline" });
18
23
  const CheckIcon = () => jsxRuntime.jsx(actions.NtdCheck, { size: 10, variant: "outline" });
24
+ const NO_NAMES = [];
25
+ const NO_LAYERS = [];
26
+ /** The accent the picker draws with: the page's background, white without a theme. */
27
+ const PAGE_ACCENT = 'var(--nice-bg-primary, white)';
28
+ /** An entry's name as shown: its label, else the export name without `Ntd`. */
29
+ const entryLabel = (entry) => { var _a; return (_a = entry.label) !== null && _a !== void 0 ? _a : iconStack.iconDisplayName(entry.name); };
30
+ /** The part of the window an element's popup can show in: the window, cut by every ancestor that clips or scrolls. */
31
+ function visibleBounds(el) {
32
+ const bounds = { top: 0, bottom: window.innerHeight, left: 0, right: window.innerWidth };
33
+ for (let p = el.parentElement; p && p !== document.body; p = p.parentElement) {
34
+ const style = window.getComputedStyle(p);
35
+ if (style.overflowX !== 'visible' || style.overflowY !== 'visible') {
36
+ const r = p.getBoundingClientRect();
37
+ bounds.top = Math.max(bounds.top, r.top);
38
+ bounds.bottom = Math.min(bounds.bottom, r.bottom);
39
+ bounds.left = Math.max(bounds.left, r.left);
40
+ bounds.right = Math.min(bounds.right, r.right);
41
+ }
42
+ }
43
+ return bounds;
44
+ }
19
45
  /* ─── localStorage helpers ─── */
20
46
  function loadFromStorage(key, fallback) {
21
47
  if (typeof window === 'undefined') {
@@ -46,40 +72,43 @@ function saveToStorage(key, value) {
46
72
  /**
47
73
  * A fully-featured icon picker dropdown component.
48
74
  *
49
- * Provides a trigger button that opens a searchable, categorized icon grid.
50
- * Supports controlled selection, keyboard navigation (Escape to close),
51
- * click-outside dismissal, and an imperative handle for programmatic control.
75
+ * Provides a trigger button that opens a searchable, categorized icon grid. The value binds both
76
+ * ways — `value` / `defaultValue` + `onChange` (1.3.9) — as the icon's export name or, with
77
+ * `valueFormat="html"`, as the icon drawn in HTML, ready to store. With `stackable` the panel gets
78
+ * an "Overlays" tab where icons are stacked on the chosen one. Names show without `Ntd`; the
79
+ * trigger shows the icon alone or the icon and its name (`displayMode`). Keyboard: arrows in the
80
+ * grid, Escape to close.
52
81
  *
53
82
  * **Styling:** Uses CSS variables for theming (see `NiceIconPicker.css`).
54
83
  * Override `--ntd-picker-bg`, `--ntd-picker-accent`, etc. on a parent element.
55
84
  *
56
85
  * @example
57
86
  * ```tsx
58
- * import { NiceIconPicker } from '@nicetodev/icons';
59
- *
60
- * function IconSelectField({ icons }) {
61
- * const [selected, setSelected] = useState<string | null>(null);
87
+ * import { NiceIconPicker } from '@nice2dev/icons';
62
88
  *
63
- * return (
64
- * <NiceIconPicker
65
- * icons={icons}
66
- * value={selected}
67
- * onChange={(name) => setSelected(name)}
68
- * variant="solid"
69
- * placeholder="Pick icon..."
70
- * />
71
- * );
89
+ * function IconField({ icons, value, onChange }) {
90
+ * // stores `<svg data-ntd-icon="NtdStar" …>…</svg>`, a stack included
91
+ * return <NiceIconPicker icons={icons} value={value} onChange={onChange} stackable />;
72
92
  * }
73
93
  * ```
74
94
  */
75
- const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker({ icons, value = null, values = [], onChange, onChangeMulti, multiSelect = false, maxSelections, placeholder, variant = 'solid', gridIconSize = 'md', triggerIconSize = 'sm', categories: categoriesProp, className, disabled = false, clearable = true, virtualized = false, virtualizedItemCount = 100, showHistory = false, showFavorites = false, storageKeyPrefix = 'ntd-icon-picker', enableDragAndDrop = false, onDragStart, onDragEnd, }, ref) {
95
+ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker({ icons, value: valueProp, defaultValue, values: valuesProp, defaultValues, onChange, onChangeMulti, valueFormat: valueFormatProp, stackable = false, displayMode = 'icon-name', optionDisplayMode = 'icon', name, 'aria-label': ariaLabel, id, testId, 'data-testid': dataTestId, multiSelect = false, maxSelections, placeholder, variant = 'solid', iconProps, gridIconSize = 'md', triggerIconSize = 'sm', categories: categoriesProp, className, disabled = false, clearable = true, virtualized = false, virtualizedItemCount = 100, showHistory = false, showFavorites = false, storageKeyPrefix = 'ntd-icon-picker', enableDragAndDrop = false, onDragStart, onDragEnd, }, ref) {
76
96
  var _a;
77
97
  const tablistRef = React.useRef(null);
78
98
  uiCore.useRovingFocus(tablistRef, { orientation: 'horizontal', wrap: true, activateOnMove: true });
99
+ const viewsRef = React.useRef(null);
100
+ uiCore.useRovingFocus(viewsRef, { orientation: 'horizontal', activateOnMove: true });
79
101
  const { t } = uiCore.useNiceTranslation();
80
102
  const [isOpen, setIsOpen] = React.useState(false);
81
103
  const [search, setSearch] = React.useState('');
82
104
  const [activeCategory, setActiveCategory] = React.useState(null);
105
+ // the panel's view: the icon grid or the stack; `picking` = the grid chooses an icon to stack
106
+ const [view, setView] = React.useState('icons');
107
+ const [picking, setPicking] = React.useState(null);
108
+ const panelId = React.useId();
109
+ const valueFormat = valueFormatProp !== null && valueFormatProp !== void 0 ? valueFormatProp : (stackable ? 'html' : 'name');
110
+ const canStack = stackable && !multiSelect && valueFormat === 'html';
111
+ const drawProps = React.useMemo(() => ({ accentColor: PAGE_ACCENT, ...iconProps, variant }), [iconProps, variant]);
83
112
  // Virtualization state
84
113
  const [visibleRange, setVisibleRange] = React.useState({ start: 0, end: virtualizedItemCount });
85
114
  const gridWrapRef = React.useRef(null);
@@ -88,35 +117,105 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
88
117
  const historyKey = `${storageKeyPrefix}-history`;
89
118
  const [favorites, setFavorites] = React.useState(() => loadFromStorage(favoritesKey, []));
90
119
  const [history, setHistory] = React.useState(() => loadFromStorage(historyKey, []));
91
- // Multi-select state (internal when uncontrolled)
92
- const [internalValues, setInternalValues] = React.useState([]);
93
- const selectedValues = React.useMemo(() => (multiSelect ? (values.length > 0 ? values : internalValues) : value ? [value] : []), [multiSelect, values, internalValues, value]);
120
+ // The value binds both ways (1.3.9): controlled by `value`, or kept here from `defaultValue`.
121
+ const [value, setValue] = uiCore.useControllableState({
122
+ value: valueProp,
123
+ defaultValue,
124
+ fallbackValue: null,
125
+ componentName: 'NiceIconPicker',
126
+ });
127
+ const [values, setValues] = uiCore.useControllableState({
128
+ value: valuesProp,
129
+ defaultValue: defaultValues,
130
+ fallbackValue: NO_NAMES,
131
+ componentName: 'NiceIconPicker',
132
+ });
94
133
  const rootRef = React.useRef(null);
95
134
  const searchInputRef = React.useRef(null);
135
+ const stackerRef = React.useRef(null);
136
+ const serializerRef = React.useRef(null);
137
+ /* ─── Icons by name: exact, or without the Ntd a stored value may lack ─── */
138
+ const byName = React.useMemo(() => new Map(icons.map((e) => [e.name, e])), [icons]);
139
+ const entryOf = React.useCallback((n) => { var _a; return (n ? ((_a = byName.get(n)) !== null && _a !== void 0 ? _a : byName.get(`Ntd${n}`)) : undefined); }, [byName]);
140
+ const labelOf = React.useCallback((n) => {
141
+ const entry = entryOf(n);
142
+ return entry ? entryLabel(entry) : iconStack.iconDisplayName(n);
143
+ }, [entryOf]);
144
+ const resolve = React.useCallback((n) => { var _a; return (_a = entryOf(n)) === null || _a === void 0 ? void 0 : _a.Component; }, [entryOf]);
145
+ /* ─── The single value as a stack — a plain icon is a stack of one ─── */
146
+ const model = React.useMemo(() => {
147
+ if (!value) {
148
+ return NO_LAYERS;
149
+ }
150
+ const source = iconHtml.parseIconHtml(value);
151
+ if (source) {
152
+ return source.layers;
153
+ }
154
+ const entry = value.includes('<') ? undefined : entryOf(value);
155
+ return entry ? [{ id: '1', icon: entry.name }] : NO_LAYERS;
156
+ }, [value, entryOf]);
157
+ // A stack waiting to be drawn into HTML: shown at once, emitted once drawn (below).
158
+ const [pending, setPending] = React.useState(null);
159
+ const shown = pending !== null && pending !== void 0 ? pending : model;
160
+ const base = shown[0];
161
+ const onChangeRef = React.useRef(onChange);
162
+ onChangeRef.current = onChange;
163
+ const emit = React.useCallback((next, baseName) => {
164
+ var _a, _b;
165
+ setValue(next);
166
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, next, (_b = entryOf(baseName)) !== null && _b !== void 0 ? _b : null);
167
+ }, [setValue, entryOf]);
168
+ /** Sets the single value to a stack: its base's name, or the stack drawn as HTML. */
169
+ const commit = React.useCallback((layers) => {
170
+ if (layers.length === 0) {
171
+ setPending(null);
172
+ emit(null);
173
+ }
174
+ else if (valueFormat === 'name') {
175
+ emit(layers[0].icon, layers[0].icon);
176
+ }
177
+ else {
178
+ setPending(layers);
179
+ }
180
+ }, [valueFormat, emit]);
181
+ // The HTML is the icon as drawn: the hidden copy below renders the pending stack, and its
182
+ // markup — ids renamed after the drawing — is the new value, emitted before the paint.
183
+ useIsoLayoutEffect(() => {
184
+ var _a;
185
+ if (!pending) {
186
+ return;
187
+ }
188
+ const svg = (_a = serializerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
189
+ setPending(null);
190
+ if (svg) {
191
+ emit(iconHtml.scopeIconHtmlIds(svg.outerHTML), pending[0].icon);
192
+ }
193
+ }, [pending, emit]);
194
+ const selectedValues = React.useMemo(() => (multiSelect ? values : base ? [base.icon] : NO_NAMES), [multiSelect, values, base]);
96
195
  /* ─── Favorites helpers ─── */
97
- const addFavorite = React.useCallback((name) => {
196
+ const addFavorite = React.useCallback((favorite) => {
98
197
  setFavorites((prev) => {
99
- if (prev.includes(name)) {
198
+ if (prev.includes(favorite)) {
100
199
  return prev;
101
200
  }
102
- const next = [...prev, name];
201
+ const next = [...prev, favorite];
103
202
  saveToStorage(favoritesKey, next);
104
203
  return next;
105
204
  });
106
205
  }, [favoritesKey]);
107
- const removeFavorite = React.useCallback((name) => {
206
+ const removeFavorite = React.useCallback((favorite) => {
108
207
  setFavorites((prev) => {
109
- const next = prev.filter((n) => n !== name);
208
+ const next = prev.filter((n) => n !== favorite);
110
209
  saveToStorage(favoritesKey, next);
111
210
  return next;
112
211
  });
113
212
  }, [favoritesKey]);
114
- const toggleFavorite = React.useCallback((name) => {
115
- if (favorites.includes(name)) {
116
- removeFavorite(name);
213
+ const toggleFavorite = React.useCallback((favorite) => {
214
+ if (favorites.includes(favorite)) {
215
+ removeFavorite(favorite);
117
216
  }
118
217
  else {
119
- addFavorite(name);
218
+ addFavorite(favorite);
120
219
  }
121
220
  }, [favorites, addFavorite, removeFavorite]);
122
221
  const clearFavorites = React.useCallback(() => {
@@ -124,10 +223,10 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
124
223
  saveToStorage(favoritesKey, []);
125
224
  }, [favoritesKey]);
126
225
  /* ─── History helpers ─── */
127
- const addToHistory = React.useCallback((name) => {
226
+ const addToHistory = React.useCallback((used) => {
128
227
  setHistory((prev) => {
129
- const filtered = prev.filter((n) => n !== name);
130
- const next = [name, ...filtered].slice(0, MAX_HISTORY_ITEMS);
228
+ const filtered = prev.filter((n) => n !== used);
229
+ const next = [used, ...filtered].slice(0, MAX_HISTORY_ITEMS);
131
230
  saveToStorage(historyKey, next);
132
231
  return next;
133
232
  });
@@ -164,12 +263,14 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
164
263
  }
165
264
  return result;
166
265
  }, [icons, categoriesProp]);
167
- /* ─── Filter icons ─── */
266
+ /* ─── Filter icons: by the name shown, the export name or the category ─── */
168
267
  const filtered = React.useMemo(() => {
169
268
  let items = icons;
170
- if (search.trim()) {
171
- const q = search.toLowerCase();
172
- items = items.filter((i) => i.name.toLowerCase().includes(q) || i.category.toLowerCase().includes(q));
269
+ const q = search.trim().toLowerCase();
270
+ if (q) {
271
+ items = items.filter((i) => entryLabel(i).toLowerCase().includes(q) ||
272
+ i.name.toLowerCase().includes(q) ||
273
+ i.category.toLowerCase().includes(q));
173
274
  }
174
275
  if (activeCategory === '__favorites__') {
175
276
  items = items.filter((i) => favorites.includes(i.name));
@@ -207,13 +308,8 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
207
308
  }
208
309
  return map;
209
310
  }, [filtered, virtualized, virtualizedFiltered]);
210
- /* ─── Selected entries ─── */
211
- const selectedEntries = React.useMemo(() => {
212
- return selectedValues
213
- .map((v) => icons.find((i) => i.name === v))
214
- .filter((e) => e !== undefined);
215
- }, [icons, selectedValues]);
216
- const selectedEntry = (_a = selectedEntries[0]) !== null && _a !== void 0 ? _a : null;
311
+ /* ─── Selected entries (multi-select) ─── */
312
+ const selectedEntries = React.useMemo(() => values.map((v) => entryOf(v)).filter((e) => e !== undefined), [values, entryOf]);
217
313
  /* ─── Click outside ─── */
218
314
  React.useEffect(() => {
219
315
  if (!isOpen) {
@@ -232,6 +328,8 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
232
328
  if (!isOpen) {
233
329
  setSearch('');
234
330
  setActiveCategory(null);
331
+ setView('icons');
332
+ setPicking(null);
235
333
  setVisibleRange({ start: 0, end: virtualizedItemCount });
236
334
  }
237
335
  }, [isOpen, virtualizedItemCount]);
@@ -239,14 +337,27 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
239
337
  // The panel is a dialog on the overlay stack: focus on the search field when it opens, Escape
240
338
  // / B close only it (a document listener before) and focus returns to the trigger. The icon
241
339
  // grid is an APG listbox moving in two dimensions — the cells were reachable by Tab only.
340
+ // While the grid picks an icon to stack, Escape goes back to the stack instead (1.3.9).
242
341
  const dropdownRef = React.useRef(null);
243
342
  uiCore.useOverlayFocus(dropdownRef, {
244
343
  open: isOpen,
245
344
  modal: false,
246
345
  initialFocus: searchInputRef,
247
- onClose: () => setIsOpen(false),
346
+ onClose: () => (picking ? setPicking(null) : setIsOpen(false)),
248
347
  });
249
348
  uiCore.useRovingFocus(gridWrapRef, { orientation: 'grid', itemSelector: '.ntd-picker-cell' });
349
+ // into the grid to pick an icon to stack: focus the search; back: the layer it went into
350
+ const wasPicking = React.useRef(false);
351
+ React.useEffect(() => {
352
+ var _a, _b, _c;
353
+ if (picking) {
354
+ (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
355
+ }
356
+ else if (wasPicking.current) {
357
+ (_c = (_b = dropdownRef.current) === null || _b === void 0 ? void 0 : _b.querySelector('.nice-icon-stacker__layer--selected .nice-icon-stacker__layer-select')) === null || _c === void 0 ? void 0 : _c.focus();
358
+ }
359
+ wasPicking.current = !!picking;
360
+ }, [picking]);
250
361
  /* ─── Virtualization scroll handler ─── */
251
362
  React.useEffect(() => {
252
363
  if (!virtualized || !isOpen || !gridWrapRef.current) {
@@ -274,63 +385,83 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
274
385
  }, [virtualized, isOpen, filtered.length]);
275
386
  /* ─── Handlers ─── */
276
387
  const handleSelect = React.useCallback((entry) => {
388
+ var _a;
389
+ // an icon to stack: into the layer the stacker has selected, then back to the stack
390
+ if (picking) {
391
+ (_a = stackerRef.current) === null || _a === void 0 ? void 0 : _a.add({ icon: entry.name });
392
+ setPicking(null);
393
+ setSearch('');
394
+ return;
395
+ }
277
396
  // Add to history
278
397
  if (showHistory) {
279
398
  addToHistory(entry.name);
280
399
  }
281
400
  if (multiSelect) {
282
- const isSelected = selectedValues.includes(entry.name);
401
+ const isSelected = values.includes(entry.name);
283
402
  let newValues;
284
403
  if (isSelected) {
285
- newValues = selectedValues.filter((v) => v !== entry.name);
404
+ newValues = values.filter((v) => v !== entry.name);
286
405
  }
287
406
  else {
288
- if (maxSelections && selectedValues.length >= maxSelections) {
407
+ if (maxSelections && values.length >= maxSelections) {
289
408
  return; // Max selections reached
290
409
  }
291
- newValues = [...selectedValues, entry.name];
410
+ newValues = [...values, entry.name];
292
411
  }
412
+ setValues(newValues);
293
413
  if (onChangeMulti) {
294
414
  const entries = newValues
295
- .map((v) => icons.find((i) => i.name === v))
415
+ .map((v) => entryOf(v))
296
416
  .filter((e) => e !== undefined);
297
417
  onChangeMulti(newValues, entries);
298
418
  }
299
- setInternalValues(newValues);
300
419
  // Don't close in multi-select mode
301
420
  }
302
421
  else {
303
- onChange === null || onChange === void 0 ? void 0 : onChange(entry.name, entry);
422
+ // the HTML records the variant it was drawn in; swapping the icon keeps its stack
423
+ const own = valueFormat === 'html' ? { variant } : {};
424
+ commit(canStack && base
425
+ ? [{ ...base, icon: entry.name, ...own }, ...shown.slice(1)]
426
+ : [{ id: '1', icon: entry.name, ...own }]);
304
427
  setIsOpen(false);
305
428
  }
306
429
  }, [
430
+ picking,
431
+ variant,
307
432
  multiSelect,
308
- selectedValues,
433
+ values,
434
+ setValues,
309
435
  maxSelections,
310
- icons,
311
- onChange,
436
+ entryOf,
312
437
  onChangeMulti,
313
438
  showHistory,
314
439
  addToHistory,
440
+ valueFormat,
441
+ canStack,
442
+ base,
443
+ shown,
444
+ commit,
315
445
  ]);
316
446
  const handleClear = React.useCallback((e) => {
317
447
  e.stopPropagation();
318
448
  if (multiSelect) {
449
+ setValues(NO_NAMES);
319
450
  onChangeMulti === null || onChangeMulti === void 0 ? void 0 : onChangeMulti([], []);
320
- setInternalValues([]);
321
451
  }
322
452
  else {
323
- onChange === null || onChange === void 0 ? void 0 : onChange(null, null);
453
+ commit(NO_LAYERS);
454
+ setView('icons');
324
455
  }
325
- }, [multiSelect, onChange, onChangeMulti]);
456
+ }, [multiSelect, setValues, onChangeMulti, commit]);
326
457
  const handleToggle = React.useCallback(() => {
327
458
  if (!disabled) {
328
459
  setIsOpen((o) => !o);
329
460
  }
330
461
  }, [disabled]);
331
- const handleFavoriteClick = React.useCallback((e, name) => {
462
+ const handleFavoriteClick = React.useCallback((e, favorite) => {
332
463
  e.stopPropagation();
333
- toggleFavorite(name);
464
+ toggleFavorite(favorite);
334
465
  }, [toggleFavorite]);
335
466
  /* ─── Drag & Drop handlers ─── */
336
467
  const handleDragStart = React.useCallback((entry, e) => {
@@ -338,8 +469,7 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
338
469
  return;
339
470
  }
340
471
  // Set various data formats for maximum compatibility
341
- const name = entry.name;
342
- const readName = readableName(name);
472
+ const readName = entryLabel(entry);
343
473
  // Plain text - icon name
344
474
  e.dataTransfer.setData('text/plain', readName);
345
475
  // JSON data with full icon info
@@ -351,14 +481,9 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
351
481
  };
352
482
  e.dataTransfer.setData('application/json', JSON.stringify(iconData));
353
483
  e.dataTransfer.setData('text/x-ntd-icon', JSON.stringify(iconData));
354
- // Try to render SVG to data URL for image dragging
484
+ // The cell's own drawing as an image
355
485
  try {
356
- const tempContainer = document.createElement('div');
357
- tempContainer.style.position = 'absolute';
358
- tempContainer.style.left = '-9999px';
359
- document.body.appendChild(tempContainer);
360
- // Use dynamic import workaround - render to string
361
- const svgElement = document.querySelector(`[data-name="${readName}"] svg`);
486
+ const svgElement = e.currentTarget.querySelector('svg');
362
487
  if (svgElement) {
363
488
  const svgClone = svgElement.cloneNode(true);
364
489
  svgClone.setAttribute('width', '64');
@@ -371,7 +496,6 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
371
496
  img.src = URL.createObjectURL(svgBlob);
372
497
  e.dataTransfer.setDragImage(img, 32, 32);
373
498
  }
374
- document.body.removeChild(tempContainer);
375
499
  }
376
500
  catch (_a) {
377
501
  // Fallback - use default drag image
@@ -382,33 +506,106 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
382
506
  const handleDragEnd = React.useCallback((entry, e) => {
383
507
  onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(entry, e);
384
508
  }, [onDragEnd]);
385
- const readableName = (name) => name.replace(/^Ntd/, '');
386
509
  const triggerLabel = React.useMemo(() => {
387
- if (multiSelect && selectedEntries.length > 0) {
510
+ if (multiSelect) {
388
511
  if (selectedEntries.length === 1) {
389
- return readableName(selectedEntries[0].name);
512
+ return entryLabel(selectedEntries[0]);
390
513
  }
391
- return t('iconPicker.iconsSelected', '{count} icons selected').replace('{count}', String(selectedEntries.length));
392
- }
393
- return selectedEntry
394
- ? readableName(selectedEntry.name)
395
- : (placeholder !== null && placeholder !== void 0 ? placeholder : t('iconPicker.selectIcon', 'Select icon…'));
396
- }, [multiSelect, selectedEntries, selectedEntry, placeholder, t]);
397
- return (jsxRuntime.jsxs("div", { ref: rootRef, className: `ntd-picker${isOpen ? ' ntd-picker--open' : ''}${disabled ? ' ntd-picker--disabled' : ''}${multiSelect ? ' ntd-picker--multi' : ''}${className ? ` ${className}` : ''}`, children: [jsxRuntime.jsxs("button", { type: "button", className: "ntd-picker-trigger", onClick: handleToggle, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [jsxRuntime.jsx("span", { className: "ntd-picker-trigger-icon", children: selectedEntry ? (jsxRuntime.jsx(selectedEntry.Component, { size: triggerIconSize, variant: variant })) : multiSelect && selectedEntries.length > 1 ? (jsxRuntime.jsx("span", { className: "ntd-picker-multi-badge", children: selectedEntries.length })) : (jsxRuntime.jsx(files.NtdGrid, { size: 16, variant: "outline" })) }), jsxRuntime.jsx("span", { className: `ntd-picker-trigger-label${!selectedEntry && selectedEntries.length === 0 ? ' ntd-picker-trigger-placeholder' : ''}`, children: triggerLabel }), jsxRuntime.jsx("span", { className: "ntd-picker-trigger-chevron", children: jsxRuntime.jsx(Chevron, {}) })] }), isOpen && (jsxRuntime.jsxs("div", { ref: dropdownRef, className: "ntd-picker-dropdown", role: "dialog", "aria-label": t('iconPicker.selectIcon', 'Select icon…'), children: [jsxRuntime.jsxs("div", { className: "ntd-picker-search", children: [jsxRuntime.jsx("span", { className: "ntd-picker-search-icon", children: jsxRuntime.jsx(SearchIcon, {}) }), jsxRuntime.jsx("input", { ref: searchInputRef, type: "text", placeholder: t('iconPicker.searchIcons', 'Search icons…'), value: search, onChange: (e) => setSearch(e.target.value), "aria-label": t('iconPicker.searchIcons2', 'Search icons') })] }), (allCategories.length > 1 || showFavorites || showHistory) && (jsxRuntime.jsxs("div", { className: "ntd-picker-tabs", ref: tablistRef, role: "tablist", children: [jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === null ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(null), role: "tab", "aria-selected": activeCategory === null, children: t('iconPicker.all', 'All') }), showFavorites && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__favorites__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__favorites__'), role: "tab", "aria-selected": activeCategory === '__favorites__', title: t('iconPicker.favorites', 'Favorites'), children: [jsxRuntime.jsx(StarIcon, { filled: true }), " ", t('iconPicker.favorites', 'Favorites'), favorites.length > 0 && (jsxRuntime.jsx("span", { className: "ntd-picker-tab-count", children: favorites.length }))] })), showHistory && history.length > 0 && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__history__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__history__'), role: "tab", "aria-selected": activeCategory === '__history__', title: t('iconPicker.recentlyUsed', 'Recently used'), children: [jsxRuntime.jsx(ClockIcon, {}), " ", t('iconPicker.recent', 'Recent')] })), allCategories.map((cat) => (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === cat ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(cat), role: "tab", "aria-selected": activeCategory === cat, children: cat }, cat)))] })), jsxRuntime.jsx("div", { className: "ntd-picker-grid-wrap", ref: gridWrapRef, role: "listbox", "aria-label": t('iconPicker.icons', 'Icons'), "aria-multiselectable": multiSelect || undefined, children: filtered.length === 0 ? (jsxRuntime.jsxs("div", { className: "ntd-picker-empty", children: [jsxRuntime.jsx("div", { className: "ntd-picker-empty-icon", children: jsxRuntime.jsx(media.NtdInbox, { size: 28, variant: "outline" }) }), activeCategory === '__favorites__'
398
- ? t('iconPicker.noFavoritesYetClickThe', 'No favorites yet. Click the star icon to add.')
399
- : activeCategory === '__history__'
400
- ? t('iconPicker.noRecentIcons', 'No recent icons.')
401
- : t('iconPicker.noIconsFound', 'No icons found')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [virtualized && visibleRange.start > 0 && (jsxRuntime.jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxRuntime.jsxs("div", { children: [!activeCategory && !(activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.startsWith('__')) && (jsxRuntime.jsx("div", { className: "ntd-picker-category-label", children: category })), jsxRuntime.jsx("div", { className: "ntd-picker-grid", children: entries.map((entry) => {
402
- const isSelected = selectedValues.includes(entry.name);
403
- const isFavorite = favorites.includes(entry.name);
404
- return (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-cell${isSelected ? ' ntd-picker-cell--selected' : ''}${multiSelect ? ' ntd-picker-cell--multi-select' : ''}${enableDragAndDrop ? ' ntd-picker-cell--draggable' : ''}`, onClick: () => handleSelect(entry), "data-name": readableName(entry.name), role: "option", "aria-selected": isSelected, title: readableName(entry.name), draggable: enableDragAndDrop, onDragStart: enableDragAndDrop ? (e) => handleDragStart(entry, e) : undefined, onDragEnd: enableDragAndDrop ? (e) => handleDragEnd(entry, e) : undefined, children: [jsxRuntime.jsx(entry.Component, { size: gridIconSize, variant: variant }), multiSelect && isSelected && (jsxRuntime.jsx("span", { className: "ntd-picker-cell-check", children: jsxRuntime.jsx(CheckIcon, {}) })), showFavorites && (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-cell-fav${isFavorite ? ' ntd-picker-cell-fav--active' : ''}`, onClick: (e) => handleFavoriteClick(e, entry.name), title: isFavorite
405
- ? t('iconPicker.removeFromFavorites', 'Remove from favorites')
406
- : t('iconPicker.addToFavorites', 'Add to favorites'), children: jsxRuntime.jsx(StarIcon, { filled: isFavorite }) }))] }, entry.name));
407
- }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsxRuntime.jsx("div", { style: { height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48 } }))] })) }), jsxRuntime.jsxs("div", { className: "ntd-picker-footer", children: [jsxRuntime.jsxs("span", { className: "ntd-picker-count", children: [(filtered.length === 1
408
- ? t('iconPicker.iconCountOne', '{count} icon')
409
- : t('iconPicker.iconCountMany', '{count} icons')).replace('{count}', String(filtered.length)), multiSelect && selectedValues.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.selected', '• {selectedValues} selected').replace('{selectedValues}', String(selectedValues.length))] })), maxSelections && multiSelect && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.max', '(max {maxSelections})').replace('{maxSelections}', String(maxSelections))] }))] }), clearable && selectedValues.length > 0 && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: multiSelect
514
+ if (selectedEntries.length > 1) {
515
+ return t('iconPicker.iconsSelected', '{count} icons selected').replace('{count}', String(selectedEntries.length));
516
+ }
517
+ }
518
+ else if (base) {
519
+ return labelOf(base.icon);
520
+ }
521
+ return placeholder !== null && placeholder !== void 0 ? placeholder : t('iconPicker.selectIcon', 'Select icon…');
522
+ }, [multiSelect, selectedEntries, base, labelOf, placeholder, t]);
523
+ const hasSelection = multiSelect ? selectedEntries.length > 0 : !!base;
524
+ const iconOnly = displayMode === 'icon';
525
+ // the field's label first, then what is chosen — the icon-only trigger has no text of its own
526
+ const triggerName = ariaLabel
527
+ ? `${ariaLabel}: ${triggerLabel}`
528
+ : iconOnly
529
+ ? triggerLabel
530
+ : undefined;
531
+ const overlays = Math.max(0, shown.length - 1);
532
+ const showGrid = view === 'icons' || !!picking;
533
+ // Where the panel opens (1.3.9): above the trigger when there is more room there, against its
534
+ // right edge near the window's, never taller than the room it has — the stack view is tall.
535
+ // The room is what the window and every clipping or scrolling ancestor leave visible.
536
+ const [placement, setPlacement] = React.useState({
537
+ up: false,
538
+ end: false,
539
+ });
540
+ useIsoLayoutEffect(() => {
541
+ const root = rootRef.current;
542
+ if (!isOpen || !root || typeof window === 'undefined') {
543
+ return;
544
+ }
545
+ const r = root.getBoundingClientRect();
546
+ const bounds = visibleBounds(root);
547
+ const want = showGrid ? 460 : 620;
548
+ const below = bounds.bottom - r.bottom - 12;
549
+ const above = r.top - bounds.top - 12;
550
+ const up = below < want && above > below;
551
+ const room = up ? above : below;
552
+ setPlacement({
553
+ up,
554
+ end: r.left + 380 > bounds.right - 8 && r.right - bounds.left >= 380,
555
+ maxHeight: room < want ? Math.max(240, Math.floor(room)) : undefined,
556
+ });
557
+ }, [isOpen, showGrid]);
558
+ const pickingInto = picking ? shown.find((l) => l.id === picking.target) : undefined;
559
+ const SingleMulti = (_a = selectedEntries[0]) === null || _a === void 0 ? void 0 : _a.Component;
560
+ return (jsxRuntime.jsxs("div", { ref: rootRef, id: id, "data-testid": dataTestId !== null && dataTestId !== void 0 ? dataTestId : testId, className: `ntd-picker${isOpen ? ' ntd-picker--open' : ''}${disabled ? ' ntd-picker--disabled' : ''}${multiSelect ? ' ntd-picker--multi' : ''}${iconOnly ? ' ntd-picker--icon-only' : ''}${className ? ` ${className}` : ''}`, children: [jsxRuntime.jsxs("button", { type: "button", className: "ntd-picker-trigger", onClick: handleToggle, disabled: disabled, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-label": triggerName, title: iconOnly ? triggerLabel : undefined, children: [jsxRuntime.jsx("span", { className: "ntd-picker-trigger-icon", children: !multiSelect && base ? (iconStack.renderIconStack(shown, resolve, {
561
+ baseProps: { ...drawProps, size: triggerIconSize },
562
+ })) : multiSelect && selectedEntries.length > 1 ? (jsxRuntime.jsx("span", { className: "ntd-picker-multi-badge", children: selectedEntries.length })) : SingleMulti ? (jsxRuntime.jsx(SingleMulti, { ...drawProps, size: triggerIconSize })) : (jsxRuntime.jsx(files.NtdGrid, { size: 16, variant: "outline" })) }), !iconOnly && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: `ntd-picker-trigger-label${hasSelection ? '' : ' ntd-picker-trigger-placeholder'}`, children: triggerLabel }), jsxRuntime.jsx("span", { className: "ntd-picker-trigger-chevron", children: jsxRuntime.jsx(Chevron, {}) })] }))] }), name &&
563
+ (multiSelect ? (values.map((v) => jsxRuntime.jsx("input", { type: "hidden", name: name, value: v }, v))) : (jsxRuntime.jsx("input", { type: "hidden", name: name, value: value !== null && value !== void 0 ? value : '' }))), pending && (jsxRuntime.jsx("span", { ref: serializerRef, className: "ntd-picker-serializer", hidden: true, children: iconStack.renderIconStack(pending, resolve, {
564
+ baseProps: {
565
+ ...drawProps,
566
+ width: '1em',
567
+ height: '1em',
568
+ title: labelOf(pending[0].icon),
569
+ ...iconHtml.iconHtmlAttributes(pending),
570
+ },
571
+ }) })), isOpen && (jsxRuntime.jsxs("div", { ref: dropdownRef, className: `ntd-picker-dropdown${showGrid ? '' : ' ntd-picker-dropdown--stack'}${placement.up ? ' ntd-picker-dropdown--up' : ''}${placement.end ? ' ntd-picker-dropdown--end' : ''}`, style: placement.maxHeight ? { maxHeight: placement.maxHeight } : undefined, role: "dialog", "aria-label": t('iconPicker.selectIcon', 'Select icon…'), children: [canStack &&
572
+ (picking ? (jsxRuntime.jsxs("div", { className: "ntd-picker-banner", children: [jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-back", onClick: () => setPicking(null), "aria-label": t('iconPicker.back', 'Back'), title: t('iconPicker.back', 'Back'), children: jsxRuntime.jsx(navigation.NtdArrowLeft, { size: 14, variant: "outline" }) }), jsxRuntime.jsx("span", { children: t('iconPicker.pickOverlay', 'Pick an icon to put on {icon}').replace('{icon}', pickingInto ? labelOf(pickingInto.icon) : base ? labelOf(base.icon) : '') })] })) : (jsxRuntime.jsxs("div", { className: "ntd-picker-views", ref: viewsRef, role: "tablist", "aria-label": t('iconPicker.selectIcon', 'Select icon…'), children: [jsxRuntime.jsx("button", { type: "button", role: "tab", id: `${panelId}-icons`, "aria-selected": view === 'icons', "aria-controls": `${panelId}-panel`, className: `ntd-picker-view${view === 'icons' ? ' ntd-picker-view--active' : ''}`, onClick: () => setView('icons'), children: t('iconPicker.tabIcon', 'Icon') }), jsxRuntime.jsxs("button", { type: "button", role: "tab", id: `${panelId}-stack`, "aria-selected": view === 'stack', "aria-controls": `${panelId}-panel`, className: `ntd-picker-view${view === 'stack' ? ' ntd-picker-view--active' : ''}`, onClick: () => setView('stack'), disabled: !base, title: base ? undefined : t('iconPicker.stackNeedsIcon', 'Pick an icon first'), children: [t('iconPicker.tabStack', 'Overlays'), overlays > 0 && jsxRuntime.jsx("span", { className: "ntd-picker-tab-count", children: overlays })] })] }))), jsxRuntime.jsxs("div", { className: "ntd-picker-panel", id: `${panelId}-panel`, ...(canStack && !picking
573
+ ? {
574
+ role: 'tabpanel',
575
+ 'aria-labelledby': `${panelId}-${view}`,
576
+ }
577
+ : {}), children: [showGrid && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "ntd-picker-search", children: [jsxRuntime.jsx("span", { className: "ntd-picker-search-icon", children: jsxRuntime.jsx(SearchIcon, {}) }), jsxRuntime.jsx("input", { ref: searchInputRef, type: "text", placeholder: t('iconPicker.searchIcons', 'Search icons…'), value: search, onChange: (e) => setSearch(e.target.value), "aria-label": t('iconPicker.searchIcons2', 'Search icons') })] }), (allCategories.length > 1 || showFavorites || showHistory) && (jsxRuntime.jsxs("div", { className: "ntd-picker-tabs", ref: tablistRef, role: "tablist", children: [jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === null ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(null), role: "tab", "aria-selected": activeCategory === null, children: t('iconPicker.all', 'All') }), showFavorites && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__favorites__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__favorites__'), role: "tab", "aria-selected": activeCategory === '__favorites__', title: t('iconPicker.favorites', 'Favorites'), children: [jsxRuntime.jsx(StarIcon, { filled: true }), " ", t('iconPicker.favorites', 'Favorites'), favorites.length > 0 && (jsxRuntime.jsx("span", { className: "ntd-picker-tab-count", children: favorites.length }))] })), showHistory && history.length > 0 && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__history__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__history__'), role: "tab", "aria-selected": activeCategory === '__history__', title: t('iconPicker.recentlyUsed', 'Recently used'), children: [jsxRuntime.jsx(ClockIcon, {}), " ", t('iconPicker.recent', 'Recent')] })), allCategories.map((cat) => (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === cat ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(cat), role: "tab", "aria-selected": activeCategory === cat, children: cat }, cat)))] })), jsxRuntime.jsx("div", { className: "ntd-picker-grid-wrap", ref: gridWrapRef, role: "listbox", "aria-label": t('iconPicker.icons', 'Icons'), "aria-multiselectable": multiSelect || undefined, children: filtered.length === 0 ? (jsxRuntime.jsxs("div", { className: "ntd-picker-empty", children: [jsxRuntime.jsx("div", { className: "ntd-picker-empty-icon", children: jsxRuntime.jsx(media.NtdInbox, { size: 28, variant: "outline" }) }), activeCategory === '__favorites__'
578
+ ? t('iconPicker.noFavoritesYetClickThe', 'No favorites yet. Click the star icon to add.')
579
+ : activeCategory === '__history__'
580
+ ? t('iconPicker.noRecentIcons', 'No recent icons.')
581
+ : t('iconPicker.noIconsFound', 'No icons found')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [virtualized && visibleRange.start > 0 && (jsxRuntime.jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxRuntime.jsxs("div", { children: [!activeCategory && (jsxRuntime.jsx("div", { className: "ntd-picker-category-label", children: category })), jsxRuntime.jsx("div", { className: `ntd-picker-grid${optionDisplayMode === 'icon-name' ? ' ntd-picker-grid--names' : ''}`, children: entries.map((entry) => {
582
+ const isSelected = !picking && selectedValues.includes(entry.name);
583
+ const isFavorite = favorites.includes(entry.name);
584
+ const label = entryLabel(entry);
585
+ const cell = (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-cell${isSelected ? ' ntd-picker-cell--selected' : ''}${multiSelect ? ' ntd-picker-cell--multi-select' : ''}${enableDragAndDrop ? ' ntd-picker-cell--draggable' : ''}`, onClick: () => handleSelect(entry), "data-name": label, role: "option", "aria-selected": isSelected, "aria-label": label, title: label, draggable: enableDragAndDrop, onDragStart: enableDragAndDrop
586
+ ? (e) => handleDragStart(entry, e)
587
+ : undefined, onDragEnd: enableDragAndDrop ? (e) => handleDragEnd(entry, e) : undefined, children: [jsxRuntime.jsx(entry.Component, { ...drawProps, size: gridIconSize }), optionDisplayMode === 'icon-name' && (jsxRuntime.jsx("span", { className: "ntd-picker-cell-name", children: label })), multiSelect && isSelected && (jsxRuntime.jsx("span", { className: "ntd-picker-cell-check", children: jsxRuntime.jsx(CheckIcon, {}) }))] }, entry.name));
588
+ if (!showFavorites) {
589
+ return cell;
590
+ }
591
+ // the star beside the cell, not in it — a button in a button is
592
+ // invalid HTML (1.3.9)
593
+ const favLabel = isFavorite
594
+ ? t('iconPicker.removeFromFavorites', 'Remove from favorites')
595
+ : t('iconPicker.addToFavorites', 'Add to favorites');
596
+ return (jsxRuntime.jsxs("div", { className: "ntd-picker-cell-wrap", children: [cell, jsxRuntime.jsx("button", { type: "button", tabIndex: -1, className: `ntd-picker-cell-fav${isFavorite ? ' ntd-picker-cell-fav--active' : ''}`, onClick: (e) => handleFavoriteClick(e, entry.name), "aria-label": `${favLabel}: ${label}`, title: favLabel, children: jsxRuntime.jsx(StarIcon, { filled: isFavorite }) })] }, entry.name));
597
+ }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsxRuntime.jsx("div", { style: {
598
+ height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48,
599
+ } }))] })) })] })), canStack && view === 'stack' && base && (jsxRuntime.jsx("div", { className: "ntd-picker-stack", hidden: !!picking, children: jsxRuntime.jsx(NiceIconStacker.NiceIconStacker, { ref: stackerRef, icons: resolve, layers: shown, onLayersChange: commit, onAddClick: (target) => {
600
+ var _a;
601
+ setSearch('');
602
+ setActiveCategory(null);
603
+ setPicking({ target: (_a = target === null || target === void 0 ? void 0 : target.id) !== null && _a !== void 0 ? _a : base.id });
604
+ }, previewProps: drawProps, iconLabel: labelOf, showCode: false, keepBase: true }) }))] }), !picking && (jsxRuntime.jsxs("div", { className: "ntd-picker-footer", children: [jsxRuntime.jsx("span", { className: "ntd-picker-count", children: showGrid && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(filtered.length === 1
605
+ ? t('iconPicker.iconCountOne', '{count} icon')
606
+ : t('iconPicker.iconCountMany', '{count} icons')).replace('{count}', String(filtered.length)), multiSelect && selectedValues.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.selected', '• {selectedValues} selected').replace('{selectedValues}', String(selectedValues.length))] })), maxSelections && multiSelect && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.max', '(max {maxSelections})').replace('{maxSelections}', String(maxSelections))] }))] })) }), clearable && hasSelection && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: multiSelect
410
607
  ? t('iconPicker.clearAll', 'Clear all')
411
- : t('iconPicker.clearSelection', 'Clear selection') })), multiSelect && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: t('iconPicker.done', 'Done') }))] })] }))] }));
608
+ : t('iconPicker.clearSelection', 'Clear selection') })), (multiSelect || view === 'stack') && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: t('iconPicker.done', 'Done') }))] }))] }))] }));
412
609
  });
413
610
 
414
611
  exports.NiceIconPicker = NiceIconPicker;