@nice2dev/icons 1.2.0 → 1.2.2

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/dist/cjs/NiceDesktopIconExporter.js +7 -7
  3. package/dist/cjs/NiceFaviconGenerator.js +7 -2
  4. package/dist/cjs/NiceIconPicker.js +32 -27
  5. package/dist/cjs/NiceIconPreview.js +3 -1
  6. package/dist/cjs/NiceIconSetCreator.js +12 -30
  7. package/dist/cjs/NtdIconBadge.js +30 -15
  8. package/dist/cjs/NtdIconMorph.js +24 -12
  9. package/dist/cjs/NtdStateMorph.js +3 -3
  10. package/dist/cjs/animationControls.js +10 -3
  11. package/dist/cjs/createIcon.js +5 -2
  12. package/dist/cjs/design-tokens.js +2 -0
  13. package/dist/cjs/headless-ui.js +3 -3
  14. package/dist/cjs/iconMetadata.js +4 -0
  15. package/dist/cjs/iconStyles.js +36 -34
  16. package/dist/cjs/icons/accessibility.js +13 -13
  17. package/dist/cjs/icons/actions.js +59 -25
  18. package/dist/cjs/icons/ai.js +15 -15
  19. package/dist/cjs/icons/brand.js +7 -7
  20. package/dist/cjs/icons/business.js +18 -81
  21. package/dist/cjs/icons/devtech.js +31 -103
  22. package/dist/cjs/icons/ecommerce.js +16 -16
  23. package/dist/cjs/icons/education.js +17 -17
  24. package/dist/cjs/icons/files.js +31 -31
  25. package/dist/cjs/icons/fintech.js +14 -14
  26. package/dist/cjs/icons/food.js +16 -16
  27. package/dist/cjs/icons/fun.js +13 -13
  28. package/dist/cjs/icons/gaming.js +15 -15
  29. package/dist/cjs/icons/health.js +13 -22
  30. package/dist/cjs/icons/index.js +12 -0
  31. package/dist/cjs/icons/legal.js +13 -13
  32. package/dist/cjs/icons/media.js +46 -23
  33. package/dist/cjs/icons/navigation.js +14 -14
  34. package/dist/cjs/icons/omniverk.js +10 -10
  35. package/dist/cjs/icons/realestate.js +17 -17
  36. package/dist/cjs/icons/saas.js +13 -13
  37. package/dist/cjs/icons/science.js +16 -16
  38. package/dist/cjs/icons/shapes.js +89 -22
  39. package/dist/cjs/icons/smarthome.js +13 -13
  40. package/dist/cjs/icons/social.js +8 -98
  41. package/dist/cjs/icons/sports.js +14 -14
  42. package/dist/cjs/icons/sustainability.js +15 -15
  43. package/dist/cjs/icons/travel.js +15 -15
  44. package/dist/cjs/icons/ui.js +39 -28
  45. package/dist/cjs/icons/weather.js +20 -20
  46. package/dist/cjs/index.js +12 -0
  47. package/dist/cjs/lottieIntegration.js +3 -3
  48. package/dist/cjs/nicetodev-icons.css +1 -1
  49. package/dist/cjs/particleEffects.js +11 -4
  50. package/dist/cjs/resolver.js +13 -0
  51. package/dist/cjs/utilities.js +4 -2
  52. package/dist/esm/NiceDesktopIconExporter.js +7 -7
  53. package/dist/esm/NiceFaviconGenerator.js +7 -2
  54. package/dist/esm/NiceIconPicker.js +33 -28
  55. package/dist/esm/NiceIconPreview.js +3 -1
  56. package/dist/esm/NiceIconSetCreator.js +12 -30
  57. package/dist/esm/NtdIconBadge.js +30 -15
  58. package/dist/esm/NtdIconMorph.js +24 -12
  59. package/dist/esm/NtdStateMorph.js +3 -3
  60. package/dist/esm/animationControls.js +11 -4
  61. package/dist/esm/createIcon.js +6 -3
  62. package/dist/esm/design-tokens.js +2 -0
  63. package/dist/esm/headless-ui.js +3 -3
  64. package/dist/esm/iconMetadata.js +4 -0
  65. package/dist/esm/iconStyles.js +36 -34
  66. package/dist/esm/icons/accessibility.js +13 -13
  67. package/dist/esm/icons/actions.js +57 -26
  68. package/dist/esm/icons/ai.js +15 -15
  69. package/dist/esm/icons/brand.js +7 -7
  70. package/dist/esm/icons/business.js +18 -81
  71. package/dist/esm/icons/devtech.js +31 -103
  72. package/dist/esm/icons/ecommerce.js +16 -16
  73. package/dist/esm/icons/education.js +17 -17
  74. package/dist/esm/icons/files.js +31 -31
  75. package/dist/esm/icons/fintech.js +14 -14
  76. package/dist/esm/icons/food.js +16 -16
  77. package/dist/esm/icons/fun.js +13 -13
  78. package/dist/esm/icons/gaming.js +15 -15
  79. package/dist/esm/icons/health.js +13 -22
  80. package/dist/esm/icons/index.js +4 -4
  81. package/dist/esm/icons/legal.js +13 -13
  82. package/dist/esm/icons/media.js +45 -24
  83. package/dist/esm/icons/navigation.js +14 -14
  84. package/dist/esm/icons/omniverk.js +10 -10
  85. package/dist/esm/icons/realestate.js +17 -17
  86. package/dist/esm/icons/saas.js +13 -13
  87. package/dist/esm/icons/science.js +16 -16
  88. package/dist/esm/icons/shapes.js +84 -23
  89. package/dist/esm/icons/smarthome.js +13 -13
  90. package/dist/esm/icons/social.js +8 -98
  91. package/dist/esm/icons/sports.js +14 -14
  92. package/dist/esm/icons/sustainability.js +15 -15
  93. package/dist/esm/icons/travel.js +15 -15
  94. package/dist/esm/icons/ui.js +39 -29
  95. package/dist/esm/icons/weather.js +20 -20
  96. package/dist/esm/index.js +4 -4
  97. package/dist/esm/lottieIntegration.js +3 -3
  98. package/dist/esm/nicetodev-icons.css +1 -1
  99. package/dist/esm/particleEffects.js +11 -4
  100. package/dist/esm/resolver.js +13 -0
  101. package/dist/esm/smilAnimations.js +1 -1
  102. package/dist/esm/utilities.js +4 -2
  103. package/dist/types/NiceDesktopIconExporter.d.ts +1 -0
  104. package/dist/types/NtdIconBadge.d.ts +12 -4
  105. package/dist/types/NtdIconMorph.d.ts +9 -3
  106. package/dist/types/NtdStateMorph.d.ts +3 -1
  107. package/dist/types/design-tokens.d.ts +2 -0
  108. package/dist/types/headless-ui.d.ts +6 -2
  109. package/dist/types/iconStyles.d.ts +33 -11
  110. package/dist/types/icons/actions.d.ts +3 -0
  111. package/dist/types/icons/index.d.ts +4 -4
  112. package/dist/types/icons/media.d.ts +3 -0
  113. package/dist/types/icons/shapes.d.ts +6 -0
  114. package/dist/types/icons/ui.d.ts +2 -0
  115. package/dist/types/lottieIntegration.d.ts +3 -1
  116. package/dist/types/particleEffects.d.ts +3 -1
  117. package/package.json +3 -1
@@ -1,4 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
2
3
  import { useState, useMemo, useCallback } from 'react';
3
4
 
4
5
  /* ══════════════════════════════════════════════════════════════════════════════
@@ -624,28 +625,27 @@ Note: iconutil is only available on macOS.
624
625
  * ```
625
626
  */
626
627
  const NiceDesktopIconExporter = ({ icon, initialConfig, onExport, className = '', }) => {
628
+ const { t } = useNiceTranslation();
627
629
  const { config, setConfig, icons, isExporting, progress, exportAll, downloadAll, downloadSingle, } = useDesktopIconExporter(icon, initialConfig);
628
630
  const handleExport = async () => {
629
631
  await exportAll();
630
632
  onExport === null || onExport === void 0 ? void 0 : onExport(icons);
631
633
  };
632
634
  const IconComponent = icon;
633
- return (jsxs("div", { className: `nice-desktop-icon-exporter ${className}`, children: [jsxs("div", { className: "nice-desktop-icon-exporter__preview", children: [jsx("h3", { children: "Preview" }), jsx("div", { className: "nice-desktop-icon-exporter__preview-grid", children: [16, 32, 48, 64, 128, 256].map((size) => (jsxs("div", { className: "nice-desktop-icon-exporter__preview-item", children: [jsx("div", { style: {
635
+ return (jsxs("div", { className: `nice-desktop-icon-exporter ${className}`, children: [jsxs("div", { className: "nice-desktop-icon-exporter__preview", children: [jsx("h3", { children: t('desktopIconExporter.preview', 'Preview') }), jsx("div", { className: "nice-desktop-icon-exporter__preview-grid", children: [16, 32, 48, 64, 128, 256].map((size) => (jsxs("div", { className: "nice-desktop-icon-exporter__preview-item", children: [jsx("div", { className: "nice-desktop-icon-exporter__preview-box", style: {
634
636
  width: Math.min(size, 128),
635
637
  height: Math.min(size, 128),
636
638
  backgroundColor: config.backgroundColor || '#f0f0f0',
637
- display: 'flex',
638
- alignItems: 'center',
639
- justifyContent: 'center',
640
- borderRadius: 4,
641
- }, children: jsx(IconComponent, { size: Math.min(size, 128) * (1 - config.padding * 2), fill: config.fillColor }) }), jsxs("span", { children: [size, "\u00D7", size] })] }, size))) })] }), jsxs("div", { className: "nice-desktop-icon-exporter__config", children: [jsx("h3", { children: "Configuration" }), jsxs("label", { children: ["Icon Name:", jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })) })] }), jsxs("label", { children: ["Fill Color:", jsx("input", { type: "color", value: config.fillColor, onChange: (e) => setConfig((c) => ({ ...c, fillColor: e.target.value })) })] }), jsxs("label", { children: ["Background:", jsx("input", { type: "color", value: config.backgroundColor || '#ffffff', onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })) }), jsx("button", { onClick: () => setConfig((c) => ({ ...c, backgroundColor: undefined })), children: "Transparent" })] }), jsxs("label", { children: ["Padding: ", Math.round(config.padding * 100), "%", jsx("input", { type: "range", min: "0", max: "0.3", step: "0.01", value: config.padding, onChange: (e) => setConfig((c) => ({ ...c, padding: parseFloat(e.target.value) })) })] }), jsxs("div", { className: "nice-desktop-icon-exporter__platforms", children: [jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeWindows, onChange: (e) => setConfig((c) => ({ ...c, includeWindows: e.target.checked })) }), "Windows (.ico)"] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeMacOS, onChange: (e) => setConfig((c) => ({ ...c, includeMacOS: e.target.checked })) }), "macOS (.iconset)"] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeLinux, onChange: (e) => setConfig((c) => ({ ...c, includeLinux: e.target.checked })) }), "Linux (hicolor)"] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeRetina, onChange: (e) => setConfig((c) => ({ ...c, includeRetina: e.target.checked })) }), "HiDPI/Retina (@2x, @3x)"] })] }), jsxs("div", { className: "nice-desktop-icon-exporter__sizes", children: [jsx("h4", { children: "Sizes:" }), DESKTOP_ICON_SIZES.map(({ size, label }) => (jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.sizes.includes(size), onChange: (e) => {
639
+ }, children: jsx(IconComponent, { size: Math.min(size, 128) * (1 - config.padding * 2), fill: config.fillColor }) }), jsxs("span", { children: [size, "\u00D7", size] })] }, size))) })] }), jsxs("div", { className: "nice-desktop-icon-exporter__config", children: [jsx("h3", { children: t('desktopIconExporter.configuration', 'Configuration') }), jsxs("label", { children: [t('desktopIconExporter.iconName', 'Icon Name:'), jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })) })] }), jsxs("label", { children: [t('desktopIconExporter.fillColor', 'Fill Color:'), jsx("input", { type: "color", value: config.fillColor, onChange: (e) => setConfig((c) => ({ ...c, fillColor: e.target.value })) })] }), jsxs("label", { children: [t('desktopIconExporter.background', 'Background:'), jsx("input", { type: "color", value: config.backgroundColor || '#ffffff', onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })) }), jsx("button", { onClick: () => setConfig((c) => ({ ...c, backgroundColor: undefined })), children: t('desktopIconExporter.transparent', 'Transparent') })] }), jsxs("label", { children: [t('desktopIconExporter.padding', 'Padding: {padding}%').replace('{padding}', String(Math.round(config.padding * 100))), jsx("input", { type: "range", min: "0", max: "0.3", step: "0.01", value: config.padding, onChange: (e) => setConfig((c) => ({ ...c, padding: parseFloat(e.target.value) })) })] }), jsxs("div", { className: "nice-desktop-icon-exporter__platforms", children: [jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeWindows, onChange: (e) => setConfig((c) => ({ ...c, includeWindows: e.target.checked })) }), t('desktopIconExporter.windowsIco', 'Windows (.ico)')] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeMacOS, onChange: (e) => setConfig((c) => ({ ...c, includeMacOS: e.target.checked })) }), t('desktopIconExporter.macosIconset', 'macOS (.iconset)')] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeLinux, onChange: (e) => setConfig((c) => ({ ...c, includeLinux: e.target.checked })) }), t('desktopIconExporter.linuxHicolor', 'Linux (hicolor)')] }), jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.includeRetina, onChange: (e) => setConfig((c) => ({ ...c, includeRetina: e.target.checked })) }), t('desktopIconExporter.hidpiRetina2x3x', 'HiDPI/Retina (@2x, @3x)')] })] }), jsxs("div", { className: "nice-desktop-icon-exporter__sizes", children: [jsx("h4", { children: t('desktopIconExporter.sizes', 'Sizes:') }), DESKTOP_ICON_SIZES.map(({ size, label }) => (jsxs("label", { children: [jsx("input", { type: "checkbox", checked: config.sizes.includes(size), onChange: (e) => {
642
640
  setConfig((c) => ({
643
641
  ...c,
644
642
  sizes: e.target.checked
645
643
  ? [...c.sizes, size].sort((a, b) => a - b)
646
644
  : c.sizes.filter((s) => s !== size),
647
645
  }));
648
- } }), label] }, size)))] })] }), jsxs("div", { className: "nice-desktop-icon-exporter__actions", children: [jsx("button", { onClick: handleExport, disabled: isExporting, children: isExporting ? `Exporting... ${Math.round(progress)}%` : 'Generate Icons' }), jsx("button", { onClick: downloadAll, disabled: isExporting || icons.length === 0, children: "Download All (ZIP)" })] }), icons.length > 0 && (jsxs("div", { className: "nice-desktop-icon-exporter__results", children: [jsxs("h3", { children: ["Generated Icons (", icons.length, ")"] }), jsx("div", { className: "nice-desktop-icon-exporter__results-grid", children: icons.map((exportedIcon) => (jsxs("div", { className: "nice-desktop-icon-exporter__result-item", children: [jsx("img", { src: exportedIcon.dataUrl, alt: exportedIcon.filename, style: { maxWidth: 64, maxHeight: 64 } }), jsx("span", { children: exportedIcon.filename }), jsx("button", { onClick: () => downloadSingle(exportedIcon), children: "Download" })] }, exportedIcon.filename))) })] }))] }));
646
+ } }), label] }, size)))] })] }), jsxs("div", { className: "nice-desktop-icon-exporter__actions", children: [jsx("button", { onClick: handleExport, disabled: isExporting, children: isExporting
647
+ ? t('desktopIconExporter.exporting', 'Exporting... {progress}%').replace('{progress}', String(Math.round(progress)))
648
+ : t('desktopIconExporter.generateIcons', 'Generate Icons') }), jsx("button", { onClick: downloadAll, disabled: isExporting || icons.length === 0, children: t('desktopIconExporter.downloadAllZip', 'Download All (ZIP)') })] }), icons.length > 0 && (jsxs("div", { className: "nice-desktop-icon-exporter__results", children: [jsx("h3", { children: t('desktopIconExporter.generatedIcons', 'Generated Icons ({icons})').replace('{icons}', String(icons.length)) }), jsx("div", { className: "nice-desktop-icon-exporter__results-grid", children: icons.map((exportedIcon) => (jsxs("div", { className: "nice-desktop-icon-exporter__result-item", children: [jsx("img", { src: exportedIcon.dataUrl, alt: exportedIcon.filename }), jsx("span", { children: exportedIcon.filename }), jsx("button", { onClick: () => downloadSingle(exportedIcon), children: t('desktopIconExporter.download', 'Download') })] }, exportedIcon.filename))) })] }))] }));
649
649
  };
650
650
 
651
651
  export { DESKTOP_ICON_SIZES, LINUX_HICOLOR_DIRS, NiceDesktopIconExporter, RETINA_VARIANTS, useDesktopIconExporter };
@@ -1,5 +1,7 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
2
3
  import { useState, useCallback } from 'react';
4
+ import { NtdDownload } from './icons/actions.js';
3
5
 
4
6
  /* ══════════════════════════════════════════════════════════════════════════════
5
7
  Constants
@@ -222,6 +224,7 @@ function useFaviconGenerator(icon, fill = '#1e1e1e', initialConfig) {
222
224
  * Favicon generator component for creating all favicon variants.
223
225
  */
224
226
  function NiceFaviconGenerator({ icon, fill = '#1e1e1e', manifestConfig, onGenerate, className = '', }) {
227
+ const { t } = useNiceTranslation();
225
228
  const { config, setConfig, assets, isGenerating, generate, downloadAll, downloadSingle, getManifestJson, getHtmlTags, } = useFaviconGenerator(icon, fill, manifestConfig);
226
229
  const [activeTab, setActiveTab] = useState('preview');
227
230
  const handleGenerate = async () => {
@@ -230,10 +233,12 @@ function NiceFaviconGenerator({ icon, fill = '#1e1e1e', manifestConfig, onGenera
230
233
  onGenerate(assets, getManifestJson());
231
234
  }
232
235
  };
233
- return (jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [jsxs("div", { style: styles.section, children: [jsx("h3", { style: styles.sectionTitle, children: "Manifest Configuration" }), jsxs("div", { style: styles.formGrid, children: [jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "App Name" }), jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "Short Name" }), jsx("input", { type: "text", value: config.shortName, onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "Theme Color" }), jsx("input", { type: "color", value: config.themeColor, onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "Background Color" }), jsx("input", { type: "color", value: config.backgroundColor, onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "Display Mode" }), jsxs("select", { value: config.display, onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })), style: styles.input, children: [jsx("option", { value: "standalone", children: "Standalone" }), jsx("option", { value: "fullscreen", children: "Fullscreen" }), jsx("option", { value: "minimal-ui", children: "Minimal UI" }), jsx("option", { value: "browser", children: "Browser" })] })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: "Start URL" }), jsx("input", { type: "text", value: config.startUrl, onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })), style: styles.input })] })] })] }), jsxs("div", { style: styles.actions, children: [jsx("button", { onClick: handleGenerate, disabled: isGenerating, style: {
236
+ return (jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [jsxs("div", { style: styles.section, children: [jsx("h3", { style: styles.sectionTitle, children: t('faviconGenerator.manifestConfiguration', 'Manifest Configuration') }), jsxs("div", { style: styles.formGrid, children: [jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.appName', 'App Name') }), jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.shortName', 'Short Name') }), jsx("input", { type: "text", value: config.shortName, onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.themeColor', 'Theme Color') }), jsx("input", { type: "color", value: config.themeColor, onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.backgroundColor', 'Background Color') }), jsx("input", { type: "color", value: config.backgroundColor, onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.displayMode', 'Display Mode') }), jsxs("select", { value: config.display, onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })), style: styles.input, children: [jsx("option", { value: "standalone", children: t('faviconGenerator.standalone', 'Standalone') }), jsx("option", { value: "fullscreen", children: t('faviconGenerator.fullscreen', 'Fullscreen') }), jsx("option", { value: "minimal-ui", children: t('faviconGenerator.minimalUi', 'Minimal UI') }), jsx("option", { value: "browser", children: t('faviconGenerator.browser', 'Browser') })] })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.startUrl', 'Start URL') }), jsx("input", { type: "text", value: config.startUrl, onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })), style: styles.input })] })] })] }), jsxs("div", { style: styles.actions, children: [jsx("button", { onClick: handleGenerate, disabled: isGenerating, style: {
234
237
  ...styles.button,
235
238
  ...(isGenerating ? styles.buttonDisabled : styles.buttonPrimary),
236
- }, children: isGenerating ? 'Generating...' : 'Generate Favicons' }), assets.length > 0 && (jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: "Download All" }))] }), assets.length > 0 && (jsxs("div", { style: styles.section, children: [jsxs("div", { style: styles.tabs, children: [jsx("button", { style: { ...styles.tab, ...(activeTab === 'preview' ? styles.tabActive : {}) }, onClick: () => setActiveTab('preview'), children: "Preview" }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'manifest' ? styles.tabActive : {}) }, onClick: () => setActiveTab('manifest'), children: "manifest.json" }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'html' ? styles.tabActive : {}) }, onClick: () => setActiveTab('html'), children: "HTML Tags" })] }), activeTab === 'preview' && (jsx("div", { style: styles.assetGrid, children: assets.map((asset) => (jsxs("div", { style: styles.assetCard, children: [jsx("div", { style: styles.assetPreview, children: jsx("img", { src: asset.dataUrl, alt: asset.filename, style: { maxWidth: '64px', maxHeight: '64px' } }) }), jsxs("div", { style: styles.assetInfo, children: [jsx("span", { style: styles.assetName, children: asset.filename }), jsxs("span", { style: styles.assetSize, children: [asset.size, "x", asset.size] }), jsx("span", { style: styles.assetPurpose, children: asset.purpose })] }), jsx("button", { onClick: () => downloadSingle(asset), style: styles.downloadBtn, children: "\u2193" })] }, asset.filename))) })), activeTab === 'manifest' && jsx("pre", { style: styles.codeBlock, children: getManifestJson() }), activeTab === 'html' && jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })] })), jsxs("div", { style: styles.reference, children: [jsx("h4", { style: styles.referenceTitle, children: "Favicon Sizes Reference" }), jsxs("table", { style: styles.table, children: [jsx("thead", { children: jsxs("tr", { children: [jsx("th", { style: styles.th, children: "File" }), jsx("th", { style: styles.th, children: "Size" }), jsx("th", { style: styles.th, children: "Purpose" })] }) }), jsx("tbody", { children: FAVICON_SIZES.map((f) => (jsxs("tr", { children: [jsxs("td", { style: styles.td, children: [f.name, ".", f.format] }), jsxs("td", { style: styles.td, children: [f.size, "x", f.size] }), jsx("td", { style: styles.td, children: f.purpose })] }, f.name))) })] })] })] }));
239
+ }, children: isGenerating
240
+ ? t('faviconGenerator.generating', 'Generating...')
241
+ : t('faviconGenerator.generateFavicons', 'Generate Favicons') }), assets.length > 0 && (jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: t('faviconGenerator.downloadAll', 'Download All') }))] }), assets.length > 0 && (jsxs("div", { style: styles.section, children: [jsxs("div", { style: styles.tabs, children: [jsx("button", { style: { ...styles.tab, ...(activeTab === 'preview' ? styles.tabActive : {}) }, onClick: () => setActiveTab('preview'), children: t('faviconGenerator.preview', 'Preview') }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'manifest' ? styles.tabActive : {}) }, onClick: () => setActiveTab('manifest'), children: "manifest.json" }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'html' ? styles.tabActive : {}) }, onClick: () => setActiveTab('html'), children: t('faviconGenerator.htmlTags', 'HTML Tags') })] }), activeTab === 'preview' && (jsx("div", { style: styles.assetGrid, children: assets.map((asset) => (jsxs("div", { style: styles.assetCard, children: [jsx("div", { style: styles.assetPreview, children: jsx("img", { src: asset.dataUrl, alt: asset.filename, style: { maxWidth: '64px', maxHeight: '64px' } }) }), jsxs("div", { style: styles.assetInfo, children: [jsx("span", { style: styles.assetName, children: asset.filename }), jsxs("span", { style: styles.assetSize, children: [asset.size, "x", asset.size] }), jsx("span", { style: styles.assetPurpose, children: asset.purpose })] }), jsx("button", { onClick: () => downloadSingle(asset), style: styles.downloadBtn, "aria-label": t('faviconGenerator.download', 'Download {filename}').replace('{filename}', String(asset.filename)), children: jsx(NtdDownload, { size: 14, variant: "outline" }) })] }, asset.filename))) })), activeTab === 'manifest' && jsx("pre", { style: styles.codeBlock, children: getManifestJson() }), activeTab === 'html' && jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })] })), jsxs("div", { style: styles.reference, children: [jsx("h4", { style: styles.referenceTitle, children: t('faviconGenerator.faviconSizesReference', 'Favicon Sizes Reference') }), jsxs("table", { style: styles.table, children: [jsx("thead", { children: jsxs("tr", { children: [jsx("th", { style: styles.th, children: t('faviconGenerator.file', 'File') }), jsx("th", { style: styles.th, children: t('faviconGenerator.size', 'Size') }), jsx("th", { style: styles.th, children: t('faviconGenerator.purpose', 'Purpose') })] }) }), jsx("tbody", { children: FAVICON_SIZES.map((f) => (jsxs("tr", { children: [jsxs("td", { style: styles.td, children: [f.name, ".", f.format] }), jsxs("td", { style: styles.td, children: [f.size, "x", f.size] }), jsx("td", { style: styles.td, children: f.purpose })] }, f.name))) })] })] })] }));
237
242
  }
238
243
  /* ══════════════════════════════════════════════════════════════════════════════
239
244
  Styles
@@ -1,17 +1,19 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { forwardRef, useState, useRef, useCallback, useImperativeHandle, useMemo, useEffect } from 'react';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
3
+ import { forwardRef, useState, useRef, useMemo, useCallback, useImperativeHandle, useEffect } from 'react';
4
+ import { NtdSearch, NtdCheck } from './icons/actions.js';
5
+ import { NtdGrid } from './icons/files.js';
6
+ import { NtdInbox } from './icons/media.js';
7
+ import { NtdChevronDown } from './icons/navigation.js';
8
+ import { NtdStar, NtdClock } from './icons/ui.js';
3
9
 
4
10
  const MAX_HISTORY_ITEMS = 20;
5
- /* ─── Chevron SVG ─── */
6
- const Chevron = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "6 9 12 15 18 9" }) }));
7
- /* ─── Search SVG ─── */
8
- const SearchIcon = () => (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("circle", { cx: "11", cy: "11", r: "8" }), jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })] }));
9
- /* ─── Star SVG (favorites) ─── */
10
- const StarIcon = ({ filled }) => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: filled ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) }));
11
- /* ─── Clock SVG (history) ─── */
12
- const ClockIcon = () => (jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("polyline", { points: "12 6 12 12 16 14" })] }));
13
- /* ─── Check SVG (multi-select) ─── */
14
- const CheckIcon = () => (jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
11
+ /* ─── Small icons: the package's own (until 1.2.0 these were pasted SVGs) ─── */
12
+ const Chevron = () => jsx(NtdChevronDown, { size: 12, variant: "outline" });
13
+ const SearchIcon = () => jsx(NtdSearch, { size: 14, variant: "outline" });
14
+ const StarIcon = ({ filled }) => (jsx(NtdStar, { size: 12, variant: filled ? 'solid' : 'outline' }));
15
+ const ClockIcon = () => jsx(NtdClock, { size: 12, variant: "outline" });
16
+ const CheckIcon = () => jsx(NtdCheck, { size: 10, variant: "outline" });
15
17
  /* ─── localStorage helpers ─── */
16
18
  function loadFromStorage(key, fallback) {
17
19
  if (typeof window === 'undefined') {
@@ -68,8 +70,9 @@ function saveToStorage(key, value) {
68
70
  * }
69
71
  * ```
70
72
  */
71
- const NiceIconPicker = forwardRef(function NiceIconPicker({ icons, value = null, values = [], onChange, onChangeMulti, multiSelect = false, maxSelections, placeholder = 'Select icon…', 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) {
73
+ const NiceIconPicker = /* @__PURE__ */ 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) {
72
74
  var _a;
75
+ const { t } = useNiceTranslation();
73
76
  const [isOpen, setIsOpen] = useState(false);
74
77
  const [search, setSearch] = useState('');
75
78
  const [activeCategory, setActiveCategory] = useState(null);
@@ -83,13 +86,7 @@ const NiceIconPicker = forwardRef(function NiceIconPicker({ icons, value = null,
83
86
  const [history, setHistory] = useState(() => loadFromStorage(historyKey, []));
84
87
  // Multi-select state (internal when uncontrolled)
85
88
  const [internalValues, setInternalValues] = useState([]);
86
- const selectedValues = multiSelect
87
- ? values.length > 0
88
- ? values
89
- : internalValues
90
- : value
91
- ? [value]
92
- : [];
89
+ const selectedValues = useMemo(() => (multiSelect ? (values.length > 0 ? values : internalValues) : value ? [value] : []), [multiSelect, values, internalValues, value]);
93
90
  const rootRef = useRef(null);
94
91
  const searchInputRef = useRef(null);
95
92
  /* ─── Favorites helpers ─── */
@@ -391,19 +388,27 @@ const NiceIconPicker = forwardRef(function NiceIconPicker({ icons, value = null,
391
388
  if (selectedEntries.length === 1) {
392
389
  return readableName(selectedEntries[0].name);
393
390
  }
394
- return `${selectedEntries.length} icons selected`;
391
+ return t('iconPicker.iconsSelected', '{count} icons selected').replace('{count}', String(selectedEntries.length));
395
392
  }
396
- return selectedEntry ? readableName(selectedEntry.name) : placeholder;
397
- }, [multiSelect, selectedEntries, selectedEntry, placeholder]);
398
- return (jsxs("div", { ref: rootRef, className: `ntd-picker${isOpen ? ' open' : ''}${disabled ? ' disabled' : ''}${multiSelect ? ' multi' : ''}${className ? ` ${className}` : ''}`, children: [jsxs("button", { type: "button", className: "ntd-picker-trigger", onClick: handleToggle, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [jsx("span", { className: "ntd-picker-trigger-icon", children: selectedEntry ? (jsx(selectedEntry.Component, { size: triggerIconSize, variant: variant })) : multiSelect && selectedEntries.length > 1 ? (jsx("span", { className: "ntd-picker-multi-badge", children: selectedEntries.length })) : (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" })] })) }), jsx("span", { className: `ntd-picker-trigger-label${!selectedEntry && selectedEntries.length === 0 ? ' ntd-picker-trigger-placeholder' : ''}`, children: triggerLabel }), jsx("span", { className: "ntd-picker-trigger-chevron", children: jsx(Chevron, {}) })] }), isOpen && (jsxs("div", { className: "ntd-picker-dropdown", role: "listbox", children: [jsxs("div", { className: "ntd-picker-search", children: [jsx("span", { className: "ntd-picker-search-icon", children: jsx(SearchIcon, {}) }), jsx("input", { ref: searchInputRef, type: "text", placeholder: "Search icons\u2026", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search icons" })] }), (allCategories.length > 1 || showFavorites || showHistory) && (jsxs("div", { className: "ntd-picker-tabs", role: "tablist", children: [jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === null ? ' active' : ''}`, onClick: () => setActiveCategory(null), role: "tab", "aria-selected": activeCategory === null, children: "All" }), showFavorites && (jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__favorites__' ? ' active' : ''}`, onClick: () => setActiveCategory('__favorites__'), role: "tab", "aria-selected": activeCategory === '__favorites__', title: "Favorites", children: [jsx(StarIcon, { filled: true }), " Favorites", favorites.length > 0 && (jsx("span", { className: "ntd-picker-tab-count", children: favorites.length }))] })), showHistory && history.length > 0 && (jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__history__' ? ' active' : ''}`, onClick: () => setActiveCategory('__history__'), role: "tab", "aria-selected": activeCategory === '__history__', title: "Recently used", children: [jsx(ClockIcon, {}), " Recent"] })), allCategories.map((cat) => (jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === cat ? ' active' : ''}`, onClick: () => setActiveCategory(cat), role: "tab", "aria-selected": activeCategory === cat, children: cat }, cat)))] })), jsx("div", { className: "ntd-picker-grid-wrap", ref: gridWrapRef, children: filtered.length === 0 ? (jsxs("div", { className: "ntd-picker-empty", children: [jsx("div", { className: "ntd-picker-empty-icon", children: "\u2205" }), activeCategory === '__favorites__'
399
- ? 'No favorites yet. Click the star icon to add.'
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 (jsxs("div", { ref: rootRef, className: `ntd-picker${isOpen ? ' ntd-picker--open' : ''}${disabled ? ' ntd-picker--disabled' : ''}${multiSelect ? ' ntd-picker--multi' : ''}${className ? ` ${className}` : ''}`, children: [jsxs("button", { type: "button", className: "ntd-picker-trigger", onClick: handleToggle, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [jsx("span", { className: "ntd-picker-trigger-icon", children: selectedEntry ? (jsx(selectedEntry.Component, { size: triggerIconSize, variant: variant })) : multiSelect && selectedEntries.length > 1 ? (jsx("span", { className: "ntd-picker-multi-badge", children: selectedEntries.length })) : (jsx(NtdGrid, { size: 16, variant: "outline" })) }), jsx("span", { className: `ntd-picker-trigger-label${!selectedEntry && selectedEntries.length === 0 ? ' ntd-picker-trigger-placeholder' : ''}`, children: triggerLabel }), jsx("span", { className: "ntd-picker-trigger-chevron", children: jsx(Chevron, {}) })] }), isOpen && (jsxs("div", { className: "ntd-picker-dropdown", role: "listbox", children: [jsxs("div", { className: "ntd-picker-search", children: [jsx("span", { className: "ntd-picker-search-icon", children: jsx(SearchIcon, {}) }), 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) && (jsxs("div", { className: "ntd-picker-tabs", role: "tablist", children: [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 && (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: [jsx(StarIcon, { filled: true }), " ", t('iconPicker.favorites', 'Favorites'), favorites.length > 0 && (jsx("span", { className: "ntd-picker-tab-count", children: favorites.length }))] })), showHistory && history.length > 0 && (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: [jsx(ClockIcon, {}), " ", t('iconPicker.recent', 'Recent')] })), allCategories.map((cat) => (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)))] })), jsx("div", { className: "ntd-picker-grid-wrap", ref: gridWrapRef, children: filtered.length === 0 ? (jsxs("div", { className: "ntd-picker-empty", children: [jsx("div", { className: "ntd-picker-empty-icon", children: jsx(NtdInbox, { size: 28, variant: "outline" }) }), activeCategory === '__favorites__'
398
+ ? t('iconPicker.noFavoritesYetClickThe', 'No favorites yet. Click the star icon to add.')
400
399
  : activeCategory === '__history__'
401
- ? 'No recent icons.'
402
- : 'No icons found'] })) : (jsxs(Fragment, { children: [virtualized && visibleRange.start > 0 && (jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxs("div", { children: [!activeCategory && !(activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.startsWith('__')) && (jsx("div", { className: "ntd-picker-category-label", children: category })), jsx("div", { className: "ntd-picker-grid", children: entries.map((entry) => {
400
+ ? t('iconPicker.noRecentIcons', 'No recent icons.')
401
+ : t('iconPicker.noIconsFound', 'No icons found')] })) : (jsxs(Fragment, { children: [virtualized && visibleRange.start > 0 && (jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxs("div", { children: [!activeCategory && !(activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.startsWith('__')) && (jsx("div", { className: "ntd-picker-category-label", children: category })), jsx("div", { className: "ntd-picker-grid", children: entries.map((entry) => {
403
402
  const isSelected = selectedValues.includes(entry.name);
404
403
  const isFavorite = favorites.includes(entry.name);
405
- return (jsxs("button", { type: "button", className: `ntd-picker-cell${isSelected ? ' selected' : ''}${multiSelect ? ' multi-select' : ''}${enableDragAndDrop ? ' 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: [jsx(entry.Component, { size: gridIconSize, variant: variant }), multiSelect && isSelected && (jsx("span", { className: "ntd-picker-cell-check", children: jsx(CheckIcon, {}) })), showFavorites && (jsx("button", { type: "button", className: `ntd-picker-cell-fav${isFavorite ? ' active' : ''}`, onClick: (e) => handleFavoriteClick(e, entry.name), title: isFavorite ? 'Remove from favorites' : 'Add to favorites', children: jsx(StarIcon, { filled: isFavorite }) }))] }, entry.name));
406
- }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsx("div", { style: { height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48 } }))] })) }), jsxs("div", { className: "ntd-picker-footer", children: [jsxs("span", { className: "ntd-picker-count", children: [filtered.length, " icon", filtered.length !== 1 ? 's' : '', multiSelect && selectedValues.length > 0 && (jsxs(Fragment, { children: [" \u2022 ", selectedValues.length, " selected"] })), maxSelections && multiSelect && jsxs(Fragment, { children: [" (max ", maxSelections, ")"] })] }), clearable && selectedValues.length > 0 && (jsxs("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: ["Clear", multiSelect ? ' all' : ' selection'] })), multiSelect && (jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: "Done" }))] })] }))] }));
404
+ return (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: [jsx(entry.Component, { size: gridIconSize, variant: variant }), multiSelect && isSelected && (jsx("span", { className: "ntd-picker-cell-check", children: jsx(CheckIcon, {}) })), showFavorites && (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: jsx(StarIcon, { filled: isFavorite }) }))] }, entry.name));
407
+ }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsx("div", { style: { height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48 } }))] })) }), jsxs("div", { className: "ntd-picker-footer", children: [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 && (jsxs(Fragment, { children: [' ', t('iconPicker.selected', '• {selectedValues} selected').replace('{selectedValues}', String(selectedValues.length))] })), maxSelections && multiSelect && (jsxs(Fragment, { children: [' ', t('iconPicker.max', '(max {maxSelections})').replace('{maxSelections}', String(maxSelections))] }))] }), clearable && selectedValues.length > 0 && (jsx("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: multiSelect
410
+ ? t('iconPicker.clearAll', 'Clear all')
411
+ : t('iconPicker.clearSelection', 'Clear selection') })), multiSelect && (jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: t('iconPicker.done', 'Done') }))] })] }))] }));
407
412
  });
408
413
 
409
414
  export { NiceIconPicker };
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
2
3
  import { useState, useMemo } from 'react';
3
4
 
4
5
  /* ══════════════════════════════════════════════════════════════════════════════
@@ -64,6 +65,7 @@ const animationCSS = `
64
65
  * Icon preview component with multiple modes and sizes.
65
66
  */
66
67
  function NiceIconPreview({ icon: Icon, iconName = 'Icon', mode = 'both', layout = 'grid', sizes = DEFAULT_SIZES, showAnimation = true, animations = DEFAULT_ANIMATIONS, fill, className = '', }) {
68
+ const { t } = useNiceTranslation();
67
69
  const [selectedAnimation, setSelectedAnimation] = useState(null);
68
70
  // Inject animation styles
69
71
  const styleSheet = useMemo(() => jsx("style", { dangerouslySetInnerHTML: { __html: animationCSS } }), []);
@@ -75,7 +77,7 @@ function NiceIconPreview({ icon: Icon, iconName = 'Icon', mode = 'both', layout
75
77
  background: BACKGROUND_COLORS[bgMode],
76
78
  }, children: jsx(Icon, { size: size, fill: iconFill, className: selectedAnimation || undefined }) }));
77
79
  };
78
- return (jsxs("div", { className: `nice-icon-preview ${className}`, style: styles.container, children: [styleSheet, jsxs("div", { style: styles.header, children: [jsx("h3", { style: styles.title, children: iconName }), showAnimation && (jsxs("div", { style: styles.animationControls, children: [jsx("span", { style: styles.animationLabel, children: "Animation:" }), jsxs("select", { value: selectedAnimation || '', onChange: (e) => setSelectedAnimation(e.target.value || null), style: styles.select, children: [jsx("option", { value: "", children: "None" }), animations.map((a) => (jsx("option", { value: a.className, children: a.name }, a.className)))] })] }))] }), layout === 'grid' && (jsxs("div", { style: styles.gridContainer, children: [(mode === 'light' || mode === 'both') && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: "Light Mode" }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'light', fill), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), (mode === 'dark' || mode === 'both') && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: "Dark Mode" }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'dark', fill), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), mode === 'gradient' && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: "Gradient Background" }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'gradient', '#ffffff'), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] }))] })), layout === 'list' && (jsx("div", { style: styles.listContainer, children: sizes.map((s) => (jsxs("div", { style: styles.listRow, children: [jsx("span", { style: styles.listLabel, children: s.label }), renderIcon(s.size, 'light', fill), renderIcon(s.size, 'dark', fill)] }, s.size))) })), layout === 'comparison' && (jsxs("div", { style: styles.comparisonContainer, children: [jsxs("div", { style: styles.comparisonSide, children: [jsx("h4", { style: styles.sectionTitle, children: "Light" }), jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.light }, children: jsx(Icon, { size: 96, fill: fill || '#1e1e1e', className: selectedAnimation || undefined }) })] }), jsxs("div", { style: styles.comparisonSide, children: [jsx("h4", { style: styles.sectionTitle, children: "Dark" }), jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.dark }, children: jsx(Icon, { size: 96, fill: fill || '#ffffff', className: selectedAnimation || undefined }) })] })] }))] }));
80
+ return (jsxs("div", { className: `nice-icon-preview ${className}`, style: styles.container, children: [styleSheet, jsxs("div", { style: styles.header, children: [jsx("h3", { style: styles.title, children: iconName }), showAnimation && (jsxs("div", { style: styles.animationControls, children: [jsx("span", { style: styles.animationLabel, children: t('iconPreview.animation', 'Animation:') }), jsxs("select", { value: selectedAnimation || '', onChange: (e) => setSelectedAnimation(e.target.value || null), style: styles.select, children: [jsx("option", { value: "", children: t('iconPreview.none', 'None') }), animations.map((a) => (jsx("option", { value: a.className, children: a.name }, a.className)))] })] }))] }), layout === 'grid' && (jsxs("div", { style: styles.gridContainer, children: [(mode === 'light' || mode === 'both') && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.lightMode', 'Light Mode') }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'light', fill), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), (mode === 'dark' || mode === 'both') && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.darkMode', 'Dark Mode') }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'dark', fill), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), mode === 'gradient' && (jsxs("div", { style: styles.section, children: [jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.gradientBackground', 'Gradient Background') }), jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'gradient', '#ffffff'), jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] }))] })), layout === 'list' && (jsx("div", { style: styles.listContainer, children: sizes.map((s) => (jsxs("div", { style: styles.listRow, children: [jsx("span", { style: styles.listLabel, children: s.label }), renderIcon(s.size, 'light', fill), renderIcon(s.size, 'dark', fill)] }, s.size))) })), layout === 'comparison' && (jsxs("div", { style: styles.comparisonContainer, children: [jsxs("div", { style: styles.comparisonSide, children: [jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.light', 'Light') }), jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.light }, children: jsx(Icon, { size: 96, fill: fill || '#1e1e1e', className: selectedAnimation || undefined }) })] }), jsxs("div", { style: styles.comparisonSide, children: [jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.dark', 'Dark') }), jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.dark }, children: jsx(Icon, { size: 96, fill: fill || '#ffffff', className: selectedAnimation || undefined }) })] })] }))] }));
79
81
  }
80
82
  /* ══════════════════════════════════════════════════════════════════════════════
81
83
  Styles
@@ -1,34 +1,7 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
2
3
  import { useState, useMemo, useCallback } from 'react';
3
- import './icons/navigation.js';
4
4
  import { NtdCheck } from './icons/actions.js';
5
- import './icons/ui.js';
6
- import './icons/sustainability.js';
7
- import './icons/accessibility.js';
8
- import './icons/legal.js';
9
- import './icons/media.js';
10
- import './icons/files.js';
11
- import './icons/fun.js';
12
- import './icons/weather.js';
13
- import './icons/shapes.js';
14
- import './icons/business.js';
15
- import './icons/social.js';
16
- import './icons/devtech.js';
17
- import './icons/ecommerce.js';
18
- import './icons/fintech.js';
19
- import './icons/saas.js';
20
- import './icons/smarthome.js';
21
- import './icons/health.js';
22
- import './icons/brand.js';
23
- import './icons/gaming.js';
24
- import './icons/ai.js';
25
- import './icons/education.js';
26
- import './icons/science.js';
27
- import './icons/realestate.js';
28
- import './icons/food.js';
29
- import './icons/travel.js';
30
- import './icons/sports.js';
31
- import './icons/omniverk.js';
32
5
 
33
6
  /* ══════════════════════════════════════════════════════════════════════════════
34
7
  Constants
@@ -36,6 +9,7 @@ import './icons/omniverk.js';
36
9
  const DEFAULT_CONFIG = {
37
10
  name: 'MyIcons',
38
11
  packageName: '@myproject/icons',
12
+ // audit-allow: i18n — the generated package.json's default description, not UI copy
39
13
  description: 'Custom icon set',
40
14
  version: '1.0.0',
41
15
  author: '',
@@ -313,6 +287,7 @@ function useIconSetCreator(options) {
313
287
  * Icon Set Creator component for building custom icon packages.
314
288
  */
315
289
  function NiceIconSetCreator({ icons, initialSelection, defaultConfig, onSelectionChange: _onSelectionChange, onExport, className = '', }) {
290
+ const { t } = useNiceTranslation();
316
291
  const creator = useIconSetCreator({ icons, initialSelection, defaultConfig });
317
292
  const [searchQuery, setSearchQuery] = useState('');
318
293
  const [categoryFilter, setCategoryFilter] = useState('all');
@@ -366,11 +341,18 @@ function NiceIconSetCreator({ icons, initialSelection, defaultConfig, onSelectio
366
341
  URL.revokeObjectURL(url);
367
342
  });
368
343
  }, [creator]);
369
- return (jsxs("div", { className: `nice-icon-set-creator ${className}`, style: styles.container, children: [jsxs("div", { style: styles.header, children: [jsx("h2", { style: styles.title, children: "Icon Set Creator" }), jsxs("div", { style: styles.stats, children: [creator.selectedCount, " / ", creator.items.length, " icons selected"] })] }), jsxs("div", { style: styles.content, children: [jsxs("div", { style: styles.configPanel, children: [jsx("h3", { style: styles.sectionTitle, children: "Configuration" }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "Set Name" }), jsx("input", { type: "text", value: creator.config.name, onChange: (e) => creator.updateConfig({ name: e.target.value }), style: styles.input, placeholder: "MyIcons" })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "Package Name" }), jsx("input", { type: "text", value: creator.config.packageName, onChange: (e) => creator.updateConfig({ packageName: e.target.value }), style: styles.input, placeholder: "@myproject/icons" })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "Description" }), jsx("input", { type: "text", value: creator.config.description, onChange: (e) => creator.updateConfig({ description: e.target.value }), style: styles.input })] }), jsxs("div", { style: styles.fieldRow, children: [jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "Version" }), jsx("input", { type: "text", value: creator.config.version, onChange: (e) => creator.updateConfig({ version: e.target.value }), style: styles.input })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "License" }), jsx("input", { type: "text", value: creator.config.license, onChange: (e) => creator.updateConfig({ license: e.target.value }), style: styles.input })] })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: "Export Format" }), jsxs("select", { value: creator.config.format, onChange: (e) => creator.updateConfig({ format: e.target.value }), style: styles.select, children: [jsx("option", { value: "esm", children: "ES Modules" }), jsx("option", { value: "cjs", children: "CommonJS" }), jsx("option", { value: "both", children: "Both" })] })] }), jsxs("div", { style: styles.checkboxGroup, children: [jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.generateTypes, onChange: (e) => creator.updateConfig({ generateTypes: e.target.checked }) }), "Generate TypeScript types"] }), jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.treeShaking, onChange: (e) => creator.updateConfig({ treeShaking: e.target.checked }) }), "Tree-shaking friendly"] }), jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.includeMetadata, onChange: (e) => creator.updateConfig({ includeMetadata: e.target.checked }) }), "Include metadata"] })] }), jsxs("div", { style: styles.exportActions, children: [jsx("button", { onClick: handleExport, style: styles.primaryButton, children: "Preview Export" }), jsx("button", { onClick: handleDownloadZip, style: styles.secondaryButton, children: "Download Files" })] })] }), jsxs("div", { style: styles.selectionPanel, children: [jsxs("div", { style: styles.selectionHeader, children: [jsx("input", { type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search icons...", style: styles.searchInput }), jsxs("select", { value: categoryFilter, onChange: (e) => setCategoryFilter(e.target.value), style: styles.categorySelect, children: [jsx("option", { value: "all", children: "All Categories" }), categories.map((cat) => (jsx("option", { value: cat, children: cat }, cat)))] })] }), jsxs("div", { style: styles.selectionActions, children: [jsx("button", { onClick: creator.selectAll, style: styles.smallButton, children: "Select All" }), jsx("button", { onClick: creator.deselectAll, style: styles.smallButton, children: "Deselect All" })] }), jsx("div", { style: styles.iconGrid, children: filteredItems.map((item) => (jsxs("div", { onClick: () => creator.toggleIcon(item.originalName), style: {
344
+ return (jsxs("div", { className: `nice-icon-set-creator ${className}`, style: styles.container, children: [jsxs("div", { style: styles.header, children: [jsx("h2", { style: styles.title, children: t('iconSetCreator.iconSetCreator', 'Icon Set Creator') }), jsx("div", { style: styles.stats, children: t('iconSetCreator.iconsSelected', '{selectedCount} / {items} icons selected')
345
+ .replace('{selectedCount}', String(creator.selectedCount))
346
+ .replace('{items}', String(creator.items.length)) })] }), jsxs("div", { style: styles.content, children: [jsxs("div", { style: styles.configPanel, children: [jsx("h3", { style: styles.sectionTitle, children: t('iconSetCreator.configuration', 'Configuration') }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.setName', 'Set Name') }), jsx("input", { type: "text", value: creator.config.name, onChange: (e) => creator.updateConfig({ name: e.target.value }), style: styles.input, placeholder: "MyIcons" })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.packageName', 'Package Name') }), jsx("input", { type: "text", value: creator.config.packageName, onChange: (e) => creator.updateConfig({ packageName: e.target.value }), style: styles.input, placeholder: "@myproject/icons" })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.description', 'Description') }), jsx("input", { type: "text", value: creator.config.description, onChange: (e) => creator.updateConfig({ description: e.target.value }), style: styles.input })] }), jsxs("div", { style: styles.fieldRow, children: [jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.version', 'Version') }), jsx("input", { type: "text", value: creator.config.version, onChange: (e) => creator.updateConfig({ version: e.target.value }), style: styles.input })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.license', 'License') }), jsx("input", { type: "text", value: creator.config.license, onChange: (e) => creator.updateConfig({ license: e.target.value }), style: styles.input })] })] }), jsxs("div", { style: styles.field, children: [jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.exportFormat', 'Export Format') }), jsxs("select", { value: creator.config.format, onChange: (e) => creator.updateConfig({ format: e.target.value }), style: styles.select, children: [jsx("option", { value: "esm", children: t('iconSetCreator.esModules', 'ES Modules') }), jsx("option", { value: "cjs", children: "CommonJS" }), jsx("option", { value: "both", children: t('iconSetCreator.both', 'Both') })] })] }), jsxs("div", { style: styles.checkboxGroup, children: [jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.generateTypes, onChange: (e) => creator.updateConfig({ generateTypes: e.target.checked }) }), t('iconSetCreator.generateTypescriptTypes', 'Generate TypeScript types')] }), jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.treeShaking, onChange: (e) => creator.updateConfig({ treeShaking: e.target.checked }) }), t('iconSetCreator.treeShakingFriendly', 'Tree-shaking friendly')] }), jsxs("label", { style: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: creator.config.includeMetadata, onChange: (e) => creator.updateConfig({ includeMetadata: e.target.checked }) }), t('iconSetCreator.includeMetadata', 'Include metadata')] })] }), jsxs("div", { style: styles.exportActions, children: [jsx("button", { onClick: handleExport, style: styles.primaryButton, children: t('iconSetCreator.previewExport', 'Preview Export') }), jsx("button", { onClick: handleDownloadZip, style: styles.secondaryButton, children: t('iconSetCreator.downloadFiles', 'Download Files') })] })] }), jsxs("div", { style: styles.selectionPanel, children: [jsxs("div", { style: styles.selectionHeader, children: [jsx("input", { type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: t('iconSetCreator.searchIcons', 'Search icons...'), style: styles.searchInput }), jsxs("select", { value: categoryFilter, onChange: (e) => setCategoryFilter(e.target.value), style: styles.categorySelect, children: [jsx("option", { value: "all", children: t('iconSetCreator.allCategories', 'All Categories') }), categories.map((cat) => (jsx("option", { value: cat, children: cat }, cat)))] })] }), jsxs("div", { style: styles.selectionActions, children: [jsx("button", { onClick: creator.selectAll, style: styles.smallButton, children: t('iconSetCreator.selectAll', 'Select All') }), jsx("button", { onClick: creator.deselectAll, style: styles.smallButton, children: t('iconSetCreator.deselectAll', 'Deselect All') })] }), jsx("div", { style: styles.iconGrid, children: filteredItems.map((item) => (jsxs("div", { role: "checkbox", "aria-checked": item.included, "aria-label": item.customName, tabIndex: 0, onClick: () => creator.toggleIcon(item.originalName), onKeyDown: (e) => {
347
+ if (e.key === 'Enter' || e.key === ' ') {
348
+ e.preventDefault();
349
+ creator.toggleIcon(item.originalName);
350
+ }
351
+ }, style: {
370
352
  ...styles.iconItem,
371
353
  borderColor: item.included ? '#3b82f6' : '#e5e7eb',
372
354
  backgroundColor: item.included ? '#eff6ff' : '#fff',
373
- }, children: [jsx(item.icon, { size: 32 }), jsx("span", { style: styles.iconName, children: item.customName }), item.included && (jsx("span", { style: styles.checkmark, children: jsx(NtdCheck, { size: 14 }) }))] }, item.originalName))) })] }), previewOutput && (jsxs("div", { style: styles.previewPanel, children: [jsx("h3", { style: styles.sectionTitle, children: "Export Preview" }), previewOutput.map((file) => (jsxs("div", { style: styles.filePreview, children: [jsx("div", { style: styles.fileName, children: file.filename }), jsxs("pre", { style: styles.codePreview, children: [file.content.slice(0, 1000), file.content.length > 1000 && '...'] })] }, file.filename)))] }))] })] }));
355
+ }, children: [jsx(item.icon, { size: 32 }), jsx("span", { style: styles.iconName, children: item.customName }), item.included && (jsx("span", { style: styles.checkmark, children: jsx(NtdCheck, { size: 14 }) }))] }, item.originalName))) })] }), previewOutput && (jsxs("div", { style: styles.previewPanel, children: [jsx("h3", { style: styles.sectionTitle, children: t('iconSetCreator.exportPreview', 'Export Preview') }), previewOutput.map((file) => (jsxs("div", { style: styles.filePreview, children: [jsx("div", { style: styles.fileName, children: file.filename }), jsxs("pre", { style: styles.codePreview, children: [file.content.slice(0, 1000), file.content.length > 1000 && '...'] })] }, file.filename)))] }))] })] }));
374
356
  }
375
357
  /* ══════════════════════════════════════════════════════════════════════════════
376
358
  Styles
@@ -1,7 +1,17 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useNiceTranslation } from '@nice2dev/ui-core';
2
3
  import { forwardRef, useState, useRef, useEffect } from 'react';
3
4
  import { SIZE_MAP } from './types.js';
4
5
 
6
+ /** The status in words for the accessible name — English defaults of `ntdIconBadge.statusValue.*`. */
7
+ const STATUS_WORDS = {
8
+ online: 'online',
9
+ offline: 'offline',
10
+ busy: 'busy',
11
+ away: 'away',
12
+ dnd: 'do not disturb',
13
+ invisible: 'invisible',
14
+ };
5
15
  /* ────────────────────────────────────────────────────────────────────────────
6
16
  CONSTANTS
7
17
  ───────────────────────────────────────────────────────────────────────────── */
@@ -185,8 +195,10 @@ function injectStyles() {
185
195
  * />
186
196
  * ```
187
197
  */
188
- const NtdBadge = forwardRef(({ icon: Icon, count = 0, maxCount = 99, showZero = false, position = 'top-right', variant = 'standard', badgeColor = '#ef4444', textColor = '#ffffff', animated = true, pulse = false, iconProps = {}, className, style, 'aria-label': ariaLabel, }, ref) => {
198
+ const NtdBadge = /* @__PURE__ */ Object.assign(
199
+ /* @__PURE__ */ forwardRef(({ icon: Icon, count = 0, maxCount = 99, showZero = false, position = 'top-right', variant = 'standard', badgeColor = '#ef4444', textColor = '#ffffff', animated = true, pulse = false, iconProps = {}, className, style, 'aria-label': ariaLabel, }, ref) => {
189
200
  var _a, _b;
201
+ const { t } = useNiceTranslation();
190
202
  const [isEntering, setIsEntering] = useState(false);
191
203
  const [countChanging, setCountChanging] = useState(false);
192
204
  const prevCountRef = useRef(count);
@@ -210,6 +222,7 @@ const NtdBadge = forwardRef(({ icon: Icon, count = 0, maxCount = 99, showZero =
210
222
  const timer = setTimeout(() => setIsEntering(false), 300);
211
223
  return () => clearTimeout(timer);
212
224
  }
225
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- the enter animation plays once, when the badge mounts
213
226
  }, []);
214
227
  const shouldShowBadge = count > 0 || showZero;
215
228
  const displayCount = count > maxCount ? `${maxCount}+` : count.toString();
@@ -230,13 +243,14 @@ const NtdBadge = forwardRef(({ icon: Icon, count = 0, maxCount = 99, showZero =
230
243
  width: resolvedSize,
231
244
  height: resolvedSize,
232
245
  ...style,
233
- }, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (shouldShowBadge ? `${count} notifications` : undefined), children: [jsx(Icon, { ...iconProps }), shouldShowBadge && (jsx("span", { className: badgeClasses, style: {
246
+ }, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (shouldShowBadge
247
+ ? t('ntdIconBadge.notifications', '{count} notifications').replace('{count}', String(count))
248
+ : undefined), children: [jsx(Icon, { ...iconProps }), shouldShowBadge && (jsx("span", { className: badgeClasses, style: {
234
249
  ...POSITION_STYLES[position],
235
250
  backgroundColor: badgeColor,
236
251
  color: textColor,
237
252
  }, "aria-hidden": "true", children: variant !== 'dot' && displayCount }))] }));
238
- });
239
- NtdBadge.displayName = 'NtdBadge';
253
+ }), { displayName: 'NtdBadge' });
240
254
  /* ────────────────────────────────────────────────────────────────────────────
241
255
  NtdStatusDot COMPONENT
242
256
  ───────────────────────────────────────────────────────────────────────────── */
@@ -255,8 +269,10 @@ NtdBadge.displayName = 'NtdBadge';
255
269
  * <NtdStatusDot icon={NtdUser} status="away" position="bottom-right" />
256
270
  * ```
257
271
  */
258
- const NtdStatusDot = forwardRef(({ icon: Icon, status, statusColor, position = 'bottom-right', dotSize = 'md', animated = true, pulse = false, iconProps = {}, className, style, }, ref) => {
259
- var _a, _b;
272
+ const NtdStatusDot = /* @__PURE__ */ Object.assign(
273
+ /* @__PURE__ */ forwardRef(({ icon: Icon, status, statusColor, position = 'bottom-right', dotSize = 'md', animated = true, pulse = false, iconProps = {}, className, style, }, ref) => {
274
+ var _a, _b, _c;
275
+ const { t } = useNiceTranslation();
260
276
  useEffect(() => {
261
277
  injectStyles();
262
278
  }, []);
@@ -276,15 +292,14 @@ const NtdStatusDot = forwardRef(({ icon: Icon, status, statusColor, position = '
276
292
  width: resolvedIconSize,
277
293
  height: resolvedIconSize,
278
294
  ...style,
279
- }, role: "status", "aria-label": `Status: ${status}`, children: [jsx(Icon, { ...iconProps }), jsx("span", { className: dotClasses, style: {
295
+ }, role: "status", "aria-label": t('ntdIconBadge.status', 'Status: {status}').replace('{status}', t('ntdIconBadge.statusValue.' + status, (_c = STATUS_WORDS[status]) !== null && _c !== void 0 ? _c : status)), children: [jsx(Icon, { ...iconProps }), jsx("span", { className: dotClasses, style: {
280
296
  ...POSITION_STYLES[position],
281
297
  width: resolvedDotSize,
282
298
  height: resolvedDotSize,
283
299
  backgroundColor: resolvedColor,
284
300
  color: resolvedColor,
285
301
  }, "aria-hidden": "true" })] }));
286
- });
287
- NtdStatusDot.displayName = 'NtdStatusDot';
302
+ }), { displayName: 'NtdStatusDot' });
288
303
  /* ────────────────────────────────────────────────────────────────────────────
289
304
  NtdIconOverlay COMPONENT
290
305
  ───────────────────────────────────────────────────────────────────────────── */
@@ -309,7 +324,8 @@ NtdStatusDot.displayName = 'NtdStatusDot';
309
324
  * />
310
325
  * ```
311
326
  */
312
- const NtdIconOverlay = forwardRef(({ icon: Icon, overlay, position = 'bottom-right', overlayScale = 0.5, overlayBg, circularBg = false, iconProps = {}, className, style, }, ref) => {
327
+ const NtdIconOverlay = /* @__PURE__ */ Object.assign(
328
+ /* @__PURE__ */ forwardRef(({ icon: Icon, overlay, position = 'bottom-right', overlayScale = 0.5, overlayBg, circularBg = false, iconProps = {}, className, style, }, ref) => {
313
329
  var _a, _b;
314
330
  useEffect(() => {
315
331
  injectStyles();
@@ -331,8 +347,7 @@ const NtdIconOverlay = forwardRef(({ icon: Icon, overlay, position = 'bottom-rig
331
347
  height: overlaySize,
332
348
  backgroundColor: overlayBg,
333
349
  }, children: overlay })] }));
334
- });
335
- NtdIconOverlay.displayName = 'NtdIconOverlay';
350
+ }), { displayName: 'NtdIconOverlay' });
336
351
  /**
337
352
  * Stack two icons for composite imagery.
338
353
  *
@@ -354,7 +369,8 @@ NtdIconOverlay.displayName = 'NtdIconOverlay';
354
369
  * />
355
370
  * ```
356
371
  */
357
- const NtdIconStack = forwardRef(({ base: BaseIcon, overlay: OverlayIcon, baseProps = {}, overlayProps = {}, position = 'bottom-right', overlayScale = 0.6, size, className, style, }, ref) => {
372
+ const NtdIconStack = /* @__PURE__ */ Object.assign(
373
+ /* @__PURE__ */ forwardRef(({ base: BaseIcon, overlay: OverlayIcon, baseProps = {}, overlayProps = {}, position = 'bottom-right', overlayScale = 0.6, size, className, style, }, ref) => {
358
374
  var _a, _b, _c;
359
375
  const resolvedSize = size
360
376
  ? typeof size === 'number'
@@ -371,7 +387,6 @@ const NtdIconStack = forwardRef(({ base: BaseIcon, overlay: OverlayIcon, basePro
371
387
  }, children: [jsx(BaseIcon, { ...baseProps, size: resolvedSize }), jsx("div", { className: "ntd-icon-overlay", style: {
372
388
  ...POSITION_STYLES[position],
373
389
  }, children: jsx(OverlayIcon, { ...overlayProps, size: overlaySize }) })] }));
374
- });
375
- NtdIconStack.displayName = 'NtdIconStack';
390
+ }), { displayName: 'NtdIconStack' });
376
391
 
377
392
  export { NtdBadge, NtdIconOverlay, NtdIconStack, NtdStatusDot };