@nice2dev/icons 1.1.5 → 1.1.7

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 (125) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/cjs/NiceDesktopIconExporter.js +0 -1
  3. package/dist/cjs/NiceFaviconGenerator.js +0 -1
  4. package/dist/cjs/NiceIconEditor.js +0 -1
  5. package/dist/cjs/NiceIconPicker.js +0 -1
  6. package/dist/cjs/NiceIconPreview.js +0 -1
  7. package/dist/cjs/NiceIconSetCreator.js +0 -1
  8. package/dist/cjs/NtdIconBadge.js +0 -1
  9. package/dist/cjs/NtdIconMorph.js +0 -1
  10. package/dist/cjs/NtdStateMorph.js +0 -1
  11. package/dist/cjs/advancedIconSearch.js +0 -1
  12. package/dist/cjs/animationControls.js +0 -1
  13. package/dist/cjs/client.js +33 -0
  14. package/dist/cjs/createIcon.js +0 -1
  15. package/dist/cjs/design-tokens.js +459 -0
  16. package/dist/cjs/figmaExport.js +0 -1
  17. package/dist/cjs/figmaSync.js +0 -1
  18. package/dist/cjs/headless-ui.js +430 -0
  19. package/dist/cjs/iconAnalytics.js +0 -1
  20. package/dist/cjs/iconMetadata.js +0 -1
  21. package/dist/cjs/iconStyles.js +0 -1
  22. package/dist/cjs/icons/accessibility.js +0 -1
  23. package/dist/cjs/icons/actions.js +0 -1
  24. package/dist/cjs/icons/ai.js +0 -1
  25. package/dist/cjs/icons/brand.js +0 -1
  26. package/dist/cjs/icons/business.js +0 -1
  27. package/dist/cjs/icons/devtech.js +0 -1
  28. package/dist/cjs/icons/ecommerce.js +0 -1
  29. package/dist/cjs/icons/education.js +0 -1
  30. package/dist/cjs/icons/files.js +0 -1
  31. package/dist/cjs/icons/fintech.js +0 -1
  32. package/dist/cjs/icons/food.js +0 -1
  33. package/dist/cjs/icons/fun.js +0 -1
  34. package/dist/cjs/icons/gaming.js +0 -1
  35. package/dist/cjs/icons/health.js +0 -1
  36. package/dist/cjs/icons/index.js +0 -1
  37. package/dist/cjs/icons/legal.js +0 -1
  38. package/dist/cjs/icons/media.js +0 -1
  39. package/dist/cjs/icons/navigation.js +0 -1
  40. package/dist/cjs/icons/omniverk.js +0 -1
  41. package/dist/cjs/icons/realestate.js +0 -1
  42. package/dist/cjs/icons/saas.js +0 -1
  43. package/dist/cjs/icons/science.js +0 -1
  44. package/dist/cjs/icons/shapes.js +0 -1
  45. package/dist/cjs/icons/smarthome.js +0 -1
  46. package/dist/cjs/icons/social.js +0 -1
  47. package/dist/cjs/icons/sports.js +0 -1
  48. package/dist/cjs/icons/sustainability.js +0 -1
  49. package/dist/cjs/icons/travel.js +0 -1
  50. package/dist/cjs/icons/ui.js +0 -1
  51. package/dist/cjs/icons/weather.js +0 -1
  52. package/dist/cjs/index.js +0 -1
  53. package/dist/cjs/lottieIntegration.js +0 -1
  54. package/dist/cjs/particleEffects.js +0 -1
  55. package/dist/cjs/resolver.js +0 -1
  56. package/dist/cjs/rsc.js +209 -0
  57. package/dist/cjs/sharpen.js +0 -1
  58. package/dist/cjs/smilAnimations.js +0 -1
  59. package/dist/cjs/tailwind-plugin.js +0 -1
  60. package/dist/cjs/types.js +0 -1
  61. package/dist/cjs/utilities.js +401 -0
  62. package/dist/cjs/variantProps.js +0 -1
  63. package/dist/esm/NiceDesktopIconExporter.js +0 -1
  64. package/dist/esm/NiceFaviconGenerator.js +0 -1
  65. package/dist/esm/NiceIconEditor.js +0 -1
  66. package/dist/esm/NiceIconPicker.js +0 -1
  67. package/dist/esm/NiceIconPreview.js +0 -1
  68. package/dist/esm/NiceIconSetCreator.js +0 -1
  69. package/dist/esm/NtdIconBadge.js +0 -1
  70. package/dist/esm/NtdIconMorph.js +0 -1
  71. package/dist/esm/NtdStateMorph.js +0 -1
  72. package/dist/esm/advancedIconSearch.js +0 -1
  73. package/dist/esm/animationControls.js +0 -1
  74. package/dist/esm/client.js +5 -0
  75. package/dist/esm/createIcon.js +0 -1
  76. package/dist/esm/design-tokens.js +446 -0
  77. package/dist/esm/figmaExport.js +0 -1
  78. package/dist/esm/figmaSync.js +0 -1
  79. package/dist/esm/headless-ui.js +413 -0
  80. package/dist/esm/iconAnalytics.js +0 -1
  81. package/dist/esm/iconMetadata.js +0 -1
  82. package/dist/esm/iconStyles.js +0 -1
  83. package/dist/esm/icons/accessibility.js +0 -1
  84. package/dist/esm/icons/actions.js +0 -1
  85. package/dist/esm/icons/ai.js +0 -1
  86. package/dist/esm/icons/brand.js +0 -1
  87. package/dist/esm/icons/business.js +0 -1
  88. package/dist/esm/icons/devtech.js +0 -1
  89. package/dist/esm/icons/ecommerce.js +0 -1
  90. package/dist/esm/icons/education.js +0 -1
  91. package/dist/esm/icons/files.js +0 -1
  92. package/dist/esm/icons/fintech.js +0 -1
  93. package/dist/esm/icons/food.js +0 -1
  94. package/dist/esm/icons/fun.js +0 -1
  95. package/dist/esm/icons/gaming.js +0 -1
  96. package/dist/esm/icons/health.js +0 -1
  97. package/dist/esm/icons/index.js +0 -1
  98. package/dist/esm/icons/legal.js +0 -1
  99. package/dist/esm/icons/media.js +0 -1
  100. package/dist/esm/icons/navigation.js +0 -1
  101. package/dist/esm/icons/omniverk.js +0 -1
  102. package/dist/esm/icons/realestate.js +0 -1
  103. package/dist/esm/icons/saas.js +0 -1
  104. package/dist/esm/icons/science.js +0 -1
  105. package/dist/esm/icons/shapes.js +0 -1
  106. package/dist/esm/icons/smarthome.js +0 -1
  107. package/dist/esm/icons/social.js +0 -1
  108. package/dist/esm/icons/sports.js +0 -1
  109. package/dist/esm/icons/sustainability.js +0 -1
  110. package/dist/esm/icons/travel.js +0 -1
  111. package/dist/esm/icons/ui.js +0 -1
  112. package/dist/esm/icons/weather.js +0 -1
  113. package/dist/esm/index.js +0 -1
  114. package/dist/esm/lottieIntegration.js +0 -1
  115. package/dist/esm/particleEffects.js +0 -1
  116. package/dist/esm/resolver.js +0 -1
  117. package/dist/esm/rsc.js +201 -0
  118. package/dist/esm/sharpen.js +0 -1
  119. package/dist/esm/smilAnimations.js +0 -1
  120. package/dist/esm/tailwind-plugin.js +0 -1
  121. package/dist/esm/types.js +0 -1
  122. package/dist/esm/utilities.js +384 -0
  123. package/dist/esm/variantProps.js +0 -1
  124. package/dist/types/headless-ui.d.ts +4 -4
  125. package/package.json +2 -2
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var sharpen = require('./sharpen.js');
5
+ var types = require('./types.js');
6
+
7
+ /* ────────────────────────────────────────────────────────────────────────────
8
+ RSC-COMPATIBLE ICON FACTORY
9
+ ───────────────────────────────────────────────────────────────────────────── */
10
+ /**
11
+ * Creates a React Server Component compatible icon.
12
+ *
13
+ * Unlike the standard `createIcon`, this version:
14
+ * - Does NOT use React hooks (useId, useSyncExternalStore, etc.)
15
+ * - Does NOT support animations
16
+ * - Does NOT support automatic dark/light mode detection
17
+ * - IS fully streamable and SSR-safe
18
+ *
19
+ * @param options - Icon configuration
20
+ * @returns A React function component (not using forwardRef)
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * export const NtdHomeRSC = createIconRSC({
25
+ * displayName: 'NtdHomeRSC',
26
+ * paths: {
27
+ * solid: ({ primaryColor }) => <path d="..." fill={primaryColor} />,
28
+ * outline: ({ primaryColor, strokeWidth }) => <path d="..." stroke={primaryColor} />,
29
+ * duotone: ({ primaryColor, secondaryColor }) => <path d="..." />,
30
+ * },
31
+ * });
32
+ * ```
33
+ */
34
+ function createIconRSC(options) {
35
+ const { displayName, viewBox = '0 0 24 24', paths } = options;
36
+ function IconRSC(props) {
37
+ var _a;
38
+ const { size = 'md', variant = 'solid', cutoutShape = 'rounded-square', primaryColor: primaryColorProp, secondaryColor: secondaryColorProp, accentColor: accentColorProp, secondaryOpacity = 0.35, strokeWidth = 1.5, gradient, gradientDirection = 135, color, rotate, flipX, flipY, scale, className, style, 'aria-label': ariaLabel, 'aria-hidden': ariaHidden, title, role = ariaLabel ? 'img' : 'presentation', 'data-testid': testId, } = props;
39
+ // Resolve size
40
+ const resolvedSize = typeof size === 'number' ? size : types.SIZE_MAP[size] || types.SIZE_MAP.md;
41
+ // Resolve colors with semantic color support
42
+ let primaryColor = primaryColorProp !== null && primaryColorProp !== void 0 ? primaryColorProp : 'currentColor';
43
+ const secondaryColor = secondaryColorProp !== null && secondaryColorProp !== void 0 ? secondaryColorProp : 'currentColor';
44
+ const accentColor = accentColorProp !== null && accentColorProp !== void 0 ? accentColorProp : primaryColor;
45
+ if (color && types.SEMANTIC_COLOR_DEFAULTS[color]) {
46
+ if (!primaryColorProp) {
47
+ primaryColor = types.SEMANTIC_COLOR_DEFAULTS[color];
48
+ }
49
+ }
50
+ // Resolve variant with fallback. `wireframe` always starts from `solid`
51
+ // (the full construction) — it is re-drawn mechanically, not authored.
52
+ const isCutout = variant === 'cutout' || variant === 'flat';
53
+ const pathRenderer = isCutout || variant === 'wireframe' ? paths.solid : ((_a = paths[variant]) !== null && _a !== void 0 ? _a : paths.solid);
54
+ // Build render props
55
+ const renderProps = {
56
+ primaryColor,
57
+ secondaryColor,
58
+ accentColor,
59
+ secondaryOpacity,
60
+ strokeWidth,
61
+ };
62
+ // Build transforms
63
+ const transforms = [];
64
+ if (rotate) {
65
+ transforms.push(`rotate(${rotate}deg)`);
66
+ }
67
+ if (flipX) {
68
+ transforms.push('scaleX(-1)');
69
+ }
70
+ if (flipY) {
71
+ transforms.push('scaleY(-1)');
72
+ }
73
+ if (scale && scale !== 1) {
74
+ transforms.push(`scale(${scale})`);
75
+ }
76
+ // Build gradient defs if needed
77
+ let gradientDefs = null;
78
+ let gradientId = null;
79
+ if (gradient && types.GRADIENT_PRESETS[gradient]) {
80
+ const colors = types.GRADIENT_PRESETS[gradient];
81
+ // Generate a deterministic ID based on displayName and gradient
82
+ gradientId = `${displayName}-${gradient}-grad`;
83
+ const x1 = Math.round(50 - 50 * Math.cos((gradientDirection * Math.PI) / 180));
84
+ const y1 = Math.round(50 - 50 * Math.sin((gradientDirection * Math.PI) / 180));
85
+ const x2 = Math.round(50 + 50 * Math.cos((gradientDirection * Math.PI) / 180));
86
+ const y2 = Math.round(50 + 50 * Math.sin((gradientDirection * Math.PI) / 180));
87
+ gradientDefs = (jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("linearGradient", { id: gradientId, x1: `${x1}%`, y1: `${y1}%`, x2: `${x2}%`, y2: `${y2}%`, children: colors.map((color, i) => (jsxRuntime.jsx("stop", { offset: `${(i / (colors.length - 1)) * 100}%`, stopColor: color }, i))) }) }));
88
+ // Override primary color with gradient reference
89
+ renderProps.primaryColor = `url(#${gradientId})`;
90
+ }
91
+ // Final styles
92
+ const finalStyle = {
93
+ width: resolvedSize,
94
+ height: resolvedSize,
95
+ ...style,
96
+ ...(transforms.length > 0 && { transform: transforms.join(' ') }),
97
+ };
98
+ // Cutout mask ID (deterministic for SSR)
99
+ const cutoutMaskId = isCutout ? `${displayName}-cutout-mask` : null;
100
+ // Cutout shape renderer
101
+ const cutoutBg = isCutout
102
+ ? (() => {
103
+ const fill = renderProps.primaryColor !== 'currentColor'
104
+ ? renderProps.secondaryColor
105
+ : renderProps.primaryColor;
106
+ const mask = `url(#${cutoutMaskId})`;
107
+ switch (cutoutShape) {
108
+ case 'circle':
109
+ return jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "11", fill: fill, mask: mask });
110
+ case 'square':
111
+ return jsxRuntime.jsx("rect", { x: "1", y: "1", width: "22", height: "22", fill: fill, mask: mask });
112
+ case 'hexagon':
113
+ return (jsxRuntime.jsx("polygon", { points: "12,1 22.39,6.5 22.39,17.5 12,23 1.61,17.5 1.61,6.5", fill: fill, mask: mask }));
114
+ case 'diamond':
115
+ return jsxRuntime.jsx("polygon", { points: "12,1 23,12 12,23 1,12", fill: fill, mask: mask });
116
+ case 'shield':
117
+ return (jsxRuntime.jsx("path", { d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5L12 1z", fill: fill, mask: mask }));
118
+ case 'squircle':
119
+ return (jsxRuntime.jsx("path", { d: "M12 1C5.5 1 1 5.5 1 8.5v7C1 18.5 5.5 23 12 23s11-4.5 11-7.5v-7C23 5.5 18.5 1 12 1z", fill: fill, mask: mask }));
120
+ default:
121
+ return jsxRuntime.jsx("rect", { x: "1", y: "1", width: "22", height: "22", rx: "4", fill: fill, mask: mask });
122
+ }
123
+ })()
124
+ : null;
125
+ // Mirrors the client renderer in createIcon.tsx: `sharp` / `rounded` /
126
+ // `wireframe` / `mini` all reuse `paths.solid`, so each needs its own pass
127
+ // to be distinguishable.
128
+ const rendered = isCutout
129
+ ? cutoutBg
130
+ : variant === 'sharp'
131
+ ? sharpen.sharpenTree(pathRenderer(renderProps))
132
+ : variant === 'rounded'
133
+ ? sharpen.roundTree(pathRenderer(renderProps))
134
+ : variant === 'wireframe'
135
+ ? sharpen.wireTree(pathRenderer(renderProps), renderProps.primaryColor)
136
+ : pathRenderer(renderProps);
137
+ const iconContent = variant === 'mini' ? (jsxRuntime.jsx("g", { transform: `translate(12 12) scale(${sharpen.MINI_SCALE}) translate(-12 -12)`, children: rendered })) : (rendered);
138
+ return (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: viewBox, width: resolvedSize, height: resolvedSize, fill: "none", className: className, style: finalStyle, role: role, "aria-label": ariaLabel, "aria-hidden": ariaHidden !== null && ariaHidden !== void 0 ? ariaHidden : !ariaLabel, "data-testid": testId, children: [title && jsxRuntime.jsx("title", { children: title }), gradientDefs, isCutout && (jsxRuntime.jsx("defs", { children: jsxRuntime.jsxs("mask", { id: cutoutMaskId, children: [jsxRuntime.jsx("rect", { x: "0", y: "0", width: "24", height: "24", fill: "white" }), jsxRuntime.jsx("g", { transform: "translate(12,12) scale(0.8) translate(-12,-12)", children: paths.solid({
139
+ ...renderProps,
140
+ primaryColor: 'black',
141
+ secondaryColor: 'black',
142
+ accentColor: 'black',
143
+ }) })] }) })), iconContent] }));
144
+ }
145
+ IconRSC.displayName = displayName;
146
+ return IconRSC;
147
+ }
148
+ /* ────────────────────────────────────────────────────────────────────────────
149
+ STREAMING-FRIENDLY UTILITIES
150
+ ───────────────────────────────────────────────────────────────────────────── */
151
+ /**
152
+ * Renders an icon to a static SVG string (for streaming/SSR).
153
+ * Useful for generating static assets or email templates.
154
+ */
155
+ function renderIconToString(Icon, props = {}) {
156
+ var _a;
157
+ try {
158
+ // Import react-dom/server for SSR rendering
159
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
160
+ const { renderToStaticMarkup } = require('react-dom/server');
161
+ const element = Icon(props);
162
+ return renderToStaticMarkup(element);
163
+ }
164
+ catch (_b) {
165
+ // Fallback: construct SVG manually
166
+ const { size = 'md', primaryColor = 'currentColor', variant: _variant = 'solid', className = '', } = props;
167
+ const sizeValue = (_a = types.SIZE_MAP[size]) !== null && _a !== void 0 ? _a : (typeof size === 'number' ? size : 24);
168
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="${sizeValue}" height="${sizeValue}" class="${className}" fill="${primaryColor}"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" fill="${primaryColor}"></path></svg>`;
169
+ }
170
+ }
171
+ /**
172
+ * Type guard to check if a component is an RSC-compatible icon
173
+ */
174
+ function isRSCIcon(component) {
175
+ return (typeof component === 'function' &&
176
+ 'displayName' in component &&
177
+ typeof component.displayName === 'string' &&
178
+ component.displayName.endsWith('RSC'));
179
+ }
180
+ /* ────────────────────────────────────────────────────────────────────────────
181
+ RSC ICON WRAPPER
182
+ ───────────────────────────────────────────────────────────────────────────── */
183
+ /**
184
+ * Creates an RSC version from an existing icon's path config.
185
+ * This allows creating RSC-compatible versions from standard icons.
186
+ *
187
+ * @example
188
+ * ```tsx
189
+ * import { NtdHome } from '@nice2dev/icons';
190
+ * import { wrapAsRSC } from '@nice2dev/icons/rsc';
191
+ *
192
+ * // Note: This requires access to the original path config
193
+ * const NtdHomeRSC = wrapAsRSC(NtdHome);
194
+ * ```
195
+ */
196
+ function wrapAsRSC(originalPaths, displayName) {
197
+ return createIconRSC({
198
+ displayName: `${displayName}RSC`,
199
+ paths: originalPaths,
200
+ });
201
+ }
202
+
203
+ exports.GRADIENT_PRESETS = types.GRADIENT_PRESETS;
204
+ exports.SEMANTIC_COLOR_DEFAULTS = types.SEMANTIC_COLOR_DEFAULTS;
205
+ exports.SIZE_MAP = types.SIZE_MAP;
206
+ exports.createIconRSC = createIconRSC;
207
+ exports.isRSCIcon = isRSCIcon;
208
+ exports.renderIconToString = renderIconToString;
209
+ exports.wrapAsRSC = wrapAsRSC;
@@ -145,4 +145,3 @@ exports.WIREFRAME_STROKE = WIREFRAME_STROKE;
145
145
  exports.roundTree = roundTree;
146
146
  exports.sharpenTree = sharpenTree;
147
147
  exports.wireTree = wireTree;
148
- //# sourceMappingURL=sharpen.js.map
@@ -181,4 +181,3 @@ exports.SmilAnimationWrapper = SmilAnimationWrapper;
181
181
  exports.createSmilAnimationDef = createSmilAnimationDef;
182
182
  exports.generateSmilAnimation = generateSmilAnimation;
183
183
  exports.isSmilSupported = isSmilSupported;
184
- //# sourceMappingURL=smilAnimations.js.map
@@ -343,4 +343,3 @@ const ntdIconPreset = {
343
343
 
344
344
  exports.ntdIconPlugin = ntdIconPlugin;
345
345
  exports.ntdIconPreset = ntdIconPreset;
346
- //# sourceMappingURL=tailwind-plugin.js.map
package/dist/cjs/types.js CHANGED
@@ -82,4 +82,3 @@ exports.GRADIENT_PRESETS = GRADIENT_PRESETS;
82
82
  exports.SEMANTIC_COLOR_DEFAULTS = SEMANTIC_COLOR_DEFAULTS;
83
83
  exports.SEMANTIC_COLOR_VARS = SEMANTIC_COLOR_VARS;
84
84
  exports.SIZE_MAP = SIZE_MAP;
85
- //# sourceMappingURL=types.js.map
@@ -0,0 +1,401 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+
7
+ /**
8
+ * @file utilities.ts
9
+ * @description Utility hooks and functions for @nice2dev/icons
10
+ *
11
+ * Provides:
12
+ * - useIcon hook for dynamic icon loading
13
+ * - useReducedMotion hook for accessibility
14
+ * - preloadIcons for performance optimization
15
+ * - Icon type guards and helpers
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * import { useIcon, useReducedMotion, preloadIcons } from '@nice2dev/icons/utilities';
20
+ *
21
+ * // Dynamic icon loading
22
+ * const { Icon, isLoading } = useIcon('NtdHome');
23
+ *
24
+ * // Respect user preference for reduced motion
25
+ * const prefersReducedMotion = useReducedMotion();
26
+ *
27
+ * // Preload icons for better performance
28
+ * await preloadIcons(['NtdHome', 'NtdSearch', 'NtdUser']);
29
+ * ```
30
+ *
31
+ * @version 1.0.0
32
+ * @since 2026-03
33
+ * @license MIT
34
+ */
35
+ /* ────────────────────────────────────────────────────────────────────────────
36
+ ICON REGISTRY
37
+ ───────────────────────────────────────────────────────────────────────────── */
38
+ /**
39
+ * Global icon cache for dynamic loading
40
+ */
41
+ const iconRegistry = new Map();
42
+ /**
43
+ * Registers an icon in the global registry
44
+ */
45
+ function registerIcon(name, component) {
46
+ iconRegistry.set(name, {
47
+ component,
48
+ loadedAt: Date.now(),
49
+ });
50
+ }
51
+ /**
52
+ * Gets an icon from the registry
53
+ */
54
+ function getIconFromRegistry(name) {
55
+ var _a;
56
+ return (_a = iconRegistry.get(name)) === null || _a === void 0 ? void 0 : _a.component;
57
+ }
58
+ /**
59
+ * Clears the icon registry
60
+ */
61
+ function clearIconRegistry() {
62
+ iconRegistry.clear();
63
+ }
64
+ /**
65
+ * Gets all registered icon names
66
+ */
67
+ function getRegisteredIconNames() {
68
+ return Array.from(iconRegistry.keys());
69
+ }
70
+ /* ────────────────────────────────────────────────────────────────────────────
71
+ USE ICON HOOK
72
+ ───────────────────────────────────────────────────────────────────────────── */
73
+ /**
74
+ * Hook for dynamically loading icons by name.
75
+ *
76
+ * @param iconName - Name of the icon to load (e.g., 'NtdHome')
77
+ * @param options - Loading options
78
+ * @returns Icon component, loading state, and error
79
+ *
80
+ * @example
81
+ * ```tsx
82
+ * function DynamicIcon({ name }: { name: string }) {
83
+ * const { Icon, isLoading, error } = useIcon(name);
84
+ *
85
+ * if (isLoading) return <Spinner />;
86
+ * if (error || !Icon) return <FallbackIcon />;
87
+ *
88
+ * return <Icon size="md" />;
89
+ * }
90
+ * ```
91
+ */
92
+ function useIcon(iconName, options = {}) {
93
+ const { fallback, cache = true } = options;
94
+ const [state, setState] = React.useState({
95
+ Icon: iconName ? getIconFromRegistry(iconName) || null : null,
96
+ isLoading: false,
97
+ error: null,
98
+ });
99
+ React.useEffect(() => {
100
+ if (!iconName) {
101
+ setState({ Icon: null, isLoading: false, error: null });
102
+ return;
103
+ }
104
+ // Check cache first
105
+ const cached = getIconFromRegistry(iconName);
106
+ if (cached) {
107
+ setState({ Icon: cached, isLoading: false, error: null });
108
+ return;
109
+ }
110
+ // Start loading
111
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
112
+ // Dynamic import (assumes icons are exported individually)
113
+ const loadIcon = async () => {
114
+ try {
115
+ // Try to import from the icons module
116
+ const module = await Promise.resolve().then(function () { return require('./icons/index.js'); });
117
+ const IconComponent = module[iconName];
118
+ if (IconComponent) {
119
+ if (cache) {
120
+ registerIcon(iconName, IconComponent);
121
+ }
122
+ setState({ Icon: IconComponent, isLoading: false, error: null });
123
+ }
124
+ else {
125
+ throw new Error(`Icon "${iconName}" not found`);
126
+ }
127
+ }
128
+ catch (err) {
129
+ setState({
130
+ Icon: fallback || null,
131
+ isLoading: false,
132
+ error: err instanceof Error ? err : new Error('Failed to load icon'),
133
+ });
134
+ }
135
+ };
136
+ loadIcon();
137
+ }, [iconName, cache, fallback]);
138
+ return state;
139
+ }
140
+ /* ────────────────────────────────────────────────────────────────────────────
141
+ USE REDUCED MOTION
142
+ ───────────────────────────────────────────────────────────────────────────── */
143
+ /**
144
+ * Subscribes to prefers-reduced-motion media query.
145
+ */
146
+ function subscribeToReducedMotion(callback) {
147
+ if (typeof window === 'undefined') {
148
+ return () => { };
149
+ }
150
+ const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
151
+ const handler = () => callback();
152
+ mediaQuery.addEventListener('change', handler);
153
+ return () => mediaQuery.removeEventListener('change', handler);
154
+ }
155
+ /**
156
+ * Gets current reduced motion preference.
157
+ */
158
+ function getReducedMotionSnapshot() {
159
+ if (typeof window === 'undefined') {
160
+ return false;
161
+ }
162
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
163
+ }
164
+ /**
165
+ * Server snapshot for SSR (assumes no reduced motion preference).
166
+ */
167
+ function getReducedMotionServerSnapshot() {
168
+ return false;
169
+ }
170
+ /**
171
+ * Hook that returns true if user prefers reduced motion.
172
+ * Uses useSyncExternalStore for SSR compatibility.
173
+ *
174
+ * @returns Whether the user prefers reduced motion
175
+ *
176
+ * @example
177
+ * ```tsx
178
+ * function AnimatedIcon() {
179
+ * const prefersReducedMotion = useReducedMotion();
180
+ *
181
+ * return (
182
+ * <NtdHeart
183
+ * animation={prefersReducedMotion ? undefined : 'pulse'}
184
+ * />
185
+ * );
186
+ * }
187
+ * ```
188
+ */
189
+ function useReducedMotion() {
190
+ return React.useSyncExternalStore(subscribeToReducedMotion, getReducedMotionSnapshot, getReducedMotionServerSnapshot);
191
+ }
192
+ /* ────────────────────────────────────────────────────────────────────────────
193
+ PRELOAD ICONS
194
+ ───────────────────────────────────────────────────────────────────────────── */
195
+ /**
196
+ * Preloads icons into the registry for instant access.
197
+ *
198
+ * @param iconNames - Array of icon names to preload
199
+ * @returns Promise that resolves when all icons are loaded
200
+ *
201
+ * @example
202
+ * ```tsx
203
+ * // Preload critical icons at app startup
204
+ * useEffect(() => {
205
+ * preloadIcons(['NtdHome', 'NtdSearch', 'NtdUser', 'NtdMenu']);
206
+ * }, []);
207
+ * ```
208
+ */
209
+ async function preloadIcons(iconNames) {
210
+ const results = new Map();
211
+ try {
212
+ const module = await Promise.resolve().then(function () { return require('./icons/index.js'); });
213
+ for (const name of iconNames) {
214
+ const IconComponent = module[name];
215
+ if (IconComponent) {
216
+ registerIcon(name, IconComponent);
217
+ results.set(name, IconComponent);
218
+ }
219
+ }
220
+ }
221
+ catch (error) {
222
+ console.warn('Failed to preload icons:', error);
223
+ }
224
+ return results;
225
+ }
226
+ /**
227
+ * Creates a preloader component that preloads icons on mount.
228
+ *
229
+ * @param iconNames - Icons to preload
230
+ * @returns React component that preloads icons
231
+ *
232
+ * @example
233
+ * ```tsx
234
+ * const IconPreloader = createIconPreloader(['NtdHome', 'NtdSearch']);
235
+ *
236
+ * function App() {
237
+ * return (
238
+ * <>
239
+ * <IconPreloader />
240
+ * <MainContent />
241
+ * </>
242
+ * );
243
+ * }
244
+ * ```
245
+ */
246
+ function createIconPreloader(iconNames) {
247
+ return function IconPreloader() {
248
+ React.useEffect(() => {
249
+ preloadIcons(iconNames);
250
+ }, []);
251
+ return null;
252
+ };
253
+ }
254
+ /* ────────────────────────────────────────────────────────────────────────────
255
+ ICON PROPS HELPERS
256
+ ───────────────────────────────────────────────────────────────────────────── */
257
+ /**
258
+ * Creates props with animation disabled if user prefers reduced motion.
259
+ *
260
+ * @param props - Original icon props
261
+ * @param prefersReducedMotion - Whether user prefers reduced motion
262
+ * @returns Props with animation conditionally disabled
263
+ */
264
+ function withReducedMotionProps(props, prefersReducedMotion) {
265
+ if (!prefersReducedMotion) {
266
+ return props;
267
+ }
268
+ return {
269
+ ...props,
270
+ animation: undefined,
271
+ animationDuration: undefined,
272
+ gradientAnimation: undefined,
273
+ };
274
+ }
275
+ /**
276
+ * Creates accessible icon props based on context.
277
+ *
278
+ * @param options - Accessibility options
279
+ * @returns Icon props for accessibility
280
+ */
281
+ function createAccessibleIconProps(options) {
282
+ const { label, isDecorative = !label, role } = options;
283
+ if (isDecorative) {
284
+ return {
285
+ 'aria-hidden': true,
286
+ role: 'presentation',
287
+ };
288
+ }
289
+ return {
290
+ 'aria-label': label,
291
+ role: role || 'img',
292
+ title: label,
293
+ };
294
+ }
295
+ /* ────────────────────────────────────────────────────────────────────────────
296
+ ICON TYPE GUARDS
297
+ ───────────────────────────────────────────────────────────────────────────── */
298
+ /**
299
+ * Checks if a value is a valid icon component.
300
+ * Handles both regular components and forwardRef components.
301
+ */
302
+ function isIconComponent(value) {
303
+ if (value == null) {
304
+ return false;
305
+ }
306
+ // ForwardRef components are objects with $$typeof, regular components are functions
307
+ const isValidComponent = typeof value === 'function' || (typeof value === 'object' && '$$typeof' in value);
308
+ if (!isValidComponent) {
309
+ return false;
310
+ }
311
+ const displayName = value.displayName;
312
+ return typeof displayName === 'string' && displayName.startsWith('Ntd');
313
+ }
314
+ /**
315
+ * Checks if an icon name is valid.
316
+ */
317
+ function isValidIconName(name) {
318
+ return /^Ntd[A-Z][a-zA-Z0-9]*$/.test(name);
319
+ }
320
+ /**
321
+ * Creates a function that renders multiple icons efficiently.
322
+ *
323
+ * @param configs - Array of icon configurations
324
+ * @returns Function that renders all configured icons
325
+ *
326
+ * @example
327
+ * ```tsx
328
+ * const renderNavIcons = createBatchIconRenderer([
329
+ * { name: 'NtdHome', props: { size: 'md' } },
330
+ * { name: 'NtdSearch', props: { size: 'md' } },
331
+ * { name: 'NtdUser', props: { size: 'md' } },
332
+ * ]);
333
+ *
334
+ * // In component
335
+ * const icons = renderNavIcons();
336
+ * ```
337
+ */
338
+ function useBatchIcons(configs) {
339
+ const [icons, setIcons] = React.useState(new Map());
340
+ const [isLoading, setIsLoading] = React.useState(true);
341
+ React.useEffect(() => {
342
+ const loadIcons = async () => {
343
+ setIsLoading(true);
344
+ const names = configs.map((c) => c.name);
345
+ const loadedIcons = await preloadIcons(names);
346
+ setIcons(loadedIcons);
347
+ setIsLoading(false);
348
+ };
349
+ loadIcons();
350
+ }, [configs.map((c) => c.name).join(',')]);
351
+ const renderIcon = React.useCallback((name, additionalProps) => {
352
+ const Icon = icons.get(name);
353
+ const config = configs.find((c) => c.name === name);
354
+ if (!Icon) {
355
+ return null;
356
+ }
357
+ const mergedProps = {
358
+ ...config === null || config === void 0 ? void 0 : config.props,
359
+ ...additionalProps,
360
+ };
361
+ return React.createElement(Icon, mergedProps);
362
+ }, [icons, configs]);
363
+ return {
364
+ renderIcon,
365
+ isLoading,
366
+ icons,
367
+ };
368
+ }
369
+ /* ────────────────────────────────────────────────────────────────────────────
370
+ EXPORTS
371
+ ───────────────────────────────────────────────────────────────────────────── */
372
+ var utilities = {
373
+ useIcon,
374
+ useReducedMotion,
375
+ preloadIcons,
376
+ createIconPreloader,
377
+ registerIcon,
378
+ getIconFromRegistry,
379
+ clearIconRegistry,
380
+ getRegisteredIconNames,
381
+ withReducedMotionProps,
382
+ createAccessibleIconProps,
383
+ isIconComponent,
384
+ isValidIconName,
385
+ useBatchIcons,
386
+ };
387
+
388
+ exports.clearIconRegistry = clearIconRegistry;
389
+ exports.createAccessibleIconProps = createAccessibleIconProps;
390
+ exports.createIconPreloader = createIconPreloader;
391
+ exports.default = utilities;
392
+ exports.getIconFromRegistry = getIconFromRegistry;
393
+ exports.getRegisteredIconNames = getRegisteredIconNames;
394
+ exports.isIconComponent = isIconComponent;
395
+ exports.isValidIconName = isValidIconName;
396
+ exports.preloadIcons = preloadIcons;
397
+ exports.registerIcon = registerIcon;
398
+ exports.useBatchIcons = useBatchIcons;
399
+ exports.useIcon = useIcon;
400
+ exports.useReducedMotion = useReducedMotion;
401
+ exports.withReducedMotionProps = withReducedMotionProps;
@@ -85,4 +85,3 @@ exports.isSolidProps = isSolidProps;
85
85
  exports.isThreeDProps = isThreeDProps;
86
86
  exports.isVividProps = isVividProps;
87
87
  exports.toIconProps = toIconProps;
88
- //# sourceMappingURL=variantProps.js.map
@@ -649,4 +649,3 @@ const NiceDesktopIconExporter = ({ icon, initialConfig, onExport, className = ''
649
649
  };
650
650
 
651
651
  export { DESKTOP_ICON_SIZES, LINUX_HICOLOR_DIRS, NiceDesktopIconExporter, RETINA_VARIANTS, useDesktopIconExporter };
652
- //# sourceMappingURL=NiceDesktopIconExporter.js.map
@@ -423,4 +423,3 @@ const styles = {
423
423
  };
424
424
 
425
425
  export { NiceFaviconGenerator, useFaviconGenerator };
426
- //# sourceMappingURL=NiceFaviconGenerator.js.map
@@ -452,4 +452,3 @@ const styles = {
452
452
  };
453
453
 
454
454
  export { NiceIconEditor, useIconEditor };
455
- //# sourceMappingURL=NiceIconEditor.js.map
@@ -407,4 +407,3 @@ const NiceIconPicker = forwardRef(function NiceIconPicker({ icons, value = null,
407
407
  });
408
408
 
409
409
  export { NiceIconPicker };
410
- //# sourceMappingURL=NiceIconPicker.js.map
@@ -193,4 +193,3 @@ const styles = {
193
193
  };
194
194
 
195
195
  export { NiceIconPreview };
196
- //# sourceMappingURL=NiceIconPreview.js.map
@@ -562,4 +562,3 @@ const styles = {
562
562
  };
563
563
 
564
564
  export { NiceIconSetCreator, useIconSetCreator };
565
- //# sourceMappingURL=NiceIconSetCreator.js.map