@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.
- package/CHANGELOG.md +142 -0
- package/dist/cjs/NiceDesktopIconExporter.js +7 -7
- package/dist/cjs/NiceFaviconGenerator.js +7 -2
- package/dist/cjs/NiceIconPicker.js +32 -27
- package/dist/cjs/NiceIconPreview.js +3 -1
- package/dist/cjs/NiceIconSetCreator.js +12 -30
- package/dist/cjs/NtdIconBadge.js +30 -15
- package/dist/cjs/NtdIconMorph.js +24 -12
- package/dist/cjs/NtdStateMorph.js +3 -3
- package/dist/cjs/animationControls.js +10 -3
- package/dist/cjs/createIcon.js +5 -2
- package/dist/cjs/design-tokens.js +2 -0
- package/dist/cjs/headless-ui.js +3 -3
- package/dist/cjs/iconMetadata.js +4 -0
- package/dist/cjs/iconStyles.js +36 -34
- package/dist/cjs/icons/accessibility.js +13 -13
- package/dist/cjs/icons/actions.js +59 -25
- package/dist/cjs/icons/ai.js +15 -15
- package/dist/cjs/icons/brand.js +7 -7
- package/dist/cjs/icons/business.js +18 -81
- package/dist/cjs/icons/devtech.js +31 -103
- package/dist/cjs/icons/ecommerce.js +16 -16
- package/dist/cjs/icons/education.js +17 -17
- package/dist/cjs/icons/files.js +31 -31
- package/dist/cjs/icons/fintech.js +14 -14
- package/dist/cjs/icons/food.js +16 -16
- package/dist/cjs/icons/fun.js +13 -13
- package/dist/cjs/icons/gaming.js +15 -15
- package/dist/cjs/icons/health.js +13 -22
- package/dist/cjs/icons/index.js +12 -0
- package/dist/cjs/icons/legal.js +13 -13
- package/dist/cjs/icons/media.js +46 -23
- package/dist/cjs/icons/navigation.js +14 -14
- package/dist/cjs/icons/omniverk.js +10 -10
- package/dist/cjs/icons/realestate.js +17 -17
- package/dist/cjs/icons/saas.js +13 -13
- package/dist/cjs/icons/science.js +16 -16
- package/dist/cjs/icons/shapes.js +89 -22
- package/dist/cjs/icons/smarthome.js +13 -13
- package/dist/cjs/icons/social.js +8 -98
- package/dist/cjs/icons/sports.js +14 -14
- package/dist/cjs/icons/sustainability.js +15 -15
- package/dist/cjs/icons/travel.js +15 -15
- package/dist/cjs/icons/ui.js +39 -28
- package/dist/cjs/icons/weather.js +20 -20
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/lottieIntegration.js +3 -3
- package/dist/cjs/nicetodev-icons.css +1 -1
- package/dist/cjs/particleEffects.js +11 -4
- package/dist/cjs/resolver.js +13 -0
- package/dist/cjs/utilities.js +4 -2
- package/dist/esm/NiceDesktopIconExporter.js +7 -7
- package/dist/esm/NiceFaviconGenerator.js +7 -2
- package/dist/esm/NiceIconPicker.js +33 -28
- package/dist/esm/NiceIconPreview.js +3 -1
- package/dist/esm/NiceIconSetCreator.js +12 -30
- package/dist/esm/NtdIconBadge.js +30 -15
- package/dist/esm/NtdIconMorph.js +24 -12
- package/dist/esm/NtdStateMorph.js +3 -3
- package/dist/esm/animationControls.js +11 -4
- package/dist/esm/createIcon.js +6 -3
- package/dist/esm/design-tokens.js +2 -0
- package/dist/esm/headless-ui.js +3 -3
- package/dist/esm/iconMetadata.js +4 -0
- package/dist/esm/iconStyles.js +36 -34
- package/dist/esm/icons/accessibility.js +13 -13
- package/dist/esm/icons/actions.js +57 -26
- package/dist/esm/icons/ai.js +15 -15
- package/dist/esm/icons/brand.js +7 -7
- package/dist/esm/icons/business.js +18 -81
- package/dist/esm/icons/devtech.js +31 -103
- package/dist/esm/icons/ecommerce.js +16 -16
- package/dist/esm/icons/education.js +17 -17
- package/dist/esm/icons/files.js +31 -31
- package/dist/esm/icons/fintech.js +14 -14
- package/dist/esm/icons/food.js +16 -16
- package/dist/esm/icons/fun.js +13 -13
- package/dist/esm/icons/gaming.js +15 -15
- package/dist/esm/icons/health.js +13 -22
- package/dist/esm/icons/index.js +4 -4
- package/dist/esm/icons/legal.js +13 -13
- package/dist/esm/icons/media.js +45 -24
- package/dist/esm/icons/navigation.js +14 -14
- package/dist/esm/icons/omniverk.js +10 -10
- package/dist/esm/icons/realestate.js +17 -17
- package/dist/esm/icons/saas.js +13 -13
- package/dist/esm/icons/science.js +16 -16
- package/dist/esm/icons/shapes.js +84 -23
- package/dist/esm/icons/smarthome.js +13 -13
- package/dist/esm/icons/social.js +8 -98
- package/dist/esm/icons/sports.js +14 -14
- package/dist/esm/icons/sustainability.js +15 -15
- package/dist/esm/icons/travel.js +15 -15
- package/dist/esm/icons/ui.js +39 -29
- package/dist/esm/icons/weather.js +20 -20
- package/dist/esm/index.js +4 -4
- package/dist/esm/lottieIntegration.js +3 -3
- package/dist/esm/nicetodev-icons.css +1 -1
- package/dist/esm/particleEffects.js +11 -4
- package/dist/esm/resolver.js +13 -0
- package/dist/esm/smilAnimations.js +1 -1
- package/dist/esm/utilities.js +4 -2
- package/dist/types/NiceDesktopIconExporter.d.ts +1 -0
- package/dist/types/NtdIconBadge.d.ts +12 -4
- package/dist/types/NtdIconMorph.d.ts +9 -3
- package/dist/types/NtdStateMorph.d.ts +3 -1
- package/dist/types/design-tokens.d.ts +2 -0
- package/dist/types/headless-ui.d.ts +6 -2
- package/dist/types/iconStyles.d.ts +33 -11
- package/dist/types/icons/actions.d.ts +3 -0
- package/dist/types/icons/index.d.ts +4 -4
- package/dist/types/icons/media.d.ts +3 -0
- package/dist/types/icons/shapes.d.ts +6 -0
- package/dist/types/icons/ui.d.ts +2 -0
- package/dist/types/lottieIntegration.d.ts +3 -1
- package/dist/types/particleEffects.d.ts +3 -1
- 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:
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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 {
|
|
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
|
-
/* ───
|
|
6
|
-
const Chevron = () =>
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
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
|
|
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
|
|
391
|
+
return t('iconPicker.iconsSelected', '{count} icons selected').replace('{count}', String(selectedEntries.length));
|
|
395
392
|
}
|
|
396
|
-
return selectedEntry
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
|
406
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
package/dist/esm/NtdIconBadge.js
CHANGED
|
@@ -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 =
|
|
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
|
|
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 =
|
|
259
|
-
|
|
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":
|
|
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 =
|
|
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 =
|
|
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 };
|