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