@nice2dev/icons 1.3.14 → 1.3.16
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 +15 -0
- package/dist/cjs/NiceDesktopIconExporter.js +688 -599
- package/dist/cjs/NiceFaviconGenerator.js +603 -417
- package/dist/cjs/NiceIconPicker.js +788 -508
- package/dist/cjs/NiceIconPreview.js +246 -188
- package/dist/cjs/NiceIconSetCreator.js +683 -552
- package/dist/cjs/NiceIconStacker.js +547 -171
- package/dist/cjs/NiceIconValue.js +27 -35
- package/dist/cjs/NtdIconBadge.js +384 -360
- package/dist/cjs/NtdIconMorph.js +419 -354
- package/dist/cjs/NtdStateMorph.js +150 -147
- package/dist/cjs/advancedIconSearch.js +373 -510
- package/dist/cjs/animationControls.js +518 -642
- package/dist/cjs/client.js +12 -15
- package/dist/cjs/createIcon.js +349 -251
- package/dist/cjs/design-tokens.js +324 -390
- package/dist/cjs/figmaExport.js +162 -257
- package/dist/cjs/figmaSync.js +234 -316
- package/dist/cjs/headless-ui.js +240 -368
- package/dist/cjs/iconAnalytics.js +337 -393
- package/dist/cjs/iconHtml.js +64 -86
- package/dist/cjs/iconMetadata.js +392 -472
- package/dist/cjs/iconParts.js +120 -90
- package/dist/cjs/iconStack.js +136 -155
- package/dist/cjs/iconStyles.js +1609 -504
- package/dist/cjs/iconValue.js +359 -430
- package/dist/cjs/icons/accessibility.js +1119 -134
- package/dist/cjs/icons/actions.js +1290 -330
- package/dist/cjs/icons/ai.js +1424 -144
- package/dist/cjs/icons/brand.js +1344 -172
- package/dist/cjs/icons/business.js +903 -193
- package/dist/cjs/icons/devtech.js +1656 -227
- package/dist/cjs/icons/ecommerce.js +802 -111
- package/dist/cjs/icons/education.js +1345 -199
- package/dist/cjs/icons/files.js +1597 -328
- package/dist/cjs/icons/fintech.js +793 -104
- package/dist/cjs/icons/food.js +1507 -153
- package/dist/cjs/icons/fun.js +786 -109
- package/dist/cjs/icons/gaming.js +916 -170
- package/dist/cjs/icons/health.js +623 -112
- package/dist/cjs/icons/index.js +34 -35
- package/dist/cjs/icons/input.js +282 -83
- package/dist/cjs/icons/legal.js +1065 -122
- package/dist/cjs/icons/media.js +1061 -267
- package/dist/cjs/icons/navigation.js +387 -122
- package/dist/cjs/icons/omniverk.js +747 -90
- package/dist/cjs/icons/realestate.js +1520 -193
- package/dist/cjs/icons/saas.js +867 -98
- package/dist/cjs/icons/science.js +1465 -165
- package/dist/cjs/icons/shapes.js +1316 -308
- package/dist/cjs/icons/smarthome.js +786 -90
- package/dist/cjs/icons/social.js +591 -59
- package/dist/cjs/icons/sports.js +1225 -133
- package/dist/cjs/icons/sustainability.js +1211 -139
- package/dist/cjs/icons/travel.js +1470 -148
- package/dist/cjs/icons/ui.js +1508 -315
- package/dist/cjs/icons/weather.js +1160 -173
- package/dist/cjs/index.js +566 -566
- package/dist/cjs/lottieIntegration.js +261 -266
- package/dist/cjs/nicetodev-icons.css +1 -1
- package/dist/cjs/particleEffects.js +270 -251
- package/dist/cjs/resolver.js +229 -284
- package/dist/cjs/rsc.js +175 -193
- package/dist/cjs/sharpen.js +73 -130
- package/dist/cjs/smilAnimations.js +371 -165
- package/dist/cjs/stacking.js +87 -122
- package/dist/cjs/tailwind-plugin.js +280 -320
- package/dist/cjs/types.js +46 -72
- package/dist/cjs/utilities.js +163 -324
- package/dist/cjs/variantProps.js +12 -52
- package/dist/esm/NiceDesktopIconExporter.js +671 -598
- package/dist/esm/NiceFaviconGenerator.js +583 -416
- package/dist/esm/NiceIconPicker.js +789 -507
- package/dist/esm/NiceIconPreview.js +247 -187
- package/dist/esm/NiceIconSetCreator.js +685 -551
- package/dist/esm/NiceIconStacker.js +549 -170
- package/dist/esm/NiceIconValue.js +29 -34
- package/dist/esm/NtdIconBadge.js +388 -359
- package/dist/esm/NtdIconMorph.js +423 -353
- package/dist/esm/NtdStateMorph.js +152 -146
- package/dist/esm/advancedIconSearch.js +391 -509
- package/dist/esm/animationControls.js +527 -641
- package/dist/esm/client.js +48 -10
- package/dist/esm/createIcon.js +350 -250
- package/dist/esm/design-tokens.js +334 -387
- package/dist/esm/figmaExport.js +170 -256
- package/dist/esm/figmaSync.js +237 -315
- package/dist/esm/headless-ui.js +254 -365
- package/dist/esm/iconAnalytics.js +342 -392
- package/dist/esm/iconHtml.js +67 -85
- package/dist/esm/iconMetadata.js +404 -471
- package/dist/esm/iconParts.js +125 -89
- package/dist/esm/iconStack.js +145 -154
- package/dist/esm/iconStyles.js +1620 -503
- package/dist/esm/iconValue.js +361 -429
- package/dist/esm/icons/accessibility.js +1133 -133
- package/dist/esm/icons/actions.js +1320 -329
- package/dist/esm/icons/ai.js +1441 -143
- package/dist/esm/icons/brand.js +1351 -171
- package/dist/esm/icons/business.js +931 -201
- package/dist/esm/icons/devtech.js +1687 -226
- package/dist/esm/icons/ecommerce.js +816 -110
- package/dist/esm/icons/education.js +1364 -198
- package/dist/esm/icons/files.js +1628 -327
- package/dist/esm/icons/fintech.js +807 -103
- package/dist/esm/icons/food.js +1524 -152
- package/dist/esm/icons/fun.js +801 -108
- package/dist/esm/icons/gaming.js +933 -169
- package/dist/esm/icons/health.js +636 -111
- package/dist/esm/icons/index.js +596 -32
- package/dist/esm/icons/input.js +326 -82
- package/dist/esm/icons/legal.js +1079 -121
- package/dist/esm/icons/media.js +1086 -266
- package/dist/esm/icons/navigation.js +401 -121
- package/dist/esm/icons/omniverk.js +759 -89
- package/dist/esm/icons/realestate.js +1544 -198
- package/dist/esm/icons/saas.js +880 -97
- package/dist/esm/icons/science.js +1482 -164
- package/dist/esm/icons/shapes.js +1343 -307
- package/dist/esm/icons/smarthome.js +799 -89
- package/dist/esm/icons/social.js +599 -58
- package/dist/esm/icons/sports.js +1240 -132
- package/dist/esm/icons/sustainability.js +1226 -138
- package/dist/esm/icons/travel.js +1486 -147
- package/dist/esm/icons/ui.js +1540 -314
- package/dist/esm/icons/weather.js +1181 -172
- package/dist/esm/index.js +756 -58
- package/dist/esm/lottieIntegration.js +264 -265
- package/dist/esm/nicetodev-icons.css +1 -1
- package/dist/esm/particleEffects.js +271 -250
- package/dist/esm/resolver.js +231 -283
- package/dist/esm/rsc.js +182 -192
- package/dist/esm/sharpen.js +78 -129
- package/dist/esm/smilAnimations.js +376 -164
- package/dist/esm/stacking.js +99 -121
- package/dist/esm/tailwind-plugin.js +282 -319
- package/dist/esm/types.js +50 -71
- package/dist/esm/utilities.js +177 -321
- package/dist/esm/variantProps.js +23 -52
- package/dist/types/icons/index.d.ts +1 -1
- package/dist/types/icons/science.d.ts +9 -0
- package/package.json +15 -22
package/dist/esm/types.js
CHANGED
|
@@ -1,79 +1,58 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default colors for semantic color variants.
|
|
3
|
-
* These are used when CSS variables are not defined.
|
|
4
|
-
*/
|
|
5
1
|
const SEMANTIC_COLOR_DEFAULTS = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
success: "#22c55e",
|
|
3
|
+
// Green 500
|
|
4
|
+
warning: "#f59e0b",
|
|
5
|
+
// Amber 500
|
|
6
|
+
error: "#ef4444",
|
|
7
|
+
// Red 500
|
|
8
|
+
info: "#3b82f6",
|
|
9
|
+
// Blue 500
|
|
10
|
+
muted: "#6b7280",
|
|
11
|
+
// Gray 500
|
|
12
|
+
primary: "#6366f1",
|
|
13
|
+
// Indigo 500
|
|
14
|
+
secondary: "#8b5cf6",
|
|
15
|
+
// Violet 500
|
|
16
|
+
accent: "#ec4899"
|
|
17
|
+
// Pink 500
|
|
14
18
|
};
|
|
15
|
-
/**
|
|
16
|
-
* CSS variable names for semantic colors.
|
|
17
|
-
* Define these in your CSS to customize icon colors globally.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```css
|
|
21
|
-
* :root {
|
|
22
|
-
* --ntd-icon-success: #10b981;
|
|
23
|
-
* --ntd-icon-error: #dc2626;
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
19
|
const SEMANTIC_COLOR_VARS = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
success: "--ntd-icon-success",
|
|
21
|
+
warning: "--ntd-icon-warning",
|
|
22
|
+
error: "--ntd-icon-error",
|
|
23
|
+
info: "--ntd-icon-info",
|
|
24
|
+
muted: "--ntd-icon-muted",
|
|
25
|
+
primary: "--ntd-icon-primary",
|
|
26
|
+
secondary: "--ntd-icon-secondary",
|
|
27
|
+
accent: "--ntd-icon-accent"
|
|
36
28
|
};
|
|
37
|
-
/** Gradient preset color stops. */
|
|
38
29
|
const GRADIENT_PRESETS = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
sunset: ["#ff6b6b", "#feca57", "#ff9ff3"],
|
|
31
|
+
ocean: ["#0652DD", "#1B9CFC", "#38ada9"],
|
|
32
|
+
forest: ["#0a3d0a", "#1e8449", "#58D68D"],
|
|
33
|
+
fire: ["#e74c3c", "#f39c12", "#f1c40f"],
|
|
34
|
+
ice: ["#74b9ff", "#a29bfe", "#dfe6e9"],
|
|
35
|
+
neon: ["#6c5ce7", "#fd79a8", "#00cec9"],
|
|
36
|
+
gold: ["#f9ca24", "#f0932b", "#e17055"],
|
|
37
|
+
"purple-haze": ["#6c5ce7", "#a55eea", "#e056a0"],
|
|
38
|
+
aurora: ["#00b894", "#00cec9", "#0984e3", "#6c5ce7"],
|
|
39
|
+
midnight: ["#0c0c1d", "#1e3a5f", "#2c3e50"],
|
|
40
|
+
candy: ["#ff6b81", "#ffa502", "#2ed573"],
|
|
41
|
+
steel: ["#636e72", "#b2bec3", "#dfe6e9"]
|
|
51
42
|
};
|
|
52
|
-
/**
|
|
53
|
-
* Map of named size presets to their pixel values.
|
|
54
|
-
*
|
|
55
|
-
* Used internally by {@link createIcon} to resolve `IconSize` strings to numbers.
|
|
56
|
-
*
|
|
57
|
-
* | Key | Value |
|
|
58
|
-
* |--------|-------|
|
|
59
|
-
* | `xs` | 12 |
|
|
60
|
-
* | `sm` | 16 |
|
|
61
|
-
* | `md` | 24 |
|
|
62
|
-
* | `lg` | 32 |
|
|
63
|
-
* | `xl` | 48 |
|
|
64
|
-
* | `2xl` | 64 |
|
|
65
|
-
* | `xxl` | 96 |
|
|
66
|
-
* | `xxxl` | 128 |
|
|
67
|
-
*/
|
|
68
43
|
const SIZE_MAP = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
44
|
+
xs: 12,
|
|
45
|
+
sm: 16,
|
|
46
|
+
md: 24,
|
|
47
|
+
lg: 32,
|
|
48
|
+
xl: 48,
|
|
49
|
+
"2xl": 64,
|
|
50
|
+
xxl: 96,
|
|
51
|
+
xxxl: 128
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
GRADIENT_PRESETS,
|
|
55
|
+
SEMANTIC_COLOR_DEFAULTS,
|
|
56
|
+
SEMANTIC_COLOR_VARS,
|
|
57
|
+
SIZE_MAP
|
|
77
58
|
};
|
|
78
|
-
|
|
79
|
-
export { GRADIENT_PRESETS, SEMANTIC_COLOR_DEFAULTS, SEMANTIC_COLOR_VARS, SIZE_MAP };
|
package/dist/esm/utilities.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState, useCallback, createElement, useSyncExternalStore } from
|
|
2
|
-
|
|
1
|
+
import { useEffect, useState, useCallback, createElement, useSyncExternalStore } from "react";
|
|
3
2
|
/**
|
|
4
3
|
* @file utilities.ts
|
|
5
4
|
* @description Utility hooks and functions for @nice2dev/icons
|
|
@@ -28,359 +27,216 @@ import { useEffect, useState, useCallback, createElement, useSyncExternalStore }
|
|
|
28
27
|
* @since 2026-03
|
|
29
28
|
* @license MIT
|
|
30
29
|
*/
|
|
31
|
-
/*
|
|
32
|
-
ICON REGISTRY
|
|
33
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
34
|
-
/**
|
|
35
|
-
* Global icon cache for dynamic loading
|
|
36
|
-
*/
|
|
37
|
-
const iconRegistry = new Map();
|
|
38
|
-
/**
|
|
39
|
-
* Registers an icon in the global registry
|
|
40
|
-
*/
|
|
30
|
+
const iconRegistry = /* @__PURE__ */ new Map();
|
|
41
31
|
function registerIcon(name, component) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
iconRegistry.set(name, {
|
|
33
|
+
component,
|
|
34
|
+
loadedAt: Date.now()
|
|
35
|
+
});
|
|
46
36
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Gets an icon from the registry
|
|
49
|
-
*/
|
|
50
37
|
function getIconFromRegistry(name) {
|
|
51
|
-
|
|
52
|
-
return (_a = iconRegistry.get(name)) === null || _a === void 0 ? void 0 : _a.component;
|
|
38
|
+
return iconRegistry.get(name)?.component;
|
|
53
39
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Clears the icon registry
|
|
56
|
-
*/
|
|
57
40
|
function clearIconRegistry() {
|
|
58
|
-
|
|
41
|
+
iconRegistry.clear();
|
|
59
42
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Gets all registered icon names
|
|
62
|
-
*/
|
|
63
43
|
function getRegisteredIconNames() {
|
|
64
|
-
|
|
44
|
+
return Array.from(iconRegistry.keys());
|
|
65
45
|
}
|
|
66
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
67
|
-
USE ICON HOOK
|
|
68
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
69
|
-
/**
|
|
70
|
-
* Hook for dynamically loading icons by name.
|
|
71
|
-
*
|
|
72
|
-
* @param iconName - Name of the icon to load (e.g., 'NtdHome')
|
|
73
|
-
* @param options - Loading options
|
|
74
|
-
* @returns Icon component, loading state, and error
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* ```tsx
|
|
78
|
-
* function DynamicIcon({ name }: { name: string }) {
|
|
79
|
-
* const { Icon, isLoading, error } = useIcon(name);
|
|
80
|
-
*
|
|
81
|
-
* if (isLoading) return <Spinner />;
|
|
82
|
-
* if (error || !Icon) return <FallbackIcon />;
|
|
83
|
-
*
|
|
84
|
-
* return <Icon size="md" />;
|
|
85
|
-
* }
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
46
|
function useIcon(iconName, options = {}) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
47
|
+
const { fallback, cache = true } = options;
|
|
48
|
+
const [state, setState] = useState({
|
|
49
|
+
Icon: iconName ? getIconFromRegistry(iconName) || null : null,
|
|
50
|
+
isLoading: false,
|
|
51
|
+
error: null
|
|
52
|
+
});
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!iconName) {
|
|
55
|
+
setState({ Icon: null, isLoading: false, error: null });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const cached = getIconFromRegistry(iconName);
|
|
59
|
+
if (cached) {
|
|
60
|
+
setState({ Icon: cached, isLoading: false, error: null });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
64
|
+
const loadIcon = async () => {
|
|
65
|
+
try {
|
|
66
|
+
const module = await import("./icons/index.js");
|
|
67
|
+
const IconComponent = module[iconName];
|
|
68
|
+
if (IconComponent) {
|
|
69
|
+
if (cache) {
|
|
70
|
+
registerIcon(iconName, IconComponent);
|
|
71
|
+
}
|
|
72
|
+
setState({ Icon: IconComponent, isLoading: false, error: null });
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error(`Icon "${iconName}" not found`);
|
|
105
75
|
}
|
|
106
|
-
|
|
107
|
-
setState(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
setState({ Icon: IconComponent, isLoading: false, error: null });
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
throw new Error(`Icon "${iconName}" not found`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
setState({
|
|
126
|
-
Icon: fallback || null,
|
|
127
|
-
isLoading: false,
|
|
128
|
-
error: err instanceof Error ? err : new Error('Failed to load icon'),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
loadIcon();
|
|
133
|
-
}, [iconName, cache, fallback]);
|
|
134
|
-
return state;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
setState({
|
|
78
|
+
Icon: fallback || null,
|
|
79
|
+
isLoading: false,
|
|
80
|
+
error: err instanceof Error ? err : new Error("Failed to load icon")
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
loadIcon();
|
|
85
|
+
}, [iconName, cache, fallback]);
|
|
86
|
+
return state;
|
|
135
87
|
}
|
|
136
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
137
|
-
USE REDUCED MOTION
|
|
138
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
139
|
-
/**
|
|
140
|
-
* Subscribes to prefers-reduced-motion media query.
|
|
141
|
-
*/
|
|
142
88
|
function subscribeToReducedMotion(callback) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
89
|
+
if (typeof window === "undefined") {
|
|
90
|
+
return () => {
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
94
|
+
const handler = () => callback();
|
|
95
|
+
mediaQuery.addEventListener("change", handler);
|
|
96
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
150
97
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Gets current reduced motion preference.
|
|
153
|
-
*/
|
|
154
98
|
function getReducedMotionSnapshot() {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
99
|
+
if (typeof window === "undefined") {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
159
103
|
}
|
|
160
|
-
/**
|
|
161
|
-
* Server snapshot for SSR (assumes no reduced motion preference).
|
|
162
|
-
*/
|
|
163
104
|
function getReducedMotionServerSnapshot() {
|
|
164
|
-
|
|
105
|
+
return false;
|
|
165
106
|
}
|
|
166
|
-
/**
|
|
167
|
-
* Hook that returns true if user prefers reduced motion.
|
|
168
|
-
* Uses useSyncExternalStore for SSR compatibility.
|
|
169
|
-
*
|
|
170
|
-
* @returns Whether the user prefers reduced motion
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* ```tsx
|
|
174
|
-
* function AnimatedIcon() {
|
|
175
|
-
* const prefersReducedMotion = useReducedMotion();
|
|
176
|
-
*
|
|
177
|
-
* return (
|
|
178
|
-
* <NtdHeart
|
|
179
|
-
* animation={prefersReducedMotion ? undefined : 'pulse'}
|
|
180
|
-
* />
|
|
181
|
-
* );
|
|
182
|
-
* }
|
|
183
|
-
* ```
|
|
184
|
-
*/
|
|
185
107
|
function useReducedMotion() {
|
|
186
|
-
|
|
108
|
+
return useSyncExternalStore(
|
|
109
|
+
subscribeToReducedMotion,
|
|
110
|
+
getReducedMotionSnapshot,
|
|
111
|
+
getReducedMotionServerSnapshot
|
|
112
|
+
);
|
|
187
113
|
}
|
|
188
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
189
|
-
PRELOAD ICONS
|
|
190
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
191
|
-
/**
|
|
192
|
-
* Preloads icons into the registry for instant access.
|
|
193
|
-
*
|
|
194
|
-
* @param iconNames - Array of icon names to preload
|
|
195
|
-
* @returns Promise that resolves when all icons are loaded
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```tsx
|
|
199
|
-
* // Preload critical icons at app startup
|
|
200
|
-
* useEffect(() => {
|
|
201
|
-
* preloadIcons(['NtdHome', 'NtdSearch', 'NtdUser', 'NtdMenu']);
|
|
202
|
-
* }, []);
|
|
203
|
-
* ```
|
|
204
|
-
*/
|
|
205
114
|
async function preloadIcons(iconNames) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
115
|
+
const results = /* @__PURE__ */ new Map();
|
|
116
|
+
try {
|
|
117
|
+
const module = await import("./icons/index.js");
|
|
118
|
+
for (const name of iconNames) {
|
|
119
|
+
const IconComponent = module[name];
|
|
120
|
+
if (IconComponent) {
|
|
121
|
+
registerIcon(name, IconComponent);
|
|
122
|
+
results.set(name, IconComponent);
|
|
123
|
+
}
|
|
216
124
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn("Failed to preload icons:", error);
|
|
127
|
+
}
|
|
128
|
+
return results;
|
|
221
129
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Creates a preloader component that preloads icons on mount.
|
|
224
|
-
*
|
|
225
|
-
* @param iconNames - Icons to preload
|
|
226
|
-
* @returns React component that preloads icons
|
|
227
|
-
*
|
|
228
|
-
* @example
|
|
229
|
-
* ```tsx
|
|
230
|
-
* const IconPreloader = createIconPreloader(['NtdHome', 'NtdSearch']);
|
|
231
|
-
*
|
|
232
|
-
* function App() {
|
|
233
|
-
* return (
|
|
234
|
-
* <>
|
|
235
|
-
* <IconPreloader />
|
|
236
|
-
* <MainContent />
|
|
237
|
-
* </>
|
|
238
|
-
* );
|
|
239
|
-
* }
|
|
240
|
-
* ```
|
|
241
|
-
*/
|
|
242
130
|
function createIconPreloader(iconNames) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
131
|
+
return function IconPreloader() {
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
preloadIcons(iconNames);
|
|
134
|
+
}, []);
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
249
137
|
}
|
|
250
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
251
|
-
ICON PROPS HELPERS
|
|
252
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
253
|
-
/**
|
|
254
|
-
* Creates props with animation disabled if user prefers reduced motion.
|
|
255
|
-
*
|
|
256
|
-
* @param props - Original icon props
|
|
257
|
-
* @param prefersReducedMotion - Whether user prefers reduced motion
|
|
258
|
-
* @returns Props with animation conditionally disabled
|
|
259
|
-
*/
|
|
260
138
|
function withReducedMotionProps(props, prefersReducedMotion) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
139
|
+
if (!prefersReducedMotion) {
|
|
140
|
+
return props;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
...props,
|
|
144
|
+
animation: void 0,
|
|
145
|
+
animationDuration: void 0,
|
|
146
|
+
gradientAnimation: void 0
|
|
147
|
+
};
|
|
270
148
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Creates accessible icon props based on context.
|
|
273
|
-
*
|
|
274
|
-
* @param options - Accessibility options
|
|
275
|
-
* @returns Icon props for accessibility
|
|
276
|
-
*/
|
|
277
149
|
function createAccessibleIconProps(options) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
'aria-hidden': true,
|
|
282
|
-
role: 'presentation',
|
|
283
|
-
};
|
|
284
|
-
}
|
|
150
|
+
const { label, isDecorative = !label, role } = options;
|
|
151
|
+
if (isDecorative) {
|
|
285
152
|
return {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
title: label,
|
|
153
|
+
"aria-hidden": true,
|
|
154
|
+
role: "presentation"
|
|
289
155
|
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
"aria-label": label,
|
|
159
|
+
role: role || "img",
|
|
160
|
+
title: label
|
|
161
|
+
};
|
|
290
162
|
}
|
|
291
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
292
|
-
ICON TYPE GUARDS
|
|
293
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
294
|
-
/**
|
|
295
|
-
* Checks if a value is a valid icon component.
|
|
296
|
-
* Handles both regular components and forwardRef components.
|
|
297
|
-
*/
|
|
298
163
|
function isIconComponent(value) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return typeof displayName === 'string' && displayName.startsWith('Ntd');
|
|
164
|
+
if (value == null) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const isValidComponent = typeof value === "function" || typeof value === "object" && "$$typeof" in value;
|
|
168
|
+
if (!isValidComponent) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const displayName = value.displayName;
|
|
172
|
+
return typeof displayName === "string" && displayName.startsWith("Ntd");
|
|
309
173
|
}
|
|
310
|
-
/**
|
|
311
|
-
* Checks if an icon name is valid.
|
|
312
|
-
*/
|
|
313
174
|
function isValidIconName(name) {
|
|
314
|
-
|
|
175
|
+
return /^Ntd[A-Z][a-zA-Z0-9]*$/.test(name);
|
|
315
176
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Creates a function that renders multiple icons efficiently.
|
|
318
|
-
*
|
|
319
|
-
* @param configs - Array of icon configurations
|
|
320
|
-
* @returns Function that renders all configured icons
|
|
321
|
-
*
|
|
322
|
-
* @example
|
|
323
|
-
* ```tsx
|
|
324
|
-
* const renderNavIcons = createBatchIconRenderer([
|
|
325
|
-
* { name: 'NtdHome', props: { size: 'md' } },
|
|
326
|
-
* { name: 'NtdSearch', props: { size: 'md' } },
|
|
327
|
-
* { name: 'NtdUser', props: { size: 'md' } },
|
|
328
|
-
* ]);
|
|
329
|
-
*
|
|
330
|
-
* // In component
|
|
331
|
-
* const icons = renderNavIcons();
|
|
332
|
-
* ```
|
|
333
|
-
*/
|
|
334
177
|
function useBatchIcons(configs) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
setIsLoading(false);
|
|
346
|
-
};
|
|
347
|
-
loadIcons();
|
|
348
|
-
}, [namesKey]);
|
|
349
|
-
const renderIcon = useCallback((name, additionalProps) => {
|
|
350
|
-
const Icon = icons.get(name);
|
|
351
|
-
const config = configs.find((c) => c.name === name);
|
|
352
|
-
if (!Icon) {
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
const mergedProps = {
|
|
356
|
-
...config === null || config === void 0 ? void 0 : config.props,
|
|
357
|
-
...additionalProps,
|
|
358
|
-
};
|
|
359
|
-
return createElement(Icon, mergedProps);
|
|
360
|
-
}, [icons, configs]);
|
|
361
|
-
return {
|
|
362
|
-
renderIcon,
|
|
363
|
-
isLoading,
|
|
364
|
-
icons,
|
|
178
|
+
const [icons, setIcons] = useState(/* @__PURE__ */ new Map());
|
|
179
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
180
|
+
const namesKey = configs.map((c) => c.name).join(",");
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
const loadIcons = async () => {
|
|
183
|
+
setIsLoading(true);
|
|
184
|
+
const names = namesKey ? namesKey.split(",") : [];
|
|
185
|
+
const loadedIcons = await preloadIcons(names);
|
|
186
|
+
setIcons(loadedIcons);
|
|
187
|
+
setIsLoading(false);
|
|
365
188
|
};
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
189
|
+
loadIcons();
|
|
190
|
+
}, [namesKey]);
|
|
191
|
+
const renderIcon = useCallback(
|
|
192
|
+
(name, additionalProps) => {
|
|
193
|
+
const Icon = icons.get(name);
|
|
194
|
+
const config = configs.find((c) => c.name === name);
|
|
195
|
+
if (!Icon) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
const mergedProps = {
|
|
199
|
+
...config?.props,
|
|
200
|
+
...additionalProps
|
|
201
|
+
};
|
|
202
|
+
return createElement(Icon, mergedProps);
|
|
203
|
+
},
|
|
204
|
+
[icons, configs]
|
|
205
|
+
);
|
|
206
|
+
return {
|
|
207
|
+
renderIcon,
|
|
208
|
+
isLoading,
|
|
209
|
+
icons
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const utilities = {
|
|
213
|
+
useIcon,
|
|
214
|
+
useReducedMotion,
|
|
215
|
+
preloadIcons,
|
|
216
|
+
createIconPreloader,
|
|
217
|
+
registerIcon,
|
|
218
|
+
getIconFromRegistry,
|
|
219
|
+
clearIconRegistry,
|
|
220
|
+
getRegisteredIconNames,
|
|
221
|
+
withReducedMotionProps,
|
|
222
|
+
createAccessibleIconProps,
|
|
223
|
+
isIconComponent,
|
|
224
|
+
isValidIconName,
|
|
225
|
+
useBatchIcons
|
|
226
|
+
};
|
|
227
|
+
export {
|
|
228
|
+
clearIconRegistry,
|
|
229
|
+
createAccessibleIconProps,
|
|
230
|
+
createIconPreloader,
|
|
231
|
+
utilities as default,
|
|
232
|
+
getIconFromRegistry,
|
|
233
|
+
getRegisteredIconNames,
|
|
234
|
+
isIconComponent,
|
|
235
|
+
isValidIconName,
|
|
236
|
+
preloadIcons,
|
|
237
|
+
registerIcon,
|
|
238
|
+
useBatchIcons,
|
|
239
|
+
useIcon,
|
|
240
|
+
useReducedMotion,
|
|
241
|
+
withReducedMotionProps
|
|
384
242
|
};
|
|
385
|
-
|
|
386
|
-
export { clearIconRegistry, createAccessibleIconProps, createIconPreloader, utilities as default, getIconFromRegistry, getRegisteredIconNames, isIconComponent, isValidIconName, preloadIcons, registerIcon, useBatchIcons, useIcon, useReducedMotion, withReducedMotionProps };
|