@nice2dev/icons 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +499 -0
- package/README.md +146 -134
- package/dist/cjs/NiceIconPicker.js +17 -19
- package/dist/cjs/createIcon.js +10 -2
- package/dist/cjs/iconParts.js +49 -0
- package/dist/cjs/icons/accessibility.js +12 -4
- package/dist/cjs/icons/actions.js +67 -25
- package/dist/cjs/icons/business.js +58 -28
- package/dist/cjs/icons/ecommerce.js +0 -20
- package/dist/cjs/icons/education.js +22 -9
- package/dist/cjs/icons/files.js +70 -56
- package/dist/cjs/icons/fun.js +39 -25
- package/dist/cjs/icons/gaming.js +29 -4
- package/dist/cjs/icons/health.js +11 -4
- package/dist/cjs/icons/index.js +55 -5
- package/dist/cjs/icons/input.js +120 -0
- package/dist/cjs/icons/legal.js +4 -9
- package/dist/cjs/icons/media.js +26 -11
- package/dist/cjs/icons/navigation.js +4 -2
- package/dist/cjs/icons/omniverk.js +19 -6
- package/dist/cjs/icons/realestate.js +10 -4
- package/dist/cjs/icons/saas.js +15 -4
- package/dist/cjs/icons/science.js +6 -3
- package/dist/cjs/icons/shapes.js +66 -31
- package/dist/cjs/icons/sports.js +6 -2
- package/dist/cjs/icons/ui.js +62 -20
- package/dist/cjs/icons/weather.js +18 -8
- package/dist/cjs/index.js +55 -5
- package/dist/cjs/nicetodev-icons.css +1 -1
- package/dist/cjs/resolver.js +46 -1
- package/dist/cjs/rsc.js +1 -1
- package/dist/esm/NiceIconPicker.js +19 -21
- package/dist/esm/createIcon.js +10 -2
- package/dist/esm/iconParts.js +46 -0
- package/dist/esm/icons/accessibility.js +12 -4
- package/dist/esm/icons/actions.js +67 -26
- package/dist/esm/icons/business.js +58 -29
- package/dist/esm/icons/ecommerce.js +1 -19
- package/dist/esm/icons/education.js +22 -10
- package/dist/esm/icons/files.js +70 -56
- package/dist/esm/icons/fun.js +37 -25
- package/dist/esm/icons/gaming.js +29 -5
- package/dist/esm/icons/health.js +11 -4
- package/dist/esm/icons/index.js +9 -8
- package/dist/esm/icons/input.js +75 -0
- package/dist/esm/icons/legal.js +4 -9
- package/dist/esm/icons/media.js +26 -11
- package/dist/esm/icons/navigation.js +4 -2
- package/dist/esm/icons/omniverk.js +19 -6
- package/dist/esm/icons/realestate.js +10 -4
- package/dist/esm/icons/saas.js +15 -4
- package/dist/esm/icons/science.js +6 -3
- package/dist/esm/icons/shapes.js +66 -31
- package/dist/esm/icons/sports.js +6 -2
- package/dist/esm/icons/ui.js +62 -21
- package/dist/esm/icons/weather.js +18 -8
- package/dist/esm/index.js +9 -8
- package/dist/esm/nicetodev-icons.css +1 -1
- package/dist/esm/resolver.js +46 -1
- package/dist/esm/rsc.js +1 -1
- package/dist/types/iconParts.d.ts +19 -0
- package/dist/types/icons/actions.d.ts +1 -0
- package/dist/types/icons/business.d.ts +2 -0
- package/dist/types/icons/ecommerce.d.ts +0 -2
- package/dist/types/icons/education.d.ts +1 -0
- package/dist/types/icons/files.d.ts +2 -1
- package/dist/types/icons/fun.d.ts +6 -1
- package/dist/types/icons/gaming.d.ts +2 -0
- package/dist/types/icons/index.d.ts +9 -8
- package/dist/types/icons/input.d.ts +53 -0
- package/dist/types/icons/omniverk.d.ts +0 -2
- package/dist/types/icons/ui.d.ts +1 -0
- package/dist/types/types.d.ts +6 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -81,12 +81,7 @@ function App() {
|
|
|
81
81
|
<NtdSearch size="md" animation="pulse" />
|
|
82
82
|
|
|
83
83
|
{/* Duotone heart with custom colors */}
|
|
84
|
-
<NtdHeart
|
|
85
|
-
variant="duotone"
|
|
86
|
-
primaryColor="#e74c3c"
|
|
87
|
-
secondaryColor="#fca5a5"
|
|
88
|
-
animation="heartbeat"
|
|
89
|
-
/>
|
|
84
|
+
<NtdHeart variant="duotone" primaryColor="#e74c3c" secondaryColor="#fca5a5" animation="heartbeat" />
|
|
90
85
|
</>
|
|
91
86
|
);
|
|
92
87
|
}
|
|
@@ -100,29 +95,29 @@ function App() {
|
|
|
100
95
|
|
|
101
96
|
Every icon component accepts these props (extends `SVGProps<SVGSVGElement>`):
|
|
102
97
|
|
|
103
|
-
| Prop
|
|
104
|
-
|
|
105
|
-
| `size`
|
|
106
|
-
| `variant`
|
|
107
|
-
| `primaryColor`
|
|
108
|
-
| `secondaryColor`
|
|
109
|
-
| `accentColor`
|
|
110
|
-
| `primaryOpacity`
|
|
111
|
-
| `secondaryOpacity`
|
|
112
|
-
| `accentOpacity`
|
|
113
|
-
| `strokeWidth`
|
|
114
|
-
| `strokeLinecap`
|
|
115
|
-
| `strokeLinejoin`
|
|
116
|
-
| `animation`
|
|
117
|
-
| `animationDuration` | `string`
|
|
118
|
-
| `gradient`
|
|
119
|
-
| `gradientType`
|
|
120
|
-
| `gradientAngle`
|
|
121
|
-
| `gradientAnimation` | `'shift' \| 'spin' \| 'pulse'`
|
|
122
|
-
| `title`
|
|
123
|
-
| `className`
|
|
124
|
-
| `style`
|
|
125
|
-
| `ref`
|
|
98
|
+
| Prop | Type | Default | Description |
|
|
99
|
+
| ------------------- | ------------------------------- | ---------------- | ------------------------------------- |
|
|
100
|
+
| `size` | `IconSize` | `'md'` | Named preset or pixel number |
|
|
101
|
+
| `variant` | `IconVariant` | `'solid'` | Rendering variant |
|
|
102
|
+
| `primaryColor` | `string` | `'currentColor'` | Main icon color |
|
|
103
|
+
| `secondaryColor` | `string` | `primaryColor` | Secondary color (duotone background) |
|
|
104
|
+
| `accentColor` | `string` | `'#ffffff'` | Accent color for detail elements |
|
|
105
|
+
| `primaryOpacity` | `number` | `1` | Opacity of primary elements (0–1) |
|
|
106
|
+
| `secondaryOpacity` | `number` | `0.4` | Opacity of secondary elements (0–1) |
|
|
107
|
+
| `accentOpacity` | `number` | `1` | Opacity of accent elements (0–1) |
|
|
108
|
+
| `strokeWidth` | `number` | `2` | Base stroke width for outline/duotone |
|
|
109
|
+
| `strokeLinecap` | `'round' \| 'square' \| 'butt'` | `'round'` | Stroke line cap style |
|
|
110
|
+
| `strokeLinejoin` | `'round' \| 'miter' \| 'bevel'` | `'round'` | Stroke line join style |
|
|
111
|
+
| `animation` | `IconAnimation` | `undefined` | CSS animation name |
|
|
112
|
+
| `animationDuration` | `string` | CSS default | Duration override (e.g. `'0.5s'`) |
|
|
113
|
+
| `gradient` | `GradientPreset` | `undefined` | Apply a gradient fill preset |
|
|
114
|
+
| `gradientType` | `'linear' \| 'radial'` | `'linear'` | Gradient shape |
|
|
115
|
+
| `gradientAngle` | `number` | `135` | Angle for linear gradients (degrees) |
|
|
116
|
+
| `gradientAnimation` | `'shift' \| 'spin' \| 'pulse'` | `undefined` | Animate the gradient |
|
|
117
|
+
| `title` | `string` | `undefined` | Accessible title for screen readers |
|
|
118
|
+
| `className` | `string` | `undefined` | Custom CSS class |
|
|
119
|
+
| `style` | `CSSProperties` | `undefined` | Inline styles |
|
|
120
|
+
| `ref` | `Ref<SVGSVGElement>` | — | Forward ref to the `<svg>` element |
|
|
126
121
|
|
|
127
122
|
Plus all standard `SVGProps<SVGSVGElement>` attributes (`onClick`, `id`, `data-*`, etc.).
|
|
128
123
|
|
|
@@ -135,7 +130,7 @@ type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'xxl' | 'xxxl' | numb
|
|
|
135
130
|
```
|
|
136
131
|
|
|
137
132
|
| Preset | Pixels |
|
|
138
|
-
|
|
133
|
+
| ------ | ------ |
|
|
139
134
|
| `xs` | 12 |
|
|
140
135
|
| `sm` | 16 |
|
|
141
136
|
| `md` | 24 |
|
|
@@ -157,12 +152,12 @@ The pixel map is exported as `SIZE_MAP: Record<string, number>`.
|
|
|
157
152
|
type IconVariant = 'solid' | 'outline' | 'duotone' | 'flat';
|
|
158
153
|
```
|
|
159
154
|
|
|
160
|
-
| Variant
|
|
161
|
-
|
|
162
|
-
| `solid`
|
|
163
|
-
| `outline` | Stroked paths with `fill="none"`
|
|
164
|
-
| `duotone` | Background shape at `secondaryOpacity` + foreground stroke
|
|
165
|
-
| `flat`
|
|
155
|
+
| Variant | Description |
|
|
156
|
+
| --------- | ----------------------------------------------------------------------------------- |
|
|
157
|
+
| `solid` | Filled shapes using `fill` |
|
|
158
|
+
| `outline` | Stroked paths with `fill="none"` |
|
|
159
|
+
| `duotone` | Background shape at `secondaryOpacity` + foreground stroke |
|
|
160
|
+
| `flat` | Colored badge background (`secondaryColor`, rounded rect) with solid content on top |
|
|
166
161
|
|
|
167
162
|
```tsx
|
|
168
163
|
<NtdHome variant="outline" primaryColor="#000" strokeWidth={1.5} />
|
|
@@ -175,10 +170,10 @@ type IconVariant = 'solid' | 'outline' | 'duotone' | 'flat';
|
|
|
175
170
|
```tsx
|
|
176
171
|
<NtdHeart
|
|
177
172
|
variant="duotone"
|
|
178
|
-
primaryColor="#e74c3c"
|
|
179
|
-
secondaryColor="#fca5a5"
|
|
180
|
-
secondaryOpacity={0.3}
|
|
181
|
-
accentColor="#fff"
|
|
173
|
+
primaryColor="#e74c3c" // foreground stroke
|
|
174
|
+
secondaryColor="#fca5a5" // background fill
|
|
175
|
+
secondaryOpacity={0.3} // background opacity
|
|
176
|
+
accentColor="#fff" // small details
|
|
182
177
|
/>
|
|
183
178
|
```
|
|
184
179
|
|
|
@@ -209,36 +204,36 @@ Apply gradient fills using the `gradient` prop with one of 12 built-in presets:
|
|
|
209
204
|
```tsx
|
|
210
205
|
<NtdHeart gradient="sunset" />
|
|
211
206
|
<NtdStar gradient="ocean" gradientType="radial" />
|
|
212
|
-
<
|
|
207
|
+
<NtdLightning gradient="neon" gradientAnimation="spin" />
|
|
213
208
|
<NtdGlobe gradient="aurora" gradientAngle={45} />
|
|
214
209
|
```
|
|
215
210
|
|
|
216
211
|
#### Available Presets (`GradientPreset`)
|
|
217
212
|
|
|
218
|
-
| Preset
|
|
219
|
-
|
|
220
|
-
| `sunset`
|
|
221
|
-
| `ocean`
|
|
222
|
-
| `forest`
|
|
223
|
-
| `fire`
|
|
224
|
-
| `ice`
|
|
225
|
-
| `neon`
|
|
226
|
-
| `gold`
|
|
227
|
-
| `purple-haze` | `#6c5ce7` → `#a55eea` → `#e056a0`
|
|
228
|
-
| `aurora`
|
|
229
|
-
| `midnight`
|
|
230
|
-
| `candy`
|
|
231
|
-
| `steel`
|
|
213
|
+
| Preset | Colors |
|
|
214
|
+
| ------------- | --------------------------------------------------- |
|
|
215
|
+
| `sunset` | `#ff6b6b` → `#feca57` → `#ff9ff3` |
|
|
216
|
+
| `ocean` | `#0652DD` → `#1B9CFC` → `#38ada9` |
|
|
217
|
+
| `forest` | `#0a3d0a` → `#1e8449` → `#58D68D` |
|
|
218
|
+
| `fire` | `#e74c3c` → `#f39c12` → `#f1c40f` |
|
|
219
|
+
| `ice` | `#74b9ff` → `#a29bfe` → `#dfe6e9` |
|
|
220
|
+
| `neon` | `#6c5ce7` → `#fd79a8` → `#00cec9` |
|
|
221
|
+
| `gold` | `#f9ca24` → `#f0932b` → `#e17055` |
|
|
222
|
+
| `purple-haze` | `#6c5ce7` → `#a55eea` → `#e056a0` |
|
|
223
|
+
| `aurora` | `#00b894` → `#00cec9` → `#0984e3` → `#6c5ce7` |
|
|
224
|
+
| `midnight` | `#0c0c1d` → `#1e3a5f` → `#2c3e50` |
|
|
225
|
+
| `candy` | `#ff6b81` → `#ffa502` → `#2ed573` |
|
|
226
|
+
| `steel` | `#636e72` → `#b2bec3` → `#dfe6e9` |
|
|
232
227
|
|
|
233
228
|
Color stops are exported as `GRADIENT_PRESETS: Record<GradientPreset, readonly string[]>`.
|
|
234
229
|
|
|
235
230
|
#### Gradient Animations (`GradientAnimation`)
|
|
236
231
|
|
|
237
|
-
| Animation | Effect
|
|
238
|
-
|
|
239
|
-
| `shift`
|
|
240
|
-
| `spin`
|
|
241
|
-
| `pulse`
|
|
232
|
+
| Animation | Effect |
|
|
233
|
+
| --------- | ------------------------------------------- |
|
|
234
|
+
| `shift` | Slides gradient colors horizontally |
|
|
235
|
+
| `spin` | Rotates the gradient around the icon center |
|
|
236
|
+
| `pulse` | Pulsates between stop colors |
|
|
242
237
|
|
|
243
238
|
Animations use SVG SMIL (`<animate>` / `<animateTransform>`) — no JavaScript runtime, works in all modern browsers.
|
|
244
239
|
|
|
@@ -265,9 +260,9 @@ import { NiceIconPicker, type IconPickerEntry } from '@nice2dev/icons';
|
|
|
265
260
|
import { NtdHome, NtdSearch, NtdHeart } from '@nice2dev/icons';
|
|
266
261
|
|
|
267
262
|
const icons: IconPickerEntry[] = [
|
|
268
|
-
{ name: 'NtdHome',
|
|
269
|
-
{ name: 'NtdSearch', Component: NtdSearch,
|
|
270
|
-
{ name: 'NtdHeart',
|
|
263
|
+
{ name: 'NtdHome', Component: NtdHome, category: 'UI' },
|
|
264
|
+
{ name: 'NtdSearch', Component: NtdSearch, category: 'Actions' },
|
|
265
|
+
{ name: 'NtdHeart', Component: NtdHeart, category: 'UI' },
|
|
271
266
|
];
|
|
272
267
|
|
|
273
268
|
function App() {
|
|
@@ -298,26 +293,26 @@ interface IconPickerEntry {
|
|
|
298
293
|
|
|
299
294
|
### NiceIconPickerProps
|
|
300
295
|
|
|
301
|
-
| Prop
|
|
302
|
-
|
|
303
|
-
| `icons`
|
|
304
|
-
| `value`
|
|
305
|
-
| `onChange`
|
|
306
|
-
| `placeholder`
|
|
307
|
-
| `variant`
|
|
308
|
-
| `gridIconSize`
|
|
309
|
-
| `triggerIconSize` | `IconSize \| number`
|
|
310
|
-
| `categories`
|
|
311
|
-
| `className`
|
|
312
|
-
| `disabled`
|
|
313
|
-
| `clearable`
|
|
296
|
+
| Prop | Type | Default | Description |
|
|
297
|
+
| ----------------- | ---------------------------------------------------------------- | ------------------ | ----------------------------- |
|
|
298
|
+
| `icons` | `IconPickerEntry[]` | **required** | Full icon registry |
|
|
299
|
+
| `value` | `string \| null` | `null` | Currently selected icon name |
|
|
300
|
+
| `onChange` | `(name: string \| null, entry: IconPickerEntry \| null) => void` | — | Selection callback |
|
|
301
|
+
| `placeholder` | `string` | `'Select icon…'` | Placeholder text |
|
|
302
|
+
| `variant` | `IconVariant` | `'solid'` | Variant for grid preview |
|
|
303
|
+
| `gridIconSize` | `IconSize \| number` | `'md'` | Icon size in the grid |
|
|
304
|
+
| `triggerIconSize` | `IconSize \| number` | `'sm'` | Icon size in trigger button |
|
|
305
|
+
| `categories` | `string[]` | auto-detected | Ordered category tab names |
|
|
306
|
+
| `className` | `string` | — | Additional CSS class |
|
|
307
|
+
| `disabled` | `boolean` | `false` | Disable the picker |
|
|
308
|
+
| `clearable` | `boolean` | `true` | Show "Clear selection" button |
|
|
314
309
|
|
|
315
310
|
### NiceIconPickerHandle (imperative ref)
|
|
316
311
|
|
|
317
312
|
```tsx
|
|
318
313
|
const ref = useRef<NiceIconPickerHandle>(null);
|
|
319
|
-
ref.current?.open();
|
|
320
|
-
ref.current?.close();
|
|
314
|
+
ref.current?.open(); // programmatically open
|
|
315
|
+
ref.current?.close(); // programmatically close
|
|
321
316
|
ref.current?.toggle(); // toggle open/closed
|
|
322
317
|
```
|
|
323
318
|
|
|
@@ -340,11 +335,9 @@ import { createIcon } from '@nice2dev/icons';
|
|
|
340
335
|
|
|
341
336
|
export const NtdMyIcon = createIcon({
|
|
342
337
|
displayName: 'NtdMyIcon',
|
|
343
|
-
viewBox: '0 0 24 24',
|
|
338
|
+
viewBox: '0 0 24 24', // optional, defaults to '0 0 24 24'
|
|
344
339
|
paths: {
|
|
345
|
-
solid: ({ primaryColor }) =>
|
|
346
|
-
<path d="M12 2l10 20H2z" fill={primaryColor} />
|
|
347
|
-
),
|
|
340
|
+
solid: ({ primaryColor }) => <path d="M12 2l10 20H2z" fill={primaryColor} />,
|
|
348
341
|
outline: ({ primaryColor, strokeWidth }) => (
|
|
349
342
|
<path d="M12 2l10 20H2z" stroke={primaryColor} strokeWidth={strokeWidth} fill="none" />
|
|
350
343
|
),
|
|
@@ -364,19 +357,19 @@ export const NtdMyIcon = createIcon({
|
|
|
364
357
|
});
|
|
365
358
|
|
|
366
359
|
// Usage — exactly like any built-in icon:
|
|
367
|
-
<NtdMyIcon size="lg" variant="duotone" primaryColor="#8b5cf6" animation="pulse"
|
|
360
|
+
<NtdMyIcon size="lg" variant="duotone" primaryColor="#8b5cf6" animation="pulse" />;
|
|
368
361
|
```
|
|
369
362
|
|
|
370
363
|
### CreateIconOptions
|
|
371
364
|
|
|
372
|
-
| Field
|
|
373
|
-
|
|
374
|
-
| `displayName`
|
|
375
|
-
| `viewBox`
|
|
376
|
-
| `paths.solid`
|
|
377
|
-
| `paths.outline` | `IconPathRenderer` | **required**
|
|
378
|
-
| `paths.duotone` | `IconPathRenderer` | **required**
|
|
379
|
-
| `paths.flat`
|
|
365
|
+
| Field | Type | Default | Description |
|
|
366
|
+
| --------------- | ------------------ | ------------- | ----------------------------- |
|
|
367
|
+
| `displayName` | `string` | **required** | React display name |
|
|
368
|
+
| `viewBox` | `string` | `'0 0 24 24'` | SVG viewBox |
|
|
369
|
+
| `paths.solid` | `IconPathRenderer` | **required** | Solid variant renderer |
|
|
370
|
+
| `paths.outline` | `IconPathRenderer` | **required** | Outline variant renderer |
|
|
371
|
+
| `paths.duotone` | `IconPathRenderer` | **required** | Duotone variant renderer |
|
|
372
|
+
| `paths.flat` | `IconPathRenderer` | **required** | Flat (badge) variant renderer |
|
|
380
373
|
|
|
381
374
|
### IconPathRenderer
|
|
382
375
|
|
|
@@ -388,69 +381,85 @@ type IconPathRenderer = (props: IconRenderProps) => React.ReactNode;
|
|
|
388
381
|
|
|
389
382
|
Properties passed to every path renderer (pre-resolved from user props):
|
|
390
383
|
|
|
391
|
-
| Prop
|
|
392
|
-
|
|
393
|
-
| `variant`
|
|
394
|
-
| `primaryColor`
|
|
395
|
-
| `secondaryColor`
|
|
396
|
-
| `accentColor`
|
|
397
|
-
| `primaryOpacity`
|
|
398
|
-
| `secondaryOpacity` | `number`
|
|
399
|
-
| `accentOpacity`
|
|
400
|
-
| `strokeWidth`
|
|
401
|
-
| `strokeLinecap`
|
|
402
|
-
| `strokeLinejoin`
|
|
384
|
+
| Prop | Type | Description |
|
|
385
|
+
| ------------------ | ------------------------------- | ------------------------ |
|
|
386
|
+
| `variant` | `IconVariant` | Active variant |
|
|
387
|
+
| `primaryColor` | `string` | Resolved primary color |
|
|
388
|
+
| `secondaryColor` | `string` | Resolved secondary color |
|
|
389
|
+
| `accentColor` | `string` | Resolved accent color |
|
|
390
|
+
| `primaryOpacity` | `number` | Primary opacity |
|
|
391
|
+
| `secondaryOpacity` | `number` | Secondary opacity |
|
|
392
|
+
| `accentOpacity` | `number` | Accent opacity |
|
|
393
|
+
| `strokeWidth` | `number` | Stroke width |
|
|
394
|
+
| `strokeLinecap` | `'round' \| 'square' \| 'butt'` | Stroke line cap |
|
|
395
|
+
| `strokeLinejoin` | `'round' \| 'miter' \| 'bevel'` | Stroke line join |
|
|
403
396
|
|
|
404
397
|
---
|
|
405
398
|
|
|
406
399
|
## Full Icon Catalog
|
|
407
400
|
|
|
408
401
|
### Navigation (14 icons)
|
|
402
|
+
|
|
409
403
|
`NtdArrowUp` · `NtdArrowDown` · `NtdArrowLeft` · `NtdArrowRight` · `NtdChevronUp` · `NtdChevronDown` · `NtdChevronLeft` · `NtdChevronRight` · `NtdMenu` · `NtdClose` · `NtdMoreHorizontal` · `NtdMoreVertical` · `NtdExternalLink` · `NtdRefresh`
|
|
410
404
|
|
|
411
405
|
### Actions (25 icons)
|
|
406
|
+
|
|
412
407
|
`NtdSearch` · `NtdEdit` · `NtdTrash` · `NtdSave` · `NtdDownload` · `NtdUpload` · `NtdShare` · `NtdCopy` · `NtdClipboard` · `NtdPlus` · `NtdMinus` · `NtdCheck` · `NtdFilter` · `NtdSort` · `NtdPrint` · `NtdZoomIn` · `NtdZoomOut` · `NtdUndo` · `NtdRedo` · `NtdLink` · `NtdSettings` · `NtdLogIn` · `NtdLogOut` · `NtdLock` · `NtdUnlock`
|
|
413
408
|
|
|
414
409
|
### UI & Status (26 icons)
|
|
410
|
+
|
|
415
411
|
`NtdHome` · `NtdUser` · `NtdUsers` · `NtdHeart` · `NtdStar` · `NtdBell` · `NtdEye` · `NtdEyeOff` · `NtdInfo` · `NtdWarning` · `NtdError` · `NtdSuccess` · `NtdHelp` · `NtdClock` · `NtdCalendar` · `NtdTag` · `NtdBookmark` · `NtdFlag` · `NtdThumbUp` · `NtdThumbDown` · `NtdShield` · `NtdGlobe` · `NtdMap` · `NtdPin` · `NtdSun` · `NtdMoon`
|
|
416
412
|
|
|
417
413
|
### Media & Communication (19 icons)
|
|
414
|
+
|
|
418
415
|
`NtdPlay` · `NtdPause` · `NtdStop` · `NtdSkipForward` · `NtdSkipBack` · `NtdVolume` · `NtdVolumeMute` · `NtdImage` · `NtdCamera` · `NtdVideo` · `NtdMicrophone` · `NtdMusic` · `NtdMail` · `NtdPhone` · `NtdChat` · `NtdSend` · `NtdNotification` · `NtdWifi` · `NtdBluetooth`
|
|
419
416
|
|
|
420
|
-
### Files & Misc (
|
|
421
|
-
|
|
417
|
+
### Files & Misc (30 icons)
|
|
418
|
+
|
|
419
|
+
`NtdFile` · `NtdFileText` · `NtdFolder` · `NtdFolderOpen` · `NtdArchive` · `NtdDatabase` · `NtdCloud` · `NtdCloudUpload` · `NtdCloudDownload` · `NtdTerminal` · `NtdCode` · `NtdGit` · `NtdPackage` · `NtdLayers` · `NtdGrid` · `NtdList` · `NtdTable` · `NtdSmartphone` · `NtdMonitor` · `NtdCpu` · `NtdKey` · `NtdAward` · `NtdCoffee` · `NtdCart` · `NtdCreditCard` · `NtdPieChart` · `NtdBarChart` · `NtdActivity` · `NtdTarget` · `NtdTruck`
|
|
422
420
|
|
|
423
421
|
### Fun & Emoji (13 icons)
|
|
424
|
-
|
|
422
|
+
|
|
423
|
+
`NtdDumpsterFire` · `NtdRocket` · `NtdGamepadOldschool` · `NtdPuzzle` · `NtdPartyPopper` · `NtdTrophy` · `NtdCrown` · `NtdDice` · `NtdSmile` · `NtdSad` · `NtdSkull` · `NtdGhost` · `NtdLightning`
|
|
425
424
|
|
|
426
425
|
### Weather & Nature (20 icons)
|
|
426
|
+
|
|
427
427
|
`NtdSunrise` · `NtdSunset` · `NtdRain` · `NtdSnow` · `NtdThunderstorm` · `NtdWind` · `NtdDroplet` · `NtdThermometer` · `NtdUmbrella` · `NtdLeaf` · `NtdFlower` · `NtdTree` · `NtdMountain` · `NtdWave` · `NtdFire` · `NtdSnowflake` · `NtdCompass` · `NtdAnchor` · `NtdFeather` · `NtdBug`
|
|
428
428
|
|
|
429
429
|
### Arrows & Shapes (22 icons)
|
|
430
|
+
|
|
430
431
|
`NtdArrowUpCircle` · `NtdArrowDownCircle` · `NtdArrowLeftCircle` · `NtdArrowRightCircle` · `NtdSquare` · `NtdCircle` · `NtdTriangle` · `NtdHexagon` · `NtdOctagon` · `NtdDiamond` · `NtdPentagon` · `NtdCross` · `NtdStar4` · `NtdCornerUpLeft` · `NtdCornerUpRight` · `NtdCornerDownLeft` · `NtdCornerDownRight` · `NtdMaximize` · `NtdMinimize` · `NtdMove` · `NtdRepeat` · `NtdShuffle`
|
|
431
432
|
|
|
432
433
|
### Business & Finance (16 icons)
|
|
434
|
+
|
|
433
435
|
`NtdBriefcase` · `NtdDollar` · `NtdWallet` · `NtdReceipt` · `NtdBank` · `NtdTrendUp` · `NtdTrendDown` · `NtdPercent` · `NtdInvoice` · `NtdStore` · `NtdBarcode` · `NtdCalculator` · `NtdPresentation` · `NtdClipboardCheck` · `NtdPiggyBank` · `NtdCoins`
|
|
434
436
|
|
|
435
437
|
### Social & Communication (8 icons)
|
|
438
|
+
|
|
436
439
|
`NtdAtSign` · `NtdPhoneOff` · `NtdBubble` · `NtdThumbsUp` · `NtdThumbsDown` · `NtdBellRing` · `NtdMegaphone` · `NtdQrCode`
|
|
437
440
|
|
|
438
441
|
### Dev & Tech (9 icons)
|
|
442
|
+
|
|
439
443
|
`NtdBrackets` · `NtdServer` · `NtdGitBranch` · `NtdGitCommit` · `NtdGitMerge` · `NtdBattery` · `NtdSlash` · `NtdHash` · `NtdBugDev`
|
|
440
444
|
|
|
441
445
|
### Food & Health (13 icons)
|
|
446
|
+
|
|
442
447
|
`NtdApple` · `NtdPizza` · `NtdGlass` · `NtdHeartPulse` · `NtdPill` · `NtdSyringe` · `NtdStethoscope` · `NtdWeight` · `NtdBandaid` · `NtdCake` · `NtdEgg` · `NtdHamburger` · `NtdDna`
|
|
443
448
|
|
|
444
449
|
### Brand & Logo (14 icons)
|
|
450
|
+
|
|
445
451
|
`NtdNiceToDev` · `NtdNiceMonogram` · `NtdNiceOrbit` · `NtdNiceSpark` · `NtdNiceShield` · `NtdNiceBadge` · `NtdNiceCore` · `NtdNiceCrest` · `NtdNiceHelix` · `NtdNicePortal` · `NtdNicePulseMark` · `NtdNiceFlagship` · `NtdOmniVerk` · `NtdOmniVerkLogo`
|
|
446
452
|
|
|
447
453
|
### Brand Studio (25 icons)
|
|
454
|
+
|
|
448
455
|
`NtdStudioGrid` · `NtdStudioBlueprint` · `NtdStudioCursor` · `NtdStudioPrototype` · `NtdStudioComponent` · `NtdStudioToken` · `NtdStudioPalette` · `NtdStudioBrush` · `NtdStudioPenTool` · `NtdStudioLayerStack` · `NtdStudioSpline` · `NtdStudioNodes` · `NtdStudioFlow` · `NtdStudioRelease` · `NtdStudioRocketMark` · `NtdStudioAIBrain` · `NtdStudioNeural` · `NtdStudioChipmark` · `NtdStudioTerminalMark` · `NtdStudioForge` · `NtdStudioWireframe` · `NtdStudioPersona` · `NtdStudioBenchmark` · `NtdStudioStudio` · `NtdStudioBeacon`
|
|
449
456
|
|
|
450
457
|
### Brand Lockups (4 icons)
|
|
458
|
+
|
|
451
459
|
`NtdNiceLockupHorizontal` · `NtdNiceLockupStacked` · `NtdNiceWordmark` · `NtdNiceSymbolWordmark`
|
|
452
460
|
|
|
453
461
|
### Brand Enterprise (18 icons)
|
|
462
|
+
|
|
454
463
|
`NtdEnterpriseRoadmap` · `NtdEnterpriseBacklog` · `NtdEnterpriseKanban` · `NtdEnterpriseSprint` · `NtdEnterpriseMilestone` · `NtdEnterprisePipeline` · `NtdEnterpriseDeploy` · `NtdEnterpriseMonitor` · `NtdEnterpriseAlert` · `NtdEnterpriseSla` · `NtdEnterpriseKpi` · `NtdEnterpriseRevenue` · `NtdEnterpriseRisk` · `NtdEnterpriseCompliance` · `NtdEnterpriseGateway` · `NtdEnterpriseDataMesh` · `NtdEnterpriseFeatureFlag` · `NtdEnterpriseWorkspace`
|
|
455
464
|
|
|
456
465
|
---
|
|
@@ -458,27 +467,35 @@ Properties passed to every path renderer (pre-resolved from user props):
|
|
|
458
467
|
## Full Animation Catalog
|
|
459
468
|
|
|
460
469
|
### Core Transforms (13)
|
|
470
|
+
|
|
461
471
|
`spin` · `spin-reverse` · `pulse` · `bounce` · `shake` · `float` · `flip` · `glow` · `wiggle` · `rubber` · `swing` · `tada` · `heartbeat`
|
|
462
472
|
|
|
463
473
|
### Entrance Animations (22)
|
|
474
|
+
|
|
464
475
|
`fade-in` · `slide-up` · `slide-down` · `slide-left` · `slide-right` · `drop` · `rise` · `roll-in` · `materialize` · `vortex` · `meteor` · `scale-in` · `signature` · `draw-sequence` · `stroke-order` · `glow-trace` · `seal-stamp` · `reveal` · `typewriter` · `unfold` · `assemble` · `draw` · `draw-from-dot`
|
|
465
476
|
|
|
466
477
|
### Exit Animations (3)
|
|
478
|
+
|
|
467
479
|
`scale-out` · `fold` · `dissolve`
|
|
468
480
|
|
|
469
481
|
### Organic / Natural (10)
|
|
482
|
+
|
|
470
483
|
`breathe` · `drift` · `orbit` · `sway` · `tilt` · `rock` · `pendulum` · `levitate` · `flap` · `skate`
|
|
471
484
|
|
|
472
485
|
### Energetic / Impact (10)
|
|
486
|
+
|
|
473
487
|
`jello` · `pop` · `squeeze` · `crush` · `stretch` · `stomp` · `snap` · `twist` · `dash` · `surge`
|
|
474
488
|
|
|
475
489
|
### Effects / Digital (8)
|
|
490
|
+
|
|
476
491
|
`flash` · `blink` · `flicker` · `vibrate` · `tremble` · `glitch` · `neon` · `earthquake`
|
|
477
492
|
|
|
478
493
|
### Complex Transforms (7)
|
|
494
|
+
|
|
479
495
|
`wobble` · `spiral` · `warp` · `morph` · `zoom-pulse` · `ripple` · `radar`
|
|
480
496
|
|
|
481
497
|
### Dramatic (6)
|
|
498
|
+
|
|
482
499
|
`ping` · `implode` · `explode` · `scatter` · `rotate-x` · `draw-loop`
|
|
483
500
|
|
|
484
501
|
---
|
|
@@ -539,6 +556,7 @@ npm run build-storybook # static build to storybook-static/
|
|
|
539
556
|
```
|
|
540
557
|
|
|
541
558
|
Stories cover:
|
|
559
|
+
|
|
542
560
|
- **Components/Icon** — all props, variants, sizes, colors, animations
|
|
543
561
|
- **Components/NiceIconPicker** — controlled picker, disabled, outline variant
|
|
544
562
|
- **Components/Animations** — full gallery of 65+ animations
|
|
@@ -569,11 +587,13 @@ dist/
|
|
|
569
587
|
```
|
|
570
588
|
|
|
571
589
|
Entry points in `package.json`:
|
|
590
|
+
|
|
572
591
|
- `main` → `dist/cjs/index.js`
|
|
573
592
|
- `module` → `dist/esm/index.js`
|
|
574
593
|
- `types` → `dist/types/index.d.ts`
|
|
575
594
|
|
|
576
595
|
---
|
|
596
|
+
|
|
577
597
|
## React Server Components (RSC)
|
|
578
598
|
|
|
579
599
|
Use icons in Server Components without "use client":
|
|
@@ -585,7 +605,7 @@ import { createIconRSC } from '@nice2dev/icons/rsc';
|
|
|
585
605
|
// Create RSC-compatible icon
|
|
586
606
|
const HomeIcon = createIconRSC({
|
|
587
607
|
displayName: 'HomeIcon',
|
|
588
|
-
paths: {
|
|
608
|
+
paths: {/* ... */},
|
|
589
609
|
});
|
|
590
610
|
|
|
591
611
|
export default function Page() {
|
|
@@ -595,11 +615,11 @@ export default function Page() {
|
|
|
595
615
|
|
|
596
616
|
### RSC vs Client Exports
|
|
597
617
|
|
|
598
|
-
| Import Path
|
|
599
|
-
|
|
600
|
-
| `@nice2dev/icons`
|
|
601
|
-
| `@nice2dev/icons/rsc`
|
|
602
|
-
| `@nice2dev/icons/client` | Client-only features ("use client" directive)
|
|
618
|
+
| Import Path | Use Case |
|
|
619
|
+
| ------------------------ | ------------------------------------------------------------ |
|
|
620
|
+
| `@nice2dev/icons` | Standard usage (includes animations, color scheme detection) |
|
|
621
|
+
| `@nice2dev/icons/rsc` | Server Components (no hooks, streaming-friendly) |
|
|
622
|
+
| `@nice2dev/icons/client` | Client-only features ("use client" directive) |
|
|
603
623
|
|
|
604
624
|
### RSC Utilities
|
|
605
625
|
|
|
@@ -662,11 +682,11 @@ const figmaTokens = toFigmaTokens(tokens);
|
|
|
662
682
|
|
|
663
683
|
### Default Token Values
|
|
664
684
|
|
|
665
|
-
| Category | Tokens
|
|
666
|
-
|
|
667
|
-
| Sizes
|
|
668
|
-
| Colors
|
|
669
|
-
| Strokes
|
|
685
|
+
| Category | Tokens |
|
|
686
|
+
| -------- | -------------------------------------------------------------------------------- |
|
|
687
|
+
| Sizes | `xs` (12px), `sm` (16px), `md` (24px), `lg` (32px), `xl` (48px), `2xl` (64px) |
|
|
688
|
+
| Colors | `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`, `muted` |
|
|
689
|
+
| Strokes | `thin` (1), `normal` (1.5), `medium` (2), `thick` (2.5), `bold` (3) |
|
|
670
690
|
|
|
671
691
|
---
|
|
672
692
|
|
|
@@ -676,12 +696,7 @@ Seamless integration with Radix UI, Headless UI, and shadcn/ui:
|
|
|
676
696
|
|
|
677
697
|
```tsx
|
|
678
698
|
import { NtdSettings, NtdChevronDown } from '@nice2dev/icons';
|
|
679
|
-
import {
|
|
680
|
-
forwardRefIcon,
|
|
681
|
-
createRadixIcon,
|
|
682
|
-
withRadixState,
|
|
683
|
-
shadcnIconClasses,
|
|
684
|
-
} from '@nice2dev/icons/headless-ui';
|
|
699
|
+
import { forwardRefIcon, createRadixIcon, withRadixState, shadcnIconClasses } from '@nice2dev/icons/headless-ui';
|
|
685
700
|
|
|
686
701
|
// Create ref-compatible icon for Radix asChild pattern
|
|
687
702
|
const SettingsIcon = forwardRefIcon(NtdSettings);
|
|
@@ -698,7 +713,7 @@ const ChevronIcon = withRadixState(NtdChevronDown);
|
|
|
698
713
|
<Button>
|
|
699
714
|
<SettingsIcon className={shadcnIconClasses.buttonLeft} />
|
|
700
715
|
Settings
|
|
701
|
-
</Button
|
|
716
|
+
</Button>;
|
|
702
717
|
```
|
|
703
718
|
|
|
704
719
|
### shadcn/ui Class Presets
|
|
@@ -715,7 +730,7 @@ shadcnIconClasses = {
|
|
|
715
730
|
dropdown: 'mr-2 h-4 w-4',
|
|
716
731
|
spinner: 'h-4 w-4 animate-spin',
|
|
717
732
|
// ...
|
|
718
|
-
}
|
|
733
|
+
};
|
|
719
734
|
```
|
|
720
735
|
|
|
721
736
|
### Dynamic Class Generation
|
|
@@ -747,29 +762,25 @@ import {
|
|
|
747
762
|
createAccessibleIconProps,
|
|
748
763
|
isIconComponent,
|
|
749
764
|
isValidIconName,
|
|
750
|
-
useBatchIcons
|
|
765
|
+
useBatchIcons,
|
|
751
766
|
} from '@nice2dev/icons/utilities';
|
|
752
767
|
|
|
753
768
|
// Dynamic icon loading with suspense support
|
|
754
769
|
function DynamicIcon({ name }: { name: string }) {
|
|
755
770
|
const { icon: Icon, loading, error } = useIcon(name);
|
|
756
|
-
|
|
771
|
+
|
|
757
772
|
if (loading) return <span>Loading...</span>;
|
|
758
773
|
if (error) return <span>Icon not found</span>;
|
|
759
774
|
if (!Icon) return null;
|
|
760
|
-
|
|
775
|
+
|
|
761
776
|
return <Icon className="w-6 h-6" />;
|
|
762
777
|
}
|
|
763
778
|
|
|
764
779
|
// Respect user's reduced motion preference
|
|
765
780
|
function AnimatedIcon() {
|
|
766
781
|
const prefersReducedMotion = useReducedMotion();
|
|
767
|
-
|
|
768
|
-
return
|
|
769
|
-
<NtdSpinner
|
|
770
|
-
className={prefersReducedMotion ? '' : 'animate-spin'}
|
|
771
|
-
/>
|
|
772
|
-
);
|
|
782
|
+
|
|
783
|
+
return <NtdSpinner className={prefersReducedMotion ? '' : 'animate-spin'} />;
|
|
773
784
|
}
|
|
774
785
|
|
|
775
786
|
// Preload icons for better performance
|
|
@@ -821,6 +832,7 @@ npx @nice2dev/icons info NtdHeart
|
|
|
821
832
|
```
|
|
822
833
|
|
|
823
834
|
---
|
|
835
|
+
|
|
824
836
|
## License
|
|
825
837
|
|
|
826
838
|
MIT © NiceToDev
|
|
@@ -74,6 +74,8 @@ function saveToStorage(key, value) {
|
|
|
74
74
|
*/
|
|
75
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) {
|
|
76
76
|
var _a;
|
|
77
|
+
const tablistRef = React.useRef(null);
|
|
78
|
+
uiCore.useRovingFocus(tablistRef, { orientation: 'horizontal', wrap: true, activateOnMove: true });
|
|
77
79
|
const { t } = uiCore.useNiceTranslation();
|
|
78
80
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
79
81
|
const [search, setSearch] = React.useState('');
|
|
@@ -225,30 +227,26 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
|
|
|
225
227
|
document.addEventListener('mousedown', onClickOutside);
|
|
226
228
|
return () => document.removeEventListener('mousedown', onClickOutside);
|
|
227
229
|
}, [isOpen]);
|
|
228
|
-
/* ───
|
|
230
|
+
/* ─── Reset on close ─── */
|
|
229
231
|
React.useEffect(() => {
|
|
230
|
-
if (isOpen) {
|
|
231
|
-
requestAnimationFrame(() => { var _a; return (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
232
|
+
if (!isOpen) {
|
|
234
233
|
setSearch('');
|
|
235
234
|
setActiveCategory(null);
|
|
236
235
|
setVisibleRange({ start: 0, end: virtualizedItemCount });
|
|
237
236
|
}
|
|
238
237
|
}, [isOpen, virtualizedItemCount]);
|
|
239
|
-
/* ─── Keyboard ─── */
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}, [isOpen]);
|
|
238
|
+
/* ─── Keyboard and pad (1.3.0) ─── */
|
|
239
|
+
// The panel is a dialog on the overlay stack: focus on the search field when it opens, Escape
|
|
240
|
+
// / B close only it (a document listener before) and focus returns to the trigger. The icon
|
|
241
|
+
// grid is an APG listbox moving in two dimensions — the cells were reachable by Tab only.
|
|
242
|
+
const dropdownRef = React.useRef(null);
|
|
243
|
+
uiCore.useOverlayFocus(dropdownRef, {
|
|
244
|
+
open: isOpen,
|
|
245
|
+
modal: false,
|
|
246
|
+
initialFocus: searchInputRef,
|
|
247
|
+
onClose: () => setIsOpen(false),
|
|
248
|
+
});
|
|
249
|
+
uiCore.useRovingFocus(gridWrapRef, { orientation: 'grid', itemSelector: '.ntd-picker-cell' });
|
|
252
250
|
/* ─── Virtualization scroll handler ─── */
|
|
253
251
|
React.useEffect(() => {
|
|
254
252
|
if (!virtualized || !isOpen || !gridWrapRef.current) {
|
|
@@ -396,7 +394,7 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
|
|
|
396
394
|
? readableName(selectedEntry.name)
|
|
397
395
|
: (placeholder !== null && placeholder !== void 0 ? placeholder : t('iconPicker.selectIcon', 'Select icon…'));
|
|
398
396
|
}, [multiSelect, selectedEntries, selectedEntry, placeholder, t]);
|
|
399
|
-
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", { className: "ntd-picker-dropdown", role: "
|
|
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__'
|
|
400
398
|
? t('iconPicker.noFavoritesYetClickThe', 'No favorites yet. Click the star icon to add.')
|
|
401
399
|
: activeCategory === '__history__'
|
|
402
400
|
? t('iconPicker.noRecentIcons', 'No recent icons.')
|