@nice2dev/icons 1.2.1 → 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.
Files changed (94) hide show
  1. package/CHANGELOG.md +538 -0
  2. package/README.md +146 -134
  3. package/dist/cjs/NiceDesktopIconExporter.js +7 -3
  4. package/dist/cjs/NiceFaviconGenerator.js +6 -2
  5. package/dist/cjs/NiceIconPicker.js +36 -28
  6. package/dist/cjs/NiceIconPreview.js +3 -1
  7. package/dist/cjs/NiceIconSetCreator.js +7 -2
  8. package/dist/cjs/NtdIconBadge.js +18 -3
  9. package/dist/cjs/NtdIconMorph.js +3 -1
  10. package/dist/cjs/createIcon.js +10 -2
  11. package/dist/cjs/design-tokens.js +2 -0
  12. package/dist/cjs/iconMetadata.js +4 -0
  13. package/dist/cjs/iconParts.js +49 -0
  14. package/dist/cjs/icons/accessibility.js +12 -4
  15. package/dist/cjs/icons/actions.js +89 -25
  16. package/dist/cjs/icons/business.js +58 -28
  17. package/dist/cjs/icons/ecommerce.js +0 -20
  18. package/dist/cjs/icons/education.js +22 -9
  19. package/dist/cjs/icons/files.js +70 -56
  20. package/dist/cjs/icons/fun.js +39 -25
  21. package/dist/cjs/icons/gaming.js +29 -4
  22. package/dist/cjs/icons/health.js +11 -4
  23. package/dist/cjs/icons/index.js +63 -5
  24. package/dist/cjs/icons/input.js +120 -0
  25. package/dist/cjs/icons/legal.js +4 -9
  26. package/dist/cjs/icons/media.js +26 -11
  27. package/dist/cjs/icons/navigation.js +4 -2
  28. package/dist/cjs/icons/omniverk.js +19 -6
  29. package/dist/cjs/icons/realestate.js +10 -4
  30. package/dist/cjs/icons/saas.js +15 -4
  31. package/dist/cjs/icons/science.js +6 -3
  32. package/dist/cjs/icons/shapes.js +133 -31
  33. package/dist/cjs/icons/sports.js +6 -2
  34. package/dist/cjs/icons/ui.js +62 -20
  35. package/dist/cjs/icons/weather.js +18 -8
  36. package/dist/cjs/index.js +63 -5
  37. package/dist/cjs/nicetodev-icons.css +1 -1
  38. package/dist/cjs/resolver.js +55 -1
  39. package/dist/cjs/rsc.js +1 -1
  40. package/dist/cjs/utilities.js +4 -2
  41. package/dist/esm/NiceDesktopIconExporter.js +7 -3
  42. package/dist/esm/NiceFaviconGenerator.js +6 -2
  43. package/dist/esm/NiceIconPicker.js +37 -29
  44. package/dist/esm/NiceIconPreview.js +3 -1
  45. package/dist/esm/NiceIconSetCreator.js +7 -2
  46. package/dist/esm/NtdIconBadge.js +18 -3
  47. package/dist/esm/NtdIconMorph.js +3 -1
  48. package/dist/esm/createIcon.js +10 -2
  49. package/dist/esm/design-tokens.js +2 -0
  50. package/dist/esm/iconMetadata.js +4 -0
  51. package/dist/esm/iconParts.js +46 -0
  52. package/dist/esm/icons/accessibility.js +12 -4
  53. package/dist/esm/icons/actions.js +87 -26
  54. package/dist/esm/icons/business.js +58 -29
  55. package/dist/esm/icons/ecommerce.js +1 -19
  56. package/dist/esm/icons/education.js +22 -10
  57. package/dist/esm/icons/files.js +70 -56
  58. package/dist/esm/icons/fun.js +37 -25
  59. package/dist/esm/icons/gaming.js +29 -5
  60. package/dist/esm/icons/health.js +11 -4
  61. package/dist/esm/icons/index.js +10 -9
  62. package/dist/esm/icons/input.js +75 -0
  63. package/dist/esm/icons/legal.js +4 -9
  64. package/dist/esm/icons/media.js +26 -11
  65. package/dist/esm/icons/navigation.js +4 -2
  66. package/dist/esm/icons/omniverk.js +19 -6
  67. package/dist/esm/icons/realestate.js +10 -4
  68. package/dist/esm/icons/saas.js +15 -4
  69. package/dist/esm/icons/science.js +6 -3
  70. package/dist/esm/icons/shapes.js +128 -32
  71. package/dist/esm/icons/sports.js +6 -2
  72. package/dist/esm/icons/ui.js +62 -21
  73. package/dist/esm/icons/weather.js +18 -8
  74. package/dist/esm/index.js +10 -9
  75. package/dist/esm/nicetodev-icons.css +1 -1
  76. package/dist/esm/resolver.js +55 -1
  77. package/dist/esm/rsc.js +1 -1
  78. package/dist/esm/utilities.js +4 -2
  79. package/dist/types/design-tokens.d.ts +2 -0
  80. package/dist/types/iconParts.d.ts +19 -0
  81. package/dist/types/icons/actions.d.ts +3 -0
  82. package/dist/types/icons/business.d.ts +2 -0
  83. package/dist/types/icons/ecommerce.d.ts +0 -2
  84. package/dist/types/icons/education.d.ts +1 -0
  85. package/dist/types/icons/files.d.ts +2 -1
  86. package/dist/types/icons/fun.d.ts +6 -1
  87. package/dist/types/icons/gaming.d.ts +2 -0
  88. package/dist/types/icons/index.d.ts +10 -9
  89. package/dist/types/icons/input.d.ts +53 -0
  90. package/dist/types/icons/omniverk.d.ts +0 -2
  91. package/dist/types/icons/shapes.d.ts +6 -0
  92. package/dist/types/icons/ui.d.ts +1 -0
  93. package/dist/types/types.d.ts +6 -0
  94. package/package.json +3 -1
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
  var actions = require('./icons/actions.js');
6
7
 
@@ -225,6 +226,7 @@ function useFaviconGenerator(icon, fill = '#1e1e1e', initialConfig) {
225
226
  * Favicon generator component for creating all favicon variants.
226
227
  */
227
228
  function NiceFaviconGenerator({ icon, fill = '#1e1e1e', manifestConfig, onGenerate, className = '', }) {
229
+ const { t } = uiCore.useNiceTranslation();
228
230
  const { config, setConfig, assets, isGenerating, generate, downloadAll, downloadSingle, getManifestJson, getHtmlTags, } = useFaviconGenerator(icon, fill, manifestConfig);
229
231
  const [activeTab, setActiveTab] = React.useState('preview');
230
232
  const handleGenerate = async () => {
@@ -233,10 +235,12 @@ function NiceFaviconGenerator({ icon, fill = '#1e1e1e', manifestConfig, onGenera
233
235
  onGenerate(assets, getManifestJson());
234
236
  }
235
237
  };
236
- return (jsxRuntime.jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: "Manifest Configuration" }), jsxRuntime.jsxs("div", { style: styles.formGrid, children: [jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "App Name" }), jsxRuntime.jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "Short Name" }), jsxRuntime.jsx("input", { type: "text", value: config.shortName, onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "Theme Color" }), jsxRuntime.jsx("input", { type: "color", value: config.themeColor, onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })), style: styles.colorInput })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "Background Color" }), jsxRuntime.jsx("input", { type: "color", value: config.backgroundColor, onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })), style: styles.colorInput })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "Display Mode" }), jsxRuntime.jsxs("select", { value: config.display, onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })), style: styles.input, children: [jsxRuntime.jsx("option", { value: "standalone", children: "Standalone" }), jsxRuntime.jsx("option", { value: "fullscreen", children: "Fullscreen" }), jsxRuntime.jsx("option", { value: "minimal-ui", children: "Minimal UI" }), jsxRuntime.jsx("option", { value: "browser", children: "Browser" })] })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: "Start URL" }), jsxRuntime.jsx("input", { type: "text", value: config.startUrl, onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })), style: styles.input })] })] })] }), jsxRuntime.jsxs("div", { style: styles.actions, children: [jsxRuntime.jsx("button", { onClick: handleGenerate, disabled: isGenerating, style: {
238
+ return (jsxRuntime.jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: t('faviconGenerator.manifestConfiguration', 'Manifest Configuration') }), jsxRuntime.jsxs("div", { style: styles.formGrid, children: [jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.appName', 'App Name') }), jsxRuntime.jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.shortName', 'Short Name') }), jsxRuntime.jsx("input", { type: "text", value: config.shortName, onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.themeColor', 'Theme Color') }), jsxRuntime.jsx("input", { type: "color", value: config.themeColor, onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })), style: styles.colorInput })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.backgroundColor', 'Background Color') }), jsxRuntime.jsx("input", { type: "color", value: config.backgroundColor, onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })), style: styles.colorInput })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.displayMode', 'Display Mode') }), jsxRuntime.jsxs("select", { value: config.display, onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })), style: styles.input, children: [jsxRuntime.jsx("option", { value: "standalone", children: t('faviconGenerator.standalone', 'Standalone') }), jsxRuntime.jsx("option", { value: "fullscreen", children: t('faviconGenerator.fullscreen', 'Fullscreen') }), jsxRuntime.jsx("option", { value: "minimal-ui", children: t('faviconGenerator.minimalUi', 'Minimal UI') }), jsxRuntime.jsx("option", { value: "browser", children: t('faviconGenerator.browser', 'Browser') })] })] }), jsxRuntime.jsxs("div", { style: styles.formGroup, children: [jsxRuntime.jsx("label", { style: styles.label, children: t('faviconGenerator.startUrl', 'Start URL') }), jsxRuntime.jsx("input", { type: "text", value: config.startUrl, onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })), style: styles.input })] })] })] }), jsxRuntime.jsxs("div", { style: styles.actions, children: [jsxRuntime.jsx("button", { onClick: handleGenerate, disabled: isGenerating, style: {
237
239
  ...styles.button,
238
240
  ...(isGenerating ? styles.buttonDisabled : styles.buttonPrimary),
239
- }, children: isGenerating ? 'Generating...' : 'Generate Favicons' }), assets.length > 0 && (jsxRuntime.jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: "Download All" }))] }), assets.length > 0 && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsxs("div", { style: styles.tabs, children: [jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'preview' ? styles.tabActive : {}) }, onClick: () => setActiveTab('preview'), children: "Preview" }), jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'manifest' ? styles.tabActive : {}) }, onClick: () => setActiveTab('manifest'), children: "manifest.json" }), jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'html' ? styles.tabActive : {}) }, onClick: () => setActiveTab('html'), children: "HTML Tags" })] }), activeTab === 'preview' && (jsxRuntime.jsx("div", { style: styles.assetGrid, children: assets.map((asset) => (jsxRuntime.jsxs("div", { style: styles.assetCard, children: [jsxRuntime.jsx("div", { style: styles.assetPreview, children: jsxRuntime.jsx("img", { src: asset.dataUrl, alt: asset.filename, style: { maxWidth: '64px', maxHeight: '64px' } }) }), jsxRuntime.jsxs("div", { style: styles.assetInfo, children: [jsxRuntime.jsx("span", { style: styles.assetName, children: asset.filename }), jsxRuntime.jsxs("span", { style: styles.assetSize, children: [asset.size, "x", asset.size] }), jsxRuntime.jsx("span", { style: styles.assetPurpose, children: asset.purpose })] }), jsxRuntime.jsx("button", { onClick: () => downloadSingle(asset), style: styles.downloadBtn, "aria-label": `Download ${asset.filename}`, children: jsxRuntime.jsx(actions.NtdDownload, { size: 14, variant: "outline" }) })] }, asset.filename))) })), activeTab === 'manifest' && jsxRuntime.jsx("pre", { style: styles.codeBlock, children: getManifestJson() }), activeTab === 'html' && jsxRuntime.jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })] })), jsxRuntime.jsxs("div", { style: styles.reference, children: [jsxRuntime.jsx("h4", { style: styles.referenceTitle, children: "Favicon Sizes Reference" }), jsxRuntime.jsxs("table", { style: styles.table, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { style: styles.th, children: "File" }), jsxRuntime.jsx("th", { style: styles.th, children: "Size" }), jsxRuntime.jsx("th", { style: styles.th, children: "Purpose" })] }) }), jsxRuntime.jsx("tbody", { children: FAVICON_SIZES.map((f) => (jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsxs("td", { style: styles.td, children: [f.name, ".", f.format] }), jsxRuntime.jsxs("td", { style: styles.td, children: [f.size, "x", f.size] }), jsxRuntime.jsx("td", { style: styles.td, children: f.purpose })] }, f.name))) })] })] })] }));
241
+ }, children: isGenerating
242
+ ? t('faviconGenerator.generating', 'Generating...')
243
+ : t('faviconGenerator.generateFavicons', 'Generate Favicons') }), assets.length > 0 && (jsxRuntime.jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: t('faviconGenerator.downloadAll', 'Download All') }))] }), assets.length > 0 && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsxs("div", { style: styles.tabs, children: [jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'preview' ? styles.tabActive : {}) }, onClick: () => setActiveTab('preview'), children: t('faviconGenerator.preview', 'Preview') }), jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'manifest' ? styles.tabActive : {}) }, onClick: () => setActiveTab('manifest'), children: "manifest.json" }), jsxRuntime.jsx("button", { style: { ...styles.tab, ...(activeTab === 'html' ? styles.tabActive : {}) }, onClick: () => setActiveTab('html'), children: t('faviconGenerator.htmlTags', 'HTML Tags') })] }), activeTab === 'preview' && (jsxRuntime.jsx("div", { style: styles.assetGrid, children: assets.map((asset) => (jsxRuntime.jsxs("div", { style: styles.assetCard, children: [jsxRuntime.jsx("div", { style: styles.assetPreview, children: jsxRuntime.jsx("img", { src: asset.dataUrl, alt: asset.filename, style: { maxWidth: '64px', maxHeight: '64px' } }) }), jsxRuntime.jsxs("div", { style: styles.assetInfo, children: [jsxRuntime.jsx("span", { style: styles.assetName, children: asset.filename }), jsxRuntime.jsxs("span", { style: styles.assetSize, children: [asset.size, "x", asset.size] }), jsxRuntime.jsx("span", { style: styles.assetPurpose, children: asset.purpose })] }), jsxRuntime.jsx("button", { onClick: () => downloadSingle(asset), style: styles.downloadBtn, "aria-label": t('faviconGenerator.download', 'Download {filename}').replace('{filename}', String(asset.filename)), children: jsxRuntime.jsx(actions.NtdDownload, { size: 14, variant: "outline" }) })] }, asset.filename))) })), activeTab === 'manifest' && jsxRuntime.jsx("pre", { style: styles.codeBlock, children: getManifestJson() }), activeTab === 'html' && jsxRuntime.jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })] })), jsxRuntime.jsxs("div", { style: styles.reference, children: [jsxRuntime.jsx("h4", { style: styles.referenceTitle, children: t('faviconGenerator.faviconSizesReference', 'Favicon Sizes Reference') }), jsxRuntime.jsxs("table", { style: styles.table, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { style: styles.th, children: t('faviconGenerator.file', 'File') }), jsxRuntime.jsx("th", { style: styles.th, children: t('faviconGenerator.size', 'Size') }), jsxRuntime.jsx("th", { style: styles.th, children: t('faviconGenerator.purpose', 'Purpose') })] }) }), jsxRuntime.jsx("tbody", { children: FAVICON_SIZES.map((f) => (jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsxs("td", { style: styles.td, children: [f.name, ".", f.format] }), jsxRuntime.jsxs("td", { style: styles.td, children: [f.size, "x", f.size] }), jsxRuntime.jsx("td", { style: styles.td, children: f.purpose })] }, f.name))) })] })] })] }));
240
244
  }
241
245
  /* ══════════════════════════════════════════════════════════════════════════════
242
246
  Styles
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
  var actions = require('./icons/actions.js');
6
7
  var files = require('./icons/files.js');
@@ -71,8 +72,11 @@ function saveToStorage(key, value) {
71
72
  * }
72
73
  * ```
73
74
  */
74
- const NiceIconPicker = /* @__PURE__ */ React.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) {
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) {
75
76
  var _a;
77
+ const tablistRef = React.useRef(null);
78
+ uiCore.useRovingFocus(tablistRef, { orientation: 'horizontal', wrap: true, activateOnMove: true });
79
+ const { t } = uiCore.useNiceTranslation();
76
80
  const [isOpen, setIsOpen] = React.useState(false);
77
81
  const [search, setSearch] = React.useState('');
78
82
  const [activeCategory, setActiveCategory] = React.useState(null);
@@ -223,30 +227,26 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
223
227
  document.addEventListener('mousedown', onClickOutside);
224
228
  return () => document.removeEventListener('mousedown', onClickOutside);
225
229
  }, [isOpen]);
226
- /* ─── Focus search on open ─── */
230
+ /* ─── Reset on close ─── */
227
231
  React.useEffect(() => {
228
- if (isOpen) {
229
- requestAnimationFrame(() => { var _a; return (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
230
- }
231
- else {
232
+ if (!isOpen) {
232
233
  setSearch('');
233
234
  setActiveCategory(null);
234
235
  setVisibleRange({ start: 0, end: virtualizedItemCount });
235
236
  }
236
237
  }, [isOpen, virtualizedItemCount]);
237
- /* ─── Keyboard ─── */
238
- React.useEffect(() => {
239
- if (!isOpen) {
240
- return;
241
- }
242
- function onKeyDown(e) {
243
- if (e.key === 'Escape') {
244
- setIsOpen(false);
245
- }
246
- }
247
- document.addEventListener('keydown', onKeyDown);
248
- return () => document.removeEventListener('keydown', onKeyDown);
249
- }, [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' });
250
250
  /* ─── Virtualization scroll handler ─── */
251
251
  React.useEffect(() => {
252
252
  if (!virtualized || !isOpen || !gridWrapRef.current) {
@@ -388,19 +388,27 @@ const NiceIconPicker = /* @__PURE__ */ React.forwardRef(function NiceIconPicker(
388
388
  if (selectedEntries.length === 1) {
389
389
  return readableName(selectedEntries[0].name);
390
390
  }
391
- return `${selectedEntries.length} icons selected`;
391
+ return t('iconPicker.iconsSelected', '{count} icons selected').replace('{count}', String(selectedEntries.length));
392
392
  }
393
- return selectedEntry ? readableName(selectedEntry.name) : placeholder;
394
- }, [multiSelect, selectedEntries, selectedEntry, placeholder]);
395
- 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: "listbox", 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: "Search icons\u2026", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search icons" })] }), (allCategories.length > 1 || showFavorites || showHistory) && (jsxRuntime.jsxs("div", { className: "ntd-picker-tabs", 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: "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: "Favorites", children: [jsxRuntime.jsx(StarIcon, { filled: true }), " 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: "Recently used", children: [jsxRuntime.jsx(ClockIcon, {}), " 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, 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__'
396
- ? '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 (jsxRuntime.jsxs("div", { ref: rootRef, className: `ntd-picker${isOpen ? ' ntd-picker--open' : ''}${disabled ? ' ntd-picker--disabled' : ''}${multiSelect ? ' ntd-picker--multi' : ''}${className ? ` ${className}` : ''}`, children: [jsxRuntime.jsxs("button", { type: "button", className: "ntd-picker-trigger", onClick: handleToggle, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [jsxRuntime.jsx("span", { className: "ntd-picker-trigger-icon", children: selectedEntry ? (jsxRuntime.jsx(selectedEntry.Component, { size: triggerIconSize, variant: variant })) : multiSelect && selectedEntries.length > 1 ? (jsxRuntime.jsx("span", { className: "ntd-picker-multi-badge", children: selectedEntries.length })) : (jsxRuntime.jsx(files.NtdGrid, { size: 16, variant: "outline" })) }), jsxRuntime.jsx("span", { className: `ntd-picker-trigger-label${!selectedEntry && selectedEntries.length === 0 ? ' ntd-picker-trigger-placeholder' : ''}`, children: triggerLabel }), jsxRuntime.jsx("span", { className: "ntd-picker-trigger-chevron", children: jsxRuntime.jsx(Chevron, {}) })] }), isOpen && (jsxRuntime.jsxs("div", { ref: dropdownRef, className: "ntd-picker-dropdown", role: "dialog", "aria-label": t('iconPicker.selectIcon', 'Select icon…'), children: [jsxRuntime.jsxs("div", { className: "ntd-picker-search", children: [jsxRuntime.jsx("span", { className: "ntd-picker-search-icon", children: jsxRuntime.jsx(SearchIcon, {}) }), jsxRuntime.jsx("input", { ref: searchInputRef, type: "text", placeholder: t('iconPicker.searchIcons', 'Search icons…'), value: search, onChange: (e) => setSearch(e.target.value), "aria-label": t('iconPicker.searchIcons2', 'Search icons') })] }), (allCategories.length > 1 || showFavorites || showHistory) && (jsxRuntime.jsxs("div", { className: "ntd-picker-tabs", ref: tablistRef, role: "tablist", children: [jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === null ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(null), role: "tab", "aria-selected": activeCategory === null, children: t('iconPicker.all', 'All') }), showFavorites && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__favorites__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__favorites__'), role: "tab", "aria-selected": activeCategory === '__favorites__', title: t('iconPicker.favorites', 'Favorites'), children: [jsxRuntime.jsx(StarIcon, { filled: true }), " ", t('iconPicker.favorites', 'Favorites'), favorites.length > 0 && (jsxRuntime.jsx("span", { className: "ntd-picker-tab-count", children: favorites.length }))] })), showHistory && history.length > 0 && (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-tab ntd-picker-tab-special${activeCategory === '__history__' ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory('__history__'), role: "tab", "aria-selected": activeCategory === '__history__', title: t('iconPicker.recentlyUsed', 'Recently used'), children: [jsxRuntime.jsx(ClockIcon, {}), " ", t('iconPicker.recent', 'Recent')] })), allCategories.map((cat) => (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-tab${activeCategory === cat ? ' ntd-picker-tab--active' : ''}`, onClick: () => setActiveCategory(cat), role: "tab", "aria-selected": activeCategory === cat, children: cat }, cat)))] })), jsxRuntime.jsx("div", { className: "ntd-picker-grid-wrap", ref: gridWrapRef, role: "listbox", "aria-label": t('iconPicker.icons', 'Icons'), "aria-multiselectable": multiSelect || undefined, children: filtered.length === 0 ? (jsxRuntime.jsxs("div", { className: "ntd-picker-empty", children: [jsxRuntime.jsx("div", { className: "ntd-picker-empty-icon", children: jsxRuntime.jsx(media.NtdInbox, { size: 28, variant: "outline" }) }), activeCategory === '__favorites__'
398
+ ? t('iconPicker.noFavoritesYetClickThe', 'No favorites yet. Click the star icon to add.')
397
399
  : activeCategory === '__history__'
398
- ? 'No recent icons.'
399
- : 'No icons found'] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [virtualized && visibleRange.start > 0 && (jsxRuntime.jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxRuntime.jsxs("div", { children: [!activeCategory && !(activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.startsWith('__')) && (jsxRuntime.jsx("div", { className: "ntd-picker-category-label", children: category })), jsxRuntime.jsx("div", { className: "ntd-picker-grid", children: entries.map((entry) => {
400
+ ? t('iconPicker.noRecentIcons', 'No recent icons.')
401
+ : t('iconPicker.noIconsFound', 'No icons found')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [virtualized && visibleRange.start > 0 && (jsxRuntime.jsx("div", { style: { height: Math.floor(visibleRange.start / 6) * 48 } })), Array.from(grouped.entries()).map(([category, entries]) => (jsxRuntime.jsxs("div", { children: [!activeCategory && !(activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.startsWith('__')) && (jsxRuntime.jsx("div", { className: "ntd-picker-category-label", children: category })), jsxRuntime.jsx("div", { className: "ntd-picker-grid", children: entries.map((entry) => {
400
402
  const isSelected = selectedValues.includes(entry.name);
401
403
  const isFavorite = favorites.includes(entry.name);
402
- return (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-cell${isSelected ? ' ntd-picker-cell--selected' : ''}${multiSelect ? ' ntd-picker-cell--multi-select' : ''}${enableDragAndDrop ? ' ntd-picker-cell--draggable' : ''}`, onClick: () => handleSelect(entry), "data-name": readableName(entry.name), role: "option", "aria-selected": isSelected, title: readableName(entry.name), draggable: enableDragAndDrop, onDragStart: enableDragAndDrop ? (e) => handleDragStart(entry, e) : undefined, onDragEnd: enableDragAndDrop ? (e) => handleDragEnd(entry, e) : undefined, children: [jsxRuntime.jsx(entry.Component, { size: gridIconSize, variant: variant }), multiSelect && isSelected && (jsxRuntime.jsx("span", { className: "ntd-picker-cell-check", children: jsxRuntime.jsx(CheckIcon, {}) })), showFavorites && (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-cell-fav${isFavorite ? ' ntd-picker-cell-fav--active' : ''}`, onClick: (e) => handleFavoriteClick(e, entry.name), title: isFavorite ? 'Remove from favorites' : 'Add to favorites', children: jsxRuntime.jsx(StarIcon, { filled: isFavorite }) }))] }, entry.name));
403
- }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsxRuntime.jsx("div", { style: { height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48 } }))] })) }), jsxRuntime.jsxs("div", { className: "ntd-picker-footer", children: [jsxRuntime.jsxs("span", { className: "ntd-picker-count", children: [filtered.length, " icon", filtered.length !== 1 ? 's' : '', multiSelect && selectedValues.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [" \u2022 ", selectedValues.length, " selected"] })), maxSelections && multiSelect && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [" (max ", maxSelections, ")"] })] }), clearable && selectedValues.length > 0 && (jsxRuntime.jsxs("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: ["Clear", multiSelect ? ' all' : ' selection'] })), multiSelect && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: "Done" }))] })] }))] }));
404
+ return (jsxRuntime.jsxs("button", { type: "button", className: `ntd-picker-cell${isSelected ? ' ntd-picker-cell--selected' : ''}${multiSelect ? ' ntd-picker-cell--multi-select' : ''}${enableDragAndDrop ? ' ntd-picker-cell--draggable' : ''}`, onClick: () => handleSelect(entry), "data-name": readableName(entry.name), role: "option", "aria-selected": isSelected, title: readableName(entry.name), draggable: enableDragAndDrop, onDragStart: enableDragAndDrop ? (e) => handleDragStart(entry, e) : undefined, onDragEnd: enableDragAndDrop ? (e) => handleDragEnd(entry, e) : undefined, children: [jsxRuntime.jsx(entry.Component, { size: gridIconSize, variant: variant }), multiSelect && isSelected && (jsxRuntime.jsx("span", { className: "ntd-picker-cell-check", children: jsxRuntime.jsx(CheckIcon, {}) })), showFavorites && (jsxRuntime.jsx("button", { type: "button", className: `ntd-picker-cell-fav${isFavorite ? ' ntd-picker-cell-fav--active' : ''}`, onClick: (e) => handleFavoriteClick(e, entry.name), title: isFavorite
405
+ ? t('iconPicker.removeFromFavorites', 'Remove from favorites')
406
+ : t('iconPicker.addToFavorites', 'Add to favorites'), children: jsxRuntime.jsx(StarIcon, { filled: isFavorite }) }))] }, entry.name));
407
+ }) })] }, category))), virtualized && visibleRange.end < filtered.length && (jsxRuntime.jsx("div", { style: { height: Math.ceil((filtered.length - visibleRange.end) / 6) * 48 } }))] })) }), jsxRuntime.jsxs("div", { className: "ntd-picker-footer", children: [jsxRuntime.jsxs("span", { className: "ntd-picker-count", children: [(filtered.length === 1
408
+ ? t('iconPicker.iconCountOne', '{count} icon')
409
+ : t('iconPicker.iconCountMany', '{count} icons')).replace('{count}', String(filtered.length)), multiSelect && selectedValues.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.selected', '• {selectedValues} selected').replace('{selectedValues}', String(selectedValues.length))] })), maxSelections && multiSelect && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', t('iconPicker.max', '(max {maxSelections})').replace('{maxSelections}', String(maxSelections))] }))] }), clearable && selectedValues.length > 0 && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-clear", onClick: handleClear, children: multiSelect
410
+ ? t('iconPicker.clearAll', 'Clear all')
411
+ : t('iconPicker.clearSelection', 'Clear selection') })), multiSelect && (jsxRuntime.jsx("button", { type: "button", className: "ntd-picker-done", onClick: () => setIsOpen(false), children: t('iconPicker.done', 'Done') }))] })] }))] }));
404
412
  });
405
413
 
406
414
  exports.NiceIconPicker = NiceIconPicker;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
 
6
7
  /* ══════════════════════════════════════════════════════════════════════════════
@@ -66,6 +67,7 @@ const animationCSS = `
66
67
  * Icon preview component with multiple modes and sizes.
67
68
  */
68
69
  function NiceIconPreview({ icon: Icon, iconName = 'Icon', mode = 'both', layout = 'grid', sizes = DEFAULT_SIZES, showAnimation = true, animations = DEFAULT_ANIMATIONS, fill, className = '', }) {
70
+ const { t } = uiCore.useNiceTranslation();
69
71
  const [selectedAnimation, setSelectedAnimation] = React.useState(null);
70
72
  // Inject animation styles
71
73
  const styleSheet = React.useMemo(() => jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: animationCSS } }), []);
@@ -77,7 +79,7 @@ function NiceIconPreview({ icon: Icon, iconName = 'Icon', mode = 'both', layout
77
79
  background: BACKGROUND_COLORS[bgMode],
78
80
  }, children: jsxRuntime.jsx(Icon, { size: size, fill: iconFill, className: selectedAnimation || undefined }) }));
79
81
  };
80
- return (jsxRuntime.jsxs("div", { className: `nice-icon-preview ${className}`, style: styles.container, children: [styleSheet, jsxRuntime.jsxs("div", { style: styles.header, children: [jsxRuntime.jsx("h3", { style: styles.title, children: iconName }), showAnimation && (jsxRuntime.jsxs("div", { style: styles.animationControls, children: [jsxRuntime.jsx("span", { style: styles.animationLabel, children: "Animation:" }), jsxRuntime.jsxs("select", { value: selectedAnimation || '', onChange: (e) => setSelectedAnimation(e.target.value || null), style: styles.select, children: [jsxRuntime.jsx("option", { value: "", children: "None" }), animations.map((a) => (jsxRuntime.jsx("option", { value: a.className, children: a.name }, a.className)))] })] }))] }), layout === 'grid' && (jsxRuntime.jsxs("div", { style: styles.gridContainer, children: [(mode === 'light' || mode === 'both') && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: "Light Mode" }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'light', fill), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), (mode === 'dark' || mode === 'both') && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: "Dark Mode" }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'dark', fill), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), mode === 'gradient' && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: "Gradient Background" }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'gradient', '#ffffff'), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] }))] })), layout === 'list' && (jsxRuntime.jsx("div", { style: styles.listContainer, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.listRow, children: [jsxRuntime.jsx("span", { style: styles.listLabel, children: s.label }), renderIcon(s.size, 'light', fill), renderIcon(s.size, 'dark', fill)] }, s.size))) })), layout === 'comparison' && (jsxRuntime.jsxs("div", { style: styles.comparisonContainer, children: [jsxRuntime.jsxs("div", { style: styles.comparisonSide, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: "Light" }), jsxRuntime.jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.light }, children: jsxRuntime.jsx(Icon, { size: 96, fill: fill || '#1e1e1e', className: selectedAnimation || undefined }) })] }), jsxRuntime.jsxs("div", { style: styles.comparisonSide, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: "Dark" }), jsxRuntime.jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.dark }, children: jsxRuntime.jsx(Icon, { size: 96, fill: fill || '#ffffff', className: selectedAnimation || undefined }) })] })] }))] }));
82
+ return (jsxRuntime.jsxs("div", { className: `nice-icon-preview ${className}`, style: styles.container, children: [styleSheet, jsxRuntime.jsxs("div", { style: styles.header, children: [jsxRuntime.jsx("h3", { style: styles.title, children: iconName }), showAnimation && (jsxRuntime.jsxs("div", { style: styles.animationControls, children: [jsxRuntime.jsx("span", { style: styles.animationLabel, children: t('iconPreview.animation', 'Animation:') }), jsxRuntime.jsxs("select", { value: selectedAnimation || '', onChange: (e) => setSelectedAnimation(e.target.value || null), style: styles.select, children: [jsxRuntime.jsx("option", { value: "", children: t('iconPreview.none', 'None') }), animations.map((a) => (jsxRuntime.jsx("option", { value: a.className, children: a.name }, a.className)))] })] }))] }), layout === 'grid' && (jsxRuntime.jsxs("div", { style: styles.gridContainer, children: [(mode === 'light' || mode === 'both') && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.lightMode', 'Light Mode') }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'light', fill), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), (mode === 'dark' || mode === 'both') && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.darkMode', 'Dark Mode') }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'dark', fill), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] })), mode === 'gradient' && (jsxRuntime.jsxs("div", { style: styles.section, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.gradientBackground', 'Gradient Background') }), jsxRuntime.jsx("div", { style: styles.sizeGrid, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.sizeItem, children: [renderIcon(s.size, 'gradient', '#ffffff'), jsxRuntime.jsx("span", { style: styles.sizeLabel, children: s.label })] }, s.size))) })] }))] })), layout === 'list' && (jsxRuntime.jsx("div", { style: styles.listContainer, children: sizes.map((s) => (jsxRuntime.jsxs("div", { style: styles.listRow, children: [jsxRuntime.jsx("span", { style: styles.listLabel, children: s.label }), renderIcon(s.size, 'light', fill), renderIcon(s.size, 'dark', fill)] }, s.size))) })), layout === 'comparison' && (jsxRuntime.jsxs("div", { style: styles.comparisonContainer, children: [jsxRuntime.jsxs("div", { style: styles.comparisonSide, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.light', 'Light') }), jsxRuntime.jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.light }, children: jsxRuntime.jsx(Icon, { size: 96, fill: fill || '#1e1e1e', className: selectedAnimation || undefined }) })] }), jsxRuntime.jsxs("div", { style: styles.comparisonSide, children: [jsxRuntime.jsx("h4", { style: styles.sectionTitle, children: t('iconPreview.dark', 'Dark') }), jsxRuntime.jsx("div", { style: { ...styles.comparisonBox, background: BACKGROUND_COLORS.dark }, children: jsxRuntime.jsx(Icon, { size: 96, fill: fill || '#ffffff', className: selectedAnimation || undefined }) })] })] }))] }));
81
83
  }
82
84
  /* ══════════════════════════════════════════════════════════════════════════════
83
85
  Styles
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
  var actions = require('./icons/actions.js');
6
7
 
@@ -10,6 +11,7 @@ var actions = require('./icons/actions.js');
10
11
  const DEFAULT_CONFIG = {
11
12
  name: 'MyIcons',
12
13
  packageName: '@myproject/icons',
14
+ // audit-allow: i18n — the generated package.json's default description, not UI copy
13
15
  description: 'Custom icon set',
14
16
  version: '1.0.0',
15
17
  author: '',
@@ -287,6 +289,7 @@ function useIconSetCreator(options) {
287
289
  * Icon Set Creator component for building custom icon packages.
288
290
  */
289
291
  function NiceIconSetCreator({ icons, initialSelection, defaultConfig, onSelectionChange: _onSelectionChange, onExport, className = '', }) {
292
+ const { t } = uiCore.useNiceTranslation();
290
293
  const creator = useIconSetCreator({ icons, initialSelection, defaultConfig });
291
294
  const [searchQuery, setSearchQuery] = React.useState('');
292
295
  const [categoryFilter, setCategoryFilter] = React.useState('all');
@@ -340,7 +343,9 @@ function NiceIconSetCreator({ icons, initialSelection, defaultConfig, onSelectio
340
343
  URL.revokeObjectURL(url);
341
344
  });
342
345
  }, [creator]);
343
- return (jsxRuntime.jsxs("div", { className: `nice-icon-set-creator ${className}`, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.header, children: [jsxRuntime.jsx("h2", { style: styles.title, children: "Icon Set Creator" }), jsxRuntime.jsxs("div", { style: styles.stats, children: [creator.selectedCount, " / ", creator.items.length, " icons selected"] })] }), jsxRuntime.jsxs("div", { style: styles.content, children: [jsxRuntime.jsxs("div", { style: styles.configPanel, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: "Configuration" }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "Set Name" }), jsxRuntime.jsx("input", { type: "text", value: creator.config.name, onChange: (e) => creator.updateConfig({ name: e.target.value }), style: styles.input, placeholder: "MyIcons" })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "Package Name" }), jsxRuntime.jsx("input", { type: "text", value: creator.config.packageName, onChange: (e) => creator.updateConfig({ packageName: e.target.value }), style: styles.input, placeholder: "@myproject/icons" })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "Description" }), jsxRuntime.jsx("input", { type: "text", value: creator.config.description, onChange: (e) => creator.updateConfig({ description: e.target.value }), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.fieldRow, children: [jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "Version" }), jsxRuntime.jsx("input", { type: "text", value: creator.config.version, onChange: (e) => creator.updateConfig({ version: e.target.value }), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "License" }), jsxRuntime.jsx("input", { type: "text", value: creator.config.license, onChange: (e) => creator.updateConfig({ license: e.target.value }), style: styles.input })] })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: "Export Format" }), jsxRuntime.jsxs("select", { value: creator.config.format, onChange: (e) => creator.updateConfig({ format: e.target.value }), style: styles.select, children: [jsxRuntime.jsx("option", { value: "esm", children: "ES Modules" }), jsxRuntime.jsx("option", { value: "cjs", children: "CommonJS" }), jsxRuntime.jsx("option", { value: "both", children: "Both" })] })] }), jsxRuntime.jsxs("div", { style: styles.checkboxGroup, children: [jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.generateTypes, onChange: (e) => creator.updateConfig({ generateTypes: e.target.checked }) }), "Generate TypeScript types"] }), jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.treeShaking, onChange: (e) => creator.updateConfig({ treeShaking: e.target.checked }) }), "Tree-shaking friendly"] }), jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.includeMetadata, onChange: (e) => creator.updateConfig({ includeMetadata: e.target.checked }) }), "Include metadata"] })] }), jsxRuntime.jsxs("div", { style: styles.exportActions, children: [jsxRuntime.jsx("button", { onClick: handleExport, style: styles.primaryButton, children: "Preview Export" }), jsxRuntime.jsx("button", { onClick: handleDownloadZip, style: styles.secondaryButton, children: "Download Files" })] })] }), jsxRuntime.jsxs("div", { style: styles.selectionPanel, children: [jsxRuntime.jsxs("div", { style: styles.selectionHeader, children: [jsxRuntime.jsx("input", { type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search icons...", style: styles.searchInput }), jsxRuntime.jsxs("select", { value: categoryFilter, onChange: (e) => setCategoryFilter(e.target.value), style: styles.categorySelect, children: [jsxRuntime.jsx("option", { value: "all", children: "All Categories" }), categories.map((cat) => (jsxRuntime.jsx("option", { value: cat, children: cat }, cat)))] })] }), jsxRuntime.jsxs("div", { style: styles.selectionActions, children: [jsxRuntime.jsx("button", { onClick: creator.selectAll, style: styles.smallButton, children: "Select All" }), jsxRuntime.jsx("button", { onClick: creator.deselectAll, style: styles.smallButton, children: "Deselect All" })] }), jsxRuntime.jsx("div", { style: styles.iconGrid, children: filteredItems.map((item) => (jsxRuntime.jsxs("div", { role: "checkbox", "aria-checked": item.included, "aria-label": item.customName, tabIndex: 0, onClick: () => creator.toggleIcon(item.originalName), onKeyDown: (e) => {
346
+ return (jsxRuntime.jsxs("div", { className: `nice-icon-set-creator ${className}`, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.header, children: [jsxRuntime.jsx("h2", { style: styles.title, children: t('iconSetCreator.iconSetCreator', 'Icon Set Creator') }), jsxRuntime.jsx("div", { style: styles.stats, children: t('iconSetCreator.iconsSelected', '{selectedCount} / {items} icons selected')
347
+ .replace('{selectedCount}', String(creator.selectedCount))
348
+ .replace('{items}', String(creator.items.length)) })] }), jsxRuntime.jsxs("div", { style: styles.content, children: [jsxRuntime.jsxs("div", { style: styles.configPanel, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: t('iconSetCreator.configuration', 'Configuration') }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.setName', 'Set Name') }), jsxRuntime.jsx("input", { type: "text", value: creator.config.name, onChange: (e) => creator.updateConfig({ name: e.target.value }), style: styles.input, placeholder: "MyIcons" })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.packageName', 'Package Name') }), jsxRuntime.jsx("input", { type: "text", value: creator.config.packageName, onChange: (e) => creator.updateConfig({ packageName: e.target.value }), style: styles.input, placeholder: "@myproject/icons" })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.description', 'Description') }), jsxRuntime.jsx("input", { type: "text", value: creator.config.description, onChange: (e) => creator.updateConfig({ description: e.target.value }), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.fieldRow, children: [jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.version', 'Version') }), jsxRuntime.jsx("input", { type: "text", value: creator.config.version, onChange: (e) => creator.updateConfig({ version: e.target.value }), style: styles.input })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.license', 'License') }), jsxRuntime.jsx("input", { type: "text", value: creator.config.license, onChange: (e) => creator.updateConfig({ license: e.target.value }), style: styles.input })] })] }), jsxRuntime.jsxs("div", { style: styles.field, children: [jsxRuntime.jsx("label", { style: styles.fieldLabel, children: t('iconSetCreator.exportFormat', 'Export Format') }), jsxRuntime.jsxs("select", { value: creator.config.format, onChange: (e) => creator.updateConfig({ format: e.target.value }), style: styles.select, children: [jsxRuntime.jsx("option", { value: "esm", children: t('iconSetCreator.esModules', 'ES Modules') }), jsxRuntime.jsx("option", { value: "cjs", children: "CommonJS" }), jsxRuntime.jsx("option", { value: "both", children: t('iconSetCreator.both', 'Both') })] })] }), jsxRuntime.jsxs("div", { style: styles.checkboxGroup, children: [jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.generateTypes, onChange: (e) => creator.updateConfig({ generateTypes: e.target.checked }) }), t('iconSetCreator.generateTypescriptTypes', 'Generate TypeScript types')] }), jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.treeShaking, onChange: (e) => creator.updateConfig({ treeShaking: e.target.checked }) }), t('iconSetCreator.treeShakingFriendly', 'Tree-shaking friendly')] }), jsxRuntime.jsxs("label", { style: styles.checkbox, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: creator.config.includeMetadata, onChange: (e) => creator.updateConfig({ includeMetadata: e.target.checked }) }), t('iconSetCreator.includeMetadata', 'Include metadata')] })] }), jsxRuntime.jsxs("div", { style: styles.exportActions, children: [jsxRuntime.jsx("button", { onClick: handleExport, style: styles.primaryButton, children: t('iconSetCreator.previewExport', 'Preview Export') }), jsxRuntime.jsx("button", { onClick: handleDownloadZip, style: styles.secondaryButton, children: t('iconSetCreator.downloadFiles', 'Download Files') })] })] }), jsxRuntime.jsxs("div", { style: styles.selectionPanel, children: [jsxRuntime.jsxs("div", { style: styles.selectionHeader, children: [jsxRuntime.jsx("input", { type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: t('iconSetCreator.searchIcons', 'Search icons...'), style: styles.searchInput }), jsxRuntime.jsxs("select", { value: categoryFilter, onChange: (e) => setCategoryFilter(e.target.value), style: styles.categorySelect, children: [jsxRuntime.jsx("option", { value: "all", children: t('iconSetCreator.allCategories', 'All Categories') }), categories.map((cat) => (jsxRuntime.jsx("option", { value: cat, children: cat }, cat)))] })] }), jsxRuntime.jsxs("div", { style: styles.selectionActions, children: [jsxRuntime.jsx("button", { onClick: creator.selectAll, style: styles.smallButton, children: t('iconSetCreator.selectAll', 'Select All') }), jsxRuntime.jsx("button", { onClick: creator.deselectAll, style: styles.smallButton, children: t('iconSetCreator.deselectAll', 'Deselect All') })] }), jsxRuntime.jsx("div", { style: styles.iconGrid, children: filteredItems.map((item) => (jsxRuntime.jsxs("div", { role: "checkbox", "aria-checked": item.included, "aria-label": item.customName, tabIndex: 0, onClick: () => creator.toggleIcon(item.originalName), onKeyDown: (e) => {
344
349
  if (e.key === 'Enter' || e.key === ' ') {
345
350
  e.preventDefault();
346
351
  creator.toggleIcon(item.originalName);
@@ -349,7 +354,7 @@ function NiceIconSetCreator({ icons, initialSelection, defaultConfig, onSelectio
349
354
  ...styles.iconItem,
350
355
  borderColor: item.included ? '#3b82f6' : '#e5e7eb',
351
356
  backgroundColor: item.included ? '#eff6ff' : '#fff',
352
- }, children: [jsxRuntime.jsx(item.icon, { size: 32 }), jsxRuntime.jsx("span", { style: styles.iconName, children: item.customName }), item.included && (jsxRuntime.jsx("span", { style: styles.checkmark, children: jsxRuntime.jsx(actions.NtdCheck, { size: 14 }) }))] }, item.originalName))) })] }), previewOutput && (jsxRuntime.jsxs("div", { style: styles.previewPanel, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: "Export Preview" }), previewOutput.map((file) => (jsxRuntime.jsxs("div", { style: styles.filePreview, children: [jsxRuntime.jsx("div", { style: styles.fileName, children: file.filename }), jsxRuntime.jsxs("pre", { style: styles.codePreview, children: [file.content.slice(0, 1000), file.content.length > 1000 && '...'] })] }, file.filename)))] }))] })] }));
357
+ }, children: [jsxRuntime.jsx(item.icon, { size: 32 }), jsxRuntime.jsx("span", { style: styles.iconName, children: item.customName }), item.included && (jsxRuntime.jsx("span", { style: styles.checkmark, children: jsxRuntime.jsx(actions.NtdCheck, { size: 14 }) }))] }, item.originalName))) })] }), previewOutput && (jsxRuntime.jsxs("div", { style: styles.previewPanel, children: [jsxRuntime.jsx("h3", { style: styles.sectionTitle, children: t('iconSetCreator.exportPreview', 'Export Preview') }), previewOutput.map((file) => (jsxRuntime.jsxs("div", { style: styles.filePreview, children: [jsxRuntime.jsx("div", { style: styles.fileName, children: file.filename }), jsxRuntime.jsxs("pre", { style: styles.codePreview, children: [file.content.slice(0, 1000), file.content.length > 1000 && '...'] })] }, file.filename)))] }))] })] }));
353
358
  }
354
359
  /* ══════════════════════════════════════════════════════════════════════════════
355
360
  Styles
@@ -1,9 +1,19 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
  var types = require('./types.js');
6
7
 
8
+ /** The status in words for the accessible name — English defaults of `ntdIconBadge.statusValue.*`. */
9
+ const STATUS_WORDS = {
10
+ online: 'online',
11
+ offline: 'offline',
12
+ busy: 'busy',
13
+ away: 'away',
14
+ dnd: 'do not disturb',
15
+ invisible: 'invisible',
16
+ };
7
17
  /* ────────────────────────────────────────────────────────────────────────────
8
18
  CONSTANTS
9
19
  ───────────────────────────────────────────────────────────────────────────── */
@@ -190,6 +200,7 @@ function injectStyles() {
190
200
  const NtdBadge = /* @__PURE__ */ Object.assign(
191
201
  /* @__PURE__ */ React.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) => {
192
202
  var _a, _b;
203
+ const { t } = uiCore.useNiceTranslation();
193
204
  const [isEntering, setIsEntering] = React.useState(false);
194
205
  const [countChanging, setCountChanging] = React.useState(false);
195
206
  const prevCountRef = React.useRef(count);
@@ -213,6 +224,7 @@ const NtdBadge = /* @__PURE__ */ Object.assign(
213
224
  const timer = setTimeout(() => setIsEntering(false), 300);
214
225
  return () => clearTimeout(timer);
215
226
  }
227
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- the enter animation plays once, when the badge mounts
216
228
  }, []);
217
229
  const shouldShowBadge = count > 0 || showZero;
218
230
  const displayCount = count > maxCount ? `${maxCount}+` : count.toString();
@@ -233,7 +245,9 @@ const NtdBadge = /* @__PURE__ */ Object.assign(
233
245
  width: resolvedSize,
234
246
  height: resolvedSize,
235
247
  ...style,
236
- }, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (shouldShowBadge ? `${count} notifications` : undefined), children: [jsxRuntime.jsx(Icon, { ...iconProps }), shouldShowBadge && (jsxRuntime.jsx("span", { className: badgeClasses, style: {
248
+ }, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (shouldShowBadge
249
+ ? t('ntdIconBadge.notifications', '{count} notifications').replace('{count}', String(count))
250
+ : undefined), children: [jsxRuntime.jsx(Icon, { ...iconProps }), shouldShowBadge && (jsxRuntime.jsx("span", { className: badgeClasses, style: {
237
251
  ...POSITION_STYLES[position],
238
252
  backgroundColor: badgeColor,
239
253
  color: textColor,
@@ -259,7 +273,8 @@ const NtdBadge = /* @__PURE__ */ Object.assign(
259
273
  */
260
274
  const NtdStatusDot = /* @__PURE__ */ Object.assign(
261
275
  /* @__PURE__ */ React.forwardRef(({ icon: Icon, status, statusColor, position = 'bottom-right', dotSize = 'md', animated = true, pulse = false, iconProps = {}, className, style, }, ref) => {
262
- var _a, _b;
276
+ var _a, _b, _c;
277
+ const { t } = uiCore.useNiceTranslation();
263
278
  React.useEffect(() => {
264
279
  injectStyles();
265
280
  }, []);
@@ -279,7 +294,7 @@ const NtdStatusDot = /* @__PURE__ */ Object.assign(
279
294
  width: resolvedIconSize,
280
295
  height: resolvedIconSize,
281
296
  ...style,
282
- }, role: "status", "aria-label": `Status: ${status}`, children: [jsxRuntime.jsx(Icon, { ...iconProps }), jsxRuntime.jsx("span", { className: dotClasses, style: {
297
+ }, 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: [jsxRuntime.jsx(Icon, { ...iconProps }), jsxRuntime.jsx("span", { className: dotClasses, style: {
283
298
  ...POSITION_STYLES[position],
284
299
  width: resolvedDotSize,
285
300
  height: resolvedDotSize,
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
+ var uiCore = require('@nice2dev/ui-core');
4
5
  var React = require('react');
5
6
  var actions = require('./icons/actions.js');
6
7
  var media = require('./icons/media.js');
@@ -264,6 +265,7 @@ const NtdIconMorph = /* @__PURE__ */ Object.assign(
264
265
  const NtdPathMorph = /* @__PURE__ */ Object.assign(
265
266
  /* @__PURE__ */ React.forwardRef(({ pair, morphed: controlledMorphed, trigger = 'none', duration = 300, easing = 'ease-in-out', size = 'md', color = 'currentColor', strokeWidth = 2, filled = false, onMorphStart, onMorphEnd, className, style, 'aria-label': ariaLabel, }, ref) => {
266
267
  var _a, _b;
268
+ const { t } = uiCore.useNiceTranslation();
267
269
  const [internalMorphed, setInternalMorphed] = React.useState(false);
268
270
  const morphed = controlledMorphed !== null && controlledMorphed !== void 0 ? controlledMorphed : internalMorphed;
269
271
  const [isAnimating, setIsAnimating] = React.useState(false);
@@ -315,7 +317,7 @@ const NtdPathMorph = /* @__PURE__ */ Object.assign(
315
317
  return (jsxRuntime.jsx("svg", { ref: ref, xmlns: "http://www.w3.org/2000/svg", viewBox: pathData.viewBox, width: resolvedSize, height: resolvedSize, className: `ntd-path-morph ${className !== null && className !== void 0 ? className : ''}`, style: {
316
318
  cursor: trigger !== 'none' ? 'pointer' : undefined,
317
319
  ...style,
318
- }, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, role: trigger !== 'none' ? 'button' : 'img', "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : `${pair} icon`, "aria-pressed": trigger !== 'none' ? morphed : undefined, children: jsxRuntime.jsx("path", { d: currentPath, fill: filled ? color : 'none', stroke: filled ? 'none' : color, strokeWidth: filled ? 0 : strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", style: {
320
+ }, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, role: trigger !== 'none' ? 'button' : 'img', "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : t('ntdIconMorph.icon', '{pair} icon').replace('{pair}', String(pair)), "aria-pressed": trigger !== 'none' ? morphed : undefined, children: jsxRuntime.jsx("path", { d: currentPath, fill: filled ? color : 'none', stroke: filled ? 'none' : color, strokeWidth: filled ? 0 : strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", style: {
319
321
  transition: `d ${duration}ms ${resolvedEasing}, fill ${duration}ms ${resolvedEasing}, stroke ${duration}ms ${resolvedEasing}`,
320
322
  } }) }));
321
323
  }), { displayName: 'NtdPathMorph' });
@@ -85,7 +85,11 @@ function renderGradientDef(id, preset, type, angle, animation) {
85
85
  }
86
86
  /* ── 3D filter helper ───────────────────────────────── */
87
87
  function render3dFilterDef(filterId) {
88
- return (jsxRuntime.jsxs("filter", { id: filterId, x: "-20%", y: "-20%", width: "140%", height: "140%", children: [jsxRuntime.jsx("feDropShadow", { dx: "0", dy: "1.5", stdDeviation: "1", floodOpacity: "0.35" }), jsxRuntime.jsxs("feComponentTransfer", { in: "SourceGraphic", result: "highlight", children: [jsxRuntime.jsx("feFuncR", { type: "linear", slope: "1.2", intercept: "0.1" }), jsxRuntime.jsx("feFuncG", { type: "linear", slope: "1.2", intercept: "0.1" }), jsxRuntime.jsx("feFuncB", { type: "linear", slope: "1.2", intercept: "0.1" })] }), jsxRuntime.jsx("feComposite", { operator: "in", in: "highlight", in2: "SourceGraphic", result: "highlightMask" }), jsxRuntime.jsx("feMerge", { children: jsxRuntime.jsx("feMergeNode", { in: "SourceGraphic" }) })] }));
88
+ return (
89
+ // The region is the icon's box plus a margin for the shadow, not a share of the shape's
90
+ // bounding box: a lone horizontal or vertical line (NtdMinus) has a zero-height box, and a
91
+ // filter region of 140% of zero rendered nothing.
92
+ jsxRuntime.jsxs("filter", { id: filterId, filterUnits: "userSpaceOnUse", x: "-4", y: "-4", width: "32", height: "32", children: [jsxRuntime.jsx("feDropShadow", { dx: "0", dy: "1.5", stdDeviation: "1", floodOpacity: "0.35" }), jsxRuntime.jsxs("feComponentTransfer", { in: "SourceGraphic", result: "highlight", children: [jsxRuntime.jsx("feFuncR", { type: "linear", slope: "1.2", intercept: "0.1" }), jsxRuntime.jsx("feFuncG", { type: "linear", slope: "1.2", intercept: "0.1" }), jsxRuntime.jsx("feFuncB", { type: "linear", slope: "1.2", intercept: "0.1" })] }), jsxRuntime.jsx("feComposite", { operator: "in", in: "highlight", in2: "SourceGraphic", result: "highlightMask" }), jsxRuntime.jsx("feMerge", { children: jsxRuntime.jsx("feMergeNode", { in: "SourceGraphic" }) })] }));
89
93
  }
90
94
  /* ── Cutout shape helper ──────────────────────────── */
91
95
  function renderCutoutShape(shape, fill, maskId) {
@@ -116,6 +120,8 @@ function createIcon(options) {
116
120
  var _a, _b, _c, _d, _e, _f, _g;
117
121
  const resolvedSize = typeof size === 'number' ? size : ((_a = types.SIZE_MAP[size]) !== null && _a !== void 0 ? _a : 24);
118
122
  const gradId = React.useId();
123
+ // the prefix of the ids of the clip paths the renderers draw (IconRenderProps.uid)
124
+ const uid = React.useId();
119
125
  const center = { x: 12, y: 12 }; // Default center for 24x24 viewBox
120
126
  // Use dark/light mode detection when both colors are specified
121
127
  const colorScheme = useColorScheme();
@@ -144,6 +150,7 @@ function createIcon(options) {
144
150
  strokeWidth: effectiveStrokeWidth,
145
151
  strokeLinecap,
146
152
  strokeLinejoin,
153
+ uid,
147
154
  };
148
155
  // Resolve renderer with fallback chain. `wireframe` has no authored layer
149
156
  // at all — it is a mechanical re-draw of the full `solid` construction, so
@@ -221,10 +228,11 @@ function createIcon(options) {
221
228
  variant: 'solid',
222
229
  primaryColor: 'black',
223
230
  secondaryColor: 'black',
224
- accentColor: 'black',
231
+ accentColor: 'white',
225
232
  primaryOpacity: 1,
226
233
  secondaryOpacity: 1,
227
234
  accentOpacity: 1,
235
+ uid: `${uid}m`,
228
236
  }) })] }) })), smilAnimation ? (needsSmilScaleWrapper ? (jsxRuntime.jsxs("g", { transform: `translate(${center.x}, ${center.y})`, filter: is3d ? `url(#${filterId})` : undefined, children: [jsxRuntime.jsx("g", { transform: `translate(-${center.x}, -${center.y})`, children: iconContent }), smilAnimationElements] })) : (jsxRuntime.jsxs("g", { filter: is3d ? `url(#${filterId})` : undefined, children: [iconContent, smilAnimationElements] }))) : is3d ? (jsxRuntime.jsx("g", { filter: `url(#${filterId})`, children: iconContent })) : (iconContent)] }));
229
237
  });
230
238
  Icon.displayName = displayName;
@@ -29,6 +29,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
29
29
  * @version 1.0.0
30
30
  * @since 2026-03
31
31
  * @license MIT
32
+ *
33
+ * audit-allow: i18n-file — token descriptions written into Style Dictionary output, not UI copy.
32
34
  */
33
35
  /* ────────────────────────────────────────────────────────────────────────────
34
36
  DEFAULT TOKEN VALUES
@@ -17,6 +17,8 @@
17
17
  /* ────────────────────────────────────────────────────────────────────────────
18
18
  CATEGORY METADATA
19
19
  ───────────────────────────────────────────────────────────────────────────── */
20
+ // audit-allow: i18n — English data for the host's icon browser and searchIcons(); no control of
21
+ // this package shows it.
20
22
  const CATEGORY_INFO = {
21
23
  actions: {
22
24
  label: 'Actions',
@@ -364,6 +366,7 @@ function getSearchSuggestions(partialQuery, limit = 5) {
364
366
  This will be populated when icons are imported
365
367
  ───────────────────────────────────────────────────────────────────────────── */
366
368
  // Example metadata definitions (actual ones will be in icon files)
369
+ // audit-allow: i18n — English search metadata: searchIcons() matches these words.
367
370
  const UI_ICON_METADATA = {
368
371
  NtdHome: {
369
372
  category: 'ui',
@@ -430,6 +433,7 @@ const UI_ICON_METADATA = {
430
433
  related: ['NtdBellOff', 'NtdAlarm'],
431
434
  },
432
435
  };
436
+ // audit-allow: i18n — English search metadata: searchIcons() matches these words.
433
437
  const ACTION_ICON_METADATA = {
434
438
  NtdPlay: {
435
439
  category: 'actions',
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var createIcon = require('./createIcon.js');
5
+
6
+ /**
7
+ * `content` drawn only inside `shape` — for accent lines that read as a cut through a shape (a
8
+ * pencil's band, a calendar's header line, an envelope's flap): clipped, they meet the shape's
9
+ * edges flush in every variant, where their round caps used to stick out of it (and `sharp` /
10
+ * `rounded` re-cap every stroke, so caps alone cannot do it).
11
+ *
12
+ * `uid` is the icon's `IconRenderProps.uid`; `name` tells the clips of one icon apart. Without a
13
+ * `uid` — a renderer called outside createIcon — the content is drawn as it is.
14
+ */
15
+ function within(uid, name, shape, content) {
16
+ if (!uid) {
17
+ return content;
18
+ }
19
+ const id = `${uid}${name}`;
20
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("clipPath", { id: id, children: shape }), jsxRuntime.jsx("g", { clipPath: `url(#${id})`, children: content })] }));
21
+ }
22
+ /** The page of every paper icon: 16 × 20, its top-right corner folded over 8. */
23
+ const PAPER = 'M12 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V10z';
24
+ const PAPER_FOLD = 'M12 2v6a2 2 0 002 2h6z';
25
+ const PAPER_FOLD_LINE = 'M12 2v8h8';
26
+ const PAPER_SHARP = 'M12 2H4v20h16V10z';
27
+ const PAPER_FOLD_SHARP = 'M12 2v8h8z';
28
+ /**
29
+ * A paper icon — NtdFile, and every document drawn on the same page (NtdFileText, NtdInvoice,
30
+ * NtdContract, …), so their pages and folds match. The fold is secondary when the page is filled;
31
+ * `text` is the document's writing, a path of strokes kept below the fold (y ≥ 11, x 7.5–16.5),
32
+ * drawn in the accent colour on a filled page and in primary on a stroked one.
33
+ */
34
+ function paperIcon(displayName, text = '') {
35
+ return createIcon.createIcon({
36
+ displayName,
37
+ paths: {
38
+ solid: ({ primaryColor, secondaryColor, accentColor, accentOpacity }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: PAPER, fill: primaryColor }), jsxRuntime.jsx("path", { d: PAPER_FOLD, fill: secondaryColor }), text && (jsxRuntime.jsx("path", { d: text, stroke: accentColor, strokeOpacity: accentOpacity, strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }))] })),
39
+ // square at every corner, the fold included — the derived `sharp` keeps a path's arcs round
40
+ sharp: ({ primaryColor, secondaryColor, accentColor, accentOpacity }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: PAPER_SHARP, fill: primaryColor }), jsxRuntime.jsx("path", { d: PAPER_FOLD_SHARP, fill: secondaryColor }), text && (jsxRuntime.jsx("path", { d: text, stroke: accentColor, strokeOpacity: accentOpacity, strokeWidth: "1.5", fill: "none" }))] })),
41
+ outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsx("path", { d: `${PAPER}${PAPER_FOLD_LINE}${text}`, stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" })),
42
+ duotone: ({ primaryColor, secondaryColor, secondaryOpacity, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: PAPER, fill: secondaryColor, opacity: secondaryOpacity }), jsxRuntime.jsx("path", { d: PAPER_FOLD_SHARP, fill: primaryColor, opacity: secondaryOpacity + 0.1 }), jsxRuntime.jsx("path", { d: `${PAPER}${PAPER_FOLD_LINE}${text}`, stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" })] })),
43
+ vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: PAPER, fill: primaryColor }), jsxRuntime.jsx("path", { d: PAPER, fill: "white", opacity: "0.1" }), jsxRuntime.jsx("path", { d: PAPER_FOLD, fill: secondaryColor }), text && (jsxRuntime.jsx("path", { d: text, stroke: "white", strokeOpacity: "0.9", strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }))] })),
44
+ },
45
+ });
46
+ }
47
+
48
+ exports.paperIcon = paperIcon;
49
+ exports.within = within;
@@ -15,13 +15,21 @@ const NtdAccessibility = /* @__PURE__ */ createIcon.createIcon({
15
15
  vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: primaryColor }), jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("path", { d: "M12 8c-4 0-6 1-6 2v2h3v8h2v-5h2v5h2v-8h3v-2c0-1-2-2-6-2z", fill: secondaryColor })] })),
16
16
  },
17
17
  });
18
+ // NtdWheelchair: the rider faces right, leaning back a little (it faced left and sat bolt
19
+ // upright), the arm forward on the rest, the leg out to the footrest, in a wheel that is a full
20
+ // 210° arc around the seat (it was a small ring under it).
21
+ const WC_TORSO = 'M8.2 7.4l2.2 6';
22
+ const WC_ARM = 'M9 9.4h5.6';
23
+ const WC_LEG = 'M10.4 13.4h5l2.5 6.4H21';
24
+ const WC_WHEEL = 'M5.6 10.95A5.6 5.6 0 1 0 13.25 18.6';
18
25
  const NtdWheelchair = /* @__PURE__ */ createIcon.createIcon({
19
26
  displayName: 'NtdWheelchair',
20
27
  paths: {
21
- solid: ({ primaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: primaryColor }), jsxRuntime.jsx("path", { d: "M10 8v6H6l-1 4h3l1-2h5a4 4 0 01-4 4 4 4 0 01-4-4H4a6 6 0 006 6 6 6 0 006-6v-8h-6z", fill: primaryColor }), jsxRuntime.jsx("path", { d: "M16 14l2 4h2l-2-4", fill: primaryColor })] })),
22
- outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M10 8v6H6l-1 4h3l1-2h5", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" }), jsxRuntime.jsx("circle", { cx: "10", cy: "16", r: "4", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M16 14l2 4h2", stroke: primaryColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" })] })),
23
- duotone: ({ primaryColor, secondaryColor, secondaryOpacity, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "10", cy: "16", r: "4", fill: secondaryColor, opacity: secondaryOpacity }), jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: primaryColor }), jsxRuntime.jsx("path", { d: "M10 8v6H6l-1 4h3l1-2h5", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" }), jsxRuntime.jsx("circle", { cx: "10", cy: "16", r: "4", stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" }), jsxRuntime.jsx("path", { d: "M16 14l2 4h2", stroke: primaryColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" })] })),
24
- vivid: ({ primaryColor, secondaryColor }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: primaryColor }), jsxRuntime.jsx("circle", { cx: "12", cy: "4", r: "2", fill: "white", opacity: "0.08" }), jsxRuntime.jsx("path", { d: "M10 8v6H6l-1 4h3l1-2h5a4 4 0 01-4 4 4 4 0 01-4-4H4a6 6 0 006 6 6 6 0 006-6v-8h-6z", fill: secondaryColor }), jsxRuntime.jsx("path", { d: "M16 14l2 4h2l-2-4", fill: "#3B82F6" })] })),
28
+ solid: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "8.6", cy: "3.4", r: "2.2", fill: primaryColor }), jsxRuntime.jsxs("g", { stroke: primaryColor, fill: "none", children: [jsxRuntime.jsx("path", { d: WC_TORSO, strokeWidth: strokeWidth * 1.4 }), jsxRuntime.jsx("path", { d: WC_ARM, strokeWidth: strokeWidth * 1.1 }), jsxRuntime.jsx("path", { d: WC_LEG, strokeWidth: strokeWidth * 1.3 }), jsxRuntime.jsx("path", { d: WC_WHEEL, strokeWidth: strokeWidth * 1.1 })] })] })),
29
+ outline: ({ primaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("circle", { cx: "8.6", cy: "3.4", r: "1.8", stroke: primaryColor, strokeWidth: strokeWidth }), jsxRuntime.jsx("path", { d: `${WC_TORSO}${WC_ARM}${WC_LEG}${WC_WHEEL}`, stroke: primaryColor, strokeWidth: strokeWidth, fill: "none" })] })),
30
+ // fills only: the rider primary, the wheel secondary
31
+ duotone: ({ primaryColor, secondaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: WC_WHEEL, stroke: secondaryColor, strokeWidth: strokeWidth * 1.1, fill: "none" }), jsxRuntime.jsx("circle", { cx: "8.6", cy: "3.4", r: "2.2", fill: primaryColor }), jsxRuntime.jsxs("g", { stroke: primaryColor, fill: "none", children: [jsxRuntime.jsx("path", { d: WC_TORSO, strokeWidth: strokeWidth * 1.4 }), jsxRuntime.jsx("path", { d: WC_ARM, strokeWidth: strokeWidth * 1.1 }), jsxRuntime.jsx("path", { d: WC_LEG, strokeWidth: strokeWidth * 1.3 })] })] })),
32
+ vivid: ({ primaryColor, secondaryColor, strokeWidth }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("path", { d: WC_WHEEL, stroke: secondaryColor, strokeWidth: strokeWidth * 1.1, fill: "none" }), jsxRuntime.jsx("circle", { cx: "8.6", cy: "3.4", r: "2.2", fill: primaryColor }), jsxRuntime.jsxs("g", { stroke: primaryColor, fill: "none", children: [jsxRuntime.jsx("path", { d: WC_TORSO, strokeWidth: strokeWidth * 1.4 }), jsxRuntime.jsx("path", { d: WC_ARM, strokeWidth: strokeWidth * 1.1 }), jsxRuntime.jsx("path", { d: WC_LEG, strokeWidth: strokeWidth * 1.3 })] })] })),
25
33
  },
26
34
  });
27
35
  const NtdBlind = /* @__PURE__ */ createIcon.createIcon({