@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/rsc.js
CHANGED
|
@@ -1,201 +1,191 @@
|
|
|
1
|
-
import { jsx, jsxs } from
|
|
2
|
-
import { sharpenTree, roundTree, wireTree, MINI_SCALE } from
|
|
3
|
-
import { SIZE_MAP, SEMANTIC_COLOR_DEFAULTS, GRADIENT_PRESETS } from
|
|
4
|
-
|
|
5
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
6
|
-
RSC-COMPATIBLE ICON FACTORY
|
|
7
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
8
|
-
/**
|
|
9
|
-
* Creates a React Server Component compatible icon.
|
|
10
|
-
*
|
|
11
|
-
* Unlike the standard `createIcon`, this version:
|
|
12
|
-
* - Does NOT use React hooks (useId, useSyncExternalStore, etc.)
|
|
13
|
-
* - Does NOT support animations
|
|
14
|
-
* - Does NOT support automatic dark/light mode detection
|
|
15
|
-
* - IS fully streamable and SSR-safe
|
|
16
|
-
*
|
|
17
|
-
* @param options - Icon configuration
|
|
18
|
-
* @returns A React function component (not using forwardRef)
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```tsx
|
|
22
|
-
* export const NtdHomeRSC = createIconRSC({
|
|
23
|
-
* displayName: 'NtdHomeRSC',
|
|
24
|
-
* paths: {
|
|
25
|
-
* solid: ({ primaryColor }) => <path d="..." fill={primaryColor} />,
|
|
26
|
-
* outline: ({ primaryColor, strokeWidth }) => <path d="..." stroke={primaryColor} />,
|
|
27
|
-
* duotone: ({ primaryColor, secondaryColor }) => <path d="..." />,
|
|
28
|
-
* },
|
|
29
|
-
* });
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { sharpenTree, roundTree, wireTree, MINI_SCALE } from "./sharpen.js";
|
|
3
|
+
import { SIZE_MAP, SEMANTIC_COLOR_DEFAULTS, GRADIENT_PRESETS } from "./types.js";
|
|
32
4
|
function createIconRSC(options) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
if (flipY) {
|
|
69
|
-
transforms.push('scaleY(-1)');
|
|
70
|
-
}
|
|
71
|
-
if (scale && scale !== 1) {
|
|
72
|
-
transforms.push(`scale(${scale})`);
|
|
73
|
-
}
|
|
74
|
-
// Build gradient defs if needed
|
|
75
|
-
let gradientDefs = null;
|
|
76
|
-
let gradientId = null;
|
|
77
|
-
if (gradient && GRADIENT_PRESETS[gradient]) {
|
|
78
|
-
const colors = GRADIENT_PRESETS[gradient];
|
|
79
|
-
// Generate a deterministic ID based on displayName and gradient
|
|
80
|
-
gradientId = `${displayName}-${gradient}-grad`;
|
|
81
|
-
const x1 = Math.round(50 - 50 * Math.cos((gradientDirection * Math.PI) / 180));
|
|
82
|
-
const y1 = Math.round(50 - 50 * Math.sin((gradientDirection * Math.PI) / 180));
|
|
83
|
-
const x2 = Math.round(50 + 50 * Math.cos((gradientDirection * Math.PI) / 180));
|
|
84
|
-
const y2 = Math.round(50 + 50 * Math.sin((gradientDirection * Math.PI) / 180));
|
|
85
|
-
gradientDefs = (jsx("defs", { children: jsx("linearGradient", { id: gradientId, x1: `${x1}%`, y1: `${y1}%`, x2: `${x2}%`, y2: `${y2}%`, children: colors.map((color, i) => (jsx("stop", { offset: `${(i / (colors.length - 1)) * 100}%`, stopColor: color }, i))) }) }));
|
|
86
|
-
// Override primary color with gradient reference
|
|
87
|
-
renderProps.primaryColor = `url(#${gradientId})`;
|
|
88
|
-
}
|
|
89
|
-
// Final styles
|
|
90
|
-
const finalStyle = {
|
|
91
|
-
width: resolvedSize,
|
|
92
|
-
height: resolvedSize,
|
|
93
|
-
...style,
|
|
94
|
-
...(transforms.length > 0 && { transform: transforms.join(' ') }),
|
|
95
|
-
};
|
|
96
|
-
// Cutout mask ID (deterministic for SSR)
|
|
97
|
-
const cutoutMaskId = isCutout ? `${displayName}-cutout-mask` : null;
|
|
98
|
-
// Cutout shape renderer
|
|
99
|
-
const cutoutBg = isCutout
|
|
100
|
-
? (() => {
|
|
101
|
-
const fill = renderProps.primaryColor !== 'currentColor'
|
|
102
|
-
? renderProps.secondaryColor
|
|
103
|
-
: renderProps.primaryColor;
|
|
104
|
-
const mask = `url(#${cutoutMaskId})`;
|
|
105
|
-
switch (cutoutShape) {
|
|
106
|
-
case 'circle':
|
|
107
|
-
return jsx("circle", { cx: "12", cy: "12", r: "11", fill: fill, mask: mask });
|
|
108
|
-
case 'square':
|
|
109
|
-
return jsx("rect", { x: "1", y: "1", width: "22", height: "22", fill: fill, mask: mask });
|
|
110
|
-
case 'hexagon':
|
|
111
|
-
return (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 }));
|
|
112
|
-
case 'diamond':
|
|
113
|
-
return jsx("polygon", { points: "12,1 23,12 12,23 1,12", fill: fill, mask: mask });
|
|
114
|
-
case 'shield':
|
|
115
|
-
return (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 }));
|
|
116
|
-
case 'squircle':
|
|
117
|
-
return (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 }));
|
|
118
|
-
default:
|
|
119
|
-
return jsx("rect", { x: "1", y: "1", width: "22", height: "22", rx: "4", fill: fill, mask: mask });
|
|
120
|
-
}
|
|
121
|
-
})()
|
|
122
|
-
: null;
|
|
123
|
-
// Mirrors the client renderer in createIcon.tsx: `sharp` / `rounded` /
|
|
124
|
-
// `wireframe` / `mini` all reuse `paths.solid`, so each needs its own pass
|
|
125
|
-
// to be distinguishable.
|
|
126
|
-
const rendered = isCutout
|
|
127
|
-
? cutoutBg
|
|
128
|
-
: variant === 'sharp'
|
|
129
|
-
? sharpenTree(pathRenderer(renderProps))
|
|
130
|
-
: variant === 'rounded'
|
|
131
|
-
? roundTree(pathRenderer(renderProps))
|
|
132
|
-
: variant === 'wireframe'
|
|
133
|
-
? wireTree(pathRenderer(renderProps), renderProps.primaryColor)
|
|
134
|
-
: pathRenderer(renderProps);
|
|
135
|
-
const iconContent = variant === 'mini' ? (jsx("g", { transform: `translate(12 12) scale(${MINI_SCALE}) translate(-12 -12)`, children: rendered })) : (rendered);
|
|
136
|
-
return (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 && jsx("title", { children: title }), gradientDefs, isCutout && (jsx("defs", { children: jsxs("mask", { id: cutoutMaskId, children: [jsx("rect", { x: "0", y: "0", width: "24", height: "24", fill: "white" }), jsx("g", { transform: "translate(12,12) scale(0.8) translate(-12,-12)", children: paths.solid({
|
|
137
|
-
...renderProps,
|
|
138
|
-
primaryColor: 'black',
|
|
139
|
-
secondaryColor: 'black',
|
|
140
|
-
accentColor: 'white',
|
|
141
|
-
}) })] }) })), iconContent] }));
|
|
5
|
+
const { displayName, viewBox = "0 0 24 24", paths } = options;
|
|
6
|
+
function IconRSC(props) {
|
|
7
|
+
const {
|
|
8
|
+
size = "md",
|
|
9
|
+
variant = "solid",
|
|
10
|
+
cutoutShape = "rounded-square",
|
|
11
|
+
primaryColor: primaryColorProp,
|
|
12
|
+
secondaryColor: secondaryColorProp,
|
|
13
|
+
accentColor: accentColorProp,
|
|
14
|
+
secondaryOpacity = 0.35,
|
|
15
|
+
strokeWidth = 1,
|
|
16
|
+
gradient,
|
|
17
|
+
gradientDirection = 135,
|
|
18
|
+
color,
|
|
19
|
+
rotate,
|
|
20
|
+
flipX,
|
|
21
|
+
flipY,
|
|
22
|
+
scale,
|
|
23
|
+
className,
|
|
24
|
+
style,
|
|
25
|
+
"aria-label": ariaLabel,
|
|
26
|
+
"aria-hidden": ariaHidden,
|
|
27
|
+
title,
|
|
28
|
+
role = ariaLabel ? "img" : "presentation",
|
|
29
|
+
"data-testid": testId
|
|
30
|
+
} = props;
|
|
31
|
+
const resolvedSize = typeof size === "number" ? size : SIZE_MAP[size] || SIZE_MAP.md;
|
|
32
|
+
let primaryColor = primaryColorProp ?? "currentColor";
|
|
33
|
+
const secondaryColor = secondaryColorProp ?? "currentColor";
|
|
34
|
+
const accentColor = accentColorProp ?? primaryColor;
|
|
35
|
+
if (color && SEMANTIC_COLOR_DEFAULTS[color]) {
|
|
36
|
+
if (!primaryColorProp) {
|
|
37
|
+
primaryColor = SEMANTIC_COLOR_DEFAULTS[color];
|
|
38
|
+
}
|
|
142
39
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
40
|
+
const isCutout = variant === "cutout";
|
|
41
|
+
const pathRenderer = isCutout || variant === "wireframe" ? paths.solid : paths[variant] ?? paths.solid;
|
|
42
|
+
const renderProps = {
|
|
43
|
+
primaryColor,
|
|
44
|
+
secondaryColor,
|
|
45
|
+
accentColor,
|
|
46
|
+
secondaryOpacity,
|
|
47
|
+
strokeWidth
|
|
48
|
+
};
|
|
49
|
+
const transforms = [];
|
|
50
|
+
if (rotate) {
|
|
51
|
+
transforms.push(`rotate(${rotate}deg)`);
|
|
52
|
+
}
|
|
53
|
+
if (flipX) {
|
|
54
|
+
transforms.push("scaleX(-1)");
|
|
55
|
+
}
|
|
56
|
+
if (flipY) {
|
|
57
|
+
transforms.push("scaleY(-1)");
|
|
58
|
+
}
|
|
59
|
+
if (scale && scale !== 1) {
|
|
60
|
+
transforms.push(`scale(${scale})`);
|
|
161
61
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
62
|
+
let gradientDefs = null;
|
|
63
|
+
let gradientId = null;
|
|
64
|
+
if (gradient && GRADIENT_PRESETS[gradient]) {
|
|
65
|
+
const colors = GRADIENT_PRESETS[gradient];
|
|
66
|
+
gradientId = `${displayName}-${gradient}-grad`;
|
|
67
|
+
const x1 = Math.round(50 - 50 * Math.cos(gradientDirection * Math.PI / 180));
|
|
68
|
+
const y1 = Math.round(50 - 50 * Math.sin(gradientDirection * Math.PI / 180));
|
|
69
|
+
const x2 = Math.round(50 + 50 * Math.cos(gradientDirection * Math.PI / 180));
|
|
70
|
+
const y2 = Math.round(50 + 50 * Math.sin(gradientDirection * Math.PI / 180));
|
|
71
|
+
gradientDefs = /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("linearGradient", { id: gradientId, x1: `${x1}%`, y1: `${y1}%`, x2: `${x2}%`, y2: `${y2}%`, children: colors.map((color2, i) => /* @__PURE__ */ jsx("stop", { offset: `${i / (colors.length - 1) * 100}%`, stopColor: color2 }, i)) }) });
|
|
72
|
+
renderProps.primaryColor = `url(#${gradientId})`;
|
|
167
73
|
}
|
|
74
|
+
const finalStyle = {
|
|
75
|
+
width: resolvedSize,
|
|
76
|
+
height: resolvedSize,
|
|
77
|
+
...style,
|
|
78
|
+
...transforms.length > 0 && { transform: transforms.join(" ") }
|
|
79
|
+
};
|
|
80
|
+
const cutoutMaskId = isCutout ? `${displayName}-cutout-mask` : null;
|
|
81
|
+
const cutoutBg = isCutout ? (() => {
|
|
82
|
+
const fill = renderProps.primaryColor !== "currentColor" ? renderProps.secondaryColor : renderProps.primaryColor;
|
|
83
|
+
const mask = `url(#${cutoutMaskId})`;
|
|
84
|
+
switch (cutoutShape) {
|
|
85
|
+
case "circle":
|
|
86
|
+
return /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "11", fill, mask });
|
|
87
|
+
case "square":
|
|
88
|
+
return /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "22", height: "22", fill, mask });
|
|
89
|
+
case "hexagon":
|
|
90
|
+
return /* @__PURE__ */ jsx(
|
|
91
|
+
"polygon",
|
|
92
|
+
{
|
|
93
|
+
points: "12,1 22.39,6.5 22.39,17.5 12,23 1.61,17.5 1.61,6.5",
|
|
94
|
+
fill,
|
|
95
|
+
mask
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
case "diamond":
|
|
99
|
+
return /* @__PURE__ */ jsx("polygon", { points: "12,1 23,12 12,23 1,12", fill, mask });
|
|
100
|
+
case "shield":
|
|
101
|
+
return /* @__PURE__ */ jsx(
|
|
102
|
+
"path",
|
|
103
|
+
{
|
|
104
|
+
d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5L12 1z",
|
|
105
|
+
fill,
|
|
106
|
+
mask
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
case "squircle":
|
|
110
|
+
return /* @__PURE__ */ jsx(
|
|
111
|
+
"path",
|
|
112
|
+
{
|
|
113
|
+
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",
|
|
114
|
+
fill,
|
|
115
|
+
mask
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
default:
|
|
119
|
+
return /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "22", height: "22", rx: "4", fill, mask });
|
|
120
|
+
}
|
|
121
|
+
})() : null;
|
|
122
|
+
const rendered = isCutout ? cutoutBg : variant === "sharp" ? sharpenTree(pathRenderer(renderProps)) : variant === "rounded" ? roundTree(pathRenderer(renderProps)) : variant === "wireframe" ? wireTree(pathRenderer(renderProps), renderProps.primaryColor) : pathRenderer(renderProps);
|
|
123
|
+
const iconContent = variant === "mini" ? /* @__PURE__ */ jsx("g", { transform: `translate(12 12) scale(${MINI_SCALE}) translate(-12 -12)`, children: rendered }) : rendered;
|
|
124
|
+
return /* @__PURE__ */ jsxs(
|
|
125
|
+
"svg",
|
|
126
|
+
{
|
|
127
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
128
|
+
viewBox,
|
|
129
|
+
width: resolvedSize,
|
|
130
|
+
height: resolvedSize,
|
|
131
|
+
fill: "none",
|
|
132
|
+
className,
|
|
133
|
+
style: finalStyle,
|
|
134
|
+
role,
|
|
135
|
+
"aria-label": ariaLabel,
|
|
136
|
+
"aria-hidden": ariaHidden ?? !ariaLabel,
|
|
137
|
+
"data-testid": testId,
|
|
138
|
+
children: [
|
|
139
|
+
title && /* @__PURE__ */ jsx("title", { children: title }),
|
|
140
|
+
gradientDefs,
|
|
141
|
+
isCutout && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("mask", { id: cutoutMaskId, children: [
|
|
142
|
+
/* @__PURE__ */ jsx("rect", { x: "0", y: "0", width: "24", height: "24", fill: "white" }),
|
|
143
|
+
/* @__PURE__ */ jsx("g", { transform: "translate(12,12) scale(0.8) translate(-12,-12)", children: paths.solid({
|
|
144
|
+
...renderProps,
|
|
145
|
+
primaryColor: "black",
|
|
146
|
+
secondaryColor: "black",
|
|
147
|
+
accentColor: "white"
|
|
148
|
+
}) })
|
|
149
|
+
] }) }),
|
|
150
|
+
iconContent
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
IconRSC.displayName = displayName;
|
|
156
|
+
return IconRSC;
|
|
157
|
+
}
|
|
158
|
+
function renderIconToString(Icon, props = {}) {
|
|
159
|
+
try {
|
|
160
|
+
const { renderToStaticMarkup } = require("react-dom/server");
|
|
161
|
+
const element = Icon(props);
|
|
162
|
+
return renderToStaticMarkup(element);
|
|
163
|
+
} catch {
|
|
164
|
+
const {
|
|
165
|
+
size = "md",
|
|
166
|
+
primaryColor = "currentColor",
|
|
167
|
+
variant: _variant = "solid",
|
|
168
|
+
className = ""
|
|
169
|
+
} = props;
|
|
170
|
+
const sizeValue = SIZE_MAP[size] ?? (typeof size === "number" ? size : 24);
|
|
171
|
+
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>`;
|
|
172
|
+
}
|
|
168
173
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Type guard to check if a component is an RSC-compatible icon
|
|
171
|
-
*/
|
|
172
174
|
function isRSCIcon(component) {
|
|
173
|
-
|
|
174
|
-
'displayName' in component &&
|
|
175
|
-
typeof component.displayName === 'string' &&
|
|
176
|
-
component.displayName.endsWith('RSC'));
|
|
175
|
+
return typeof component === "function" && "displayName" in component && typeof component.displayName === "string" && component.displayName.endsWith("RSC");
|
|
177
176
|
}
|
|
178
|
-
/* ────────────────────────────────────────────────────────────────────────────
|
|
179
|
-
RSC ICON WRAPPER
|
|
180
|
-
───────────────────────────────────────────────────────────────────────────── */
|
|
181
|
-
/**
|
|
182
|
-
* Creates an RSC version from an existing icon's path config.
|
|
183
|
-
* This allows creating RSC-compatible versions from standard icons.
|
|
184
|
-
*
|
|
185
|
-
* @example
|
|
186
|
-
* ```tsx
|
|
187
|
-
* import { NtdHome } from '@nice2dev/icons';
|
|
188
|
-
* import { wrapAsRSC } from '@nice2dev/icons/rsc';
|
|
189
|
-
*
|
|
190
|
-
* // Note: This requires access to the original path config
|
|
191
|
-
* const NtdHomeRSC = wrapAsRSC(NtdHome);
|
|
192
|
-
* ```
|
|
193
|
-
*/
|
|
194
177
|
function wrapAsRSC(originalPaths, displayName) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
178
|
+
return createIconRSC({
|
|
179
|
+
displayName: `${displayName}RSC`,
|
|
180
|
+
paths: originalPaths
|
|
181
|
+
});
|
|
199
182
|
}
|
|
200
|
-
|
|
201
|
-
|
|
183
|
+
export {
|
|
184
|
+
GRADIENT_PRESETS,
|
|
185
|
+
SEMANTIC_COLOR_DEFAULTS,
|
|
186
|
+
SIZE_MAP,
|
|
187
|
+
createIconRSC,
|
|
188
|
+
isRSCIcon,
|
|
189
|
+
renderIconToString,
|
|
190
|
+
wrapAsRSC
|
|
191
|
+
};
|
package/dist/esm/sharpen.js
CHANGED
|
@@ -1,141 +1,90 @@
|
|
|
1
|
-
import { Children, isValidElement, cloneElement } from
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Tags whose `rx`/`ry` express a *corner rounding* rather than the shape
|
|
5
|
-
* itself. `circle` / `ellipse` are deliberately absent — a circle has to stay
|
|
6
|
-
* a circle in every variant.
|
|
7
|
-
*/
|
|
8
|
-
const ROUNDED_CORNER_TAGS = new Set(['rect']);
|
|
9
|
-
/**
|
|
10
|
-
* Scale factor of the `mini` variant, about the icon centre. Shared by the
|
|
11
|
-
* client (`createIcon`) and RSC (`rsc`) renderers so the two stay identical.
|
|
12
|
-
*
|
|
13
|
-
* Thinning the stroke — what `mini` did on its own — is invisible on a filled
|
|
14
|
-
* shape, which left `mini` indistinguishable from `solid` for most of the set.
|
|
15
|
-
*/
|
|
1
|
+
import { Children, isValidElement, cloneElement } from "react";
|
|
2
|
+
const ROUNDED_CORNER_TAGS = /* @__PURE__ */ new Set(["rect"]);
|
|
16
3
|
const MINI_SCALE = 0.875;
|
|
17
|
-
/**
|
|
18
|
-
* Corner radius `rounded` gives a `<rect>`, as a fraction of its shorter side.
|
|
19
|
-
* Relative rather than absolute so it reads the same on a 16-unit detail rect
|
|
20
|
-
* and on a full-bleed 22-unit background.
|
|
21
|
-
*/
|
|
22
4
|
const ROUND_RADIUS_RATIO = 0.25;
|
|
23
|
-
/** SVG lengths arrive as numbers or numeric strings; anything else is unusable. */
|
|
24
5
|
function toNumber(value) {
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
const n = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
|
|
7
|
+
return Number.isFinite(n) ? n : void 0;
|
|
27
8
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Turns a rendered `solid` tree into its `sharp` equivalent: square line caps,
|
|
30
|
-
* mitered joins and zeroed corner radii, applied recursively.
|
|
31
|
-
*
|
|
32
|
-
* The `sharp` variant has no per-icon path data — it reuses `paths.solid` — so
|
|
33
|
-
* without this pass it would be pixel-identical to `solid` for every fill-based
|
|
34
|
-
* icon. Overriding rather than defaulting matters: some icons hardcode their
|
|
35
|
-
* own `strokeLinecap` / `strokeLinejoin`, and those must not survive here.
|
|
36
|
-
*
|
|
37
|
-
* Intrinsic (string-typed) elements only — fragments are traversed but never
|
|
38
|
-
* receive SVG attributes.
|
|
39
|
-
*/
|
|
40
9
|
function sharpenTree(node) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
10
|
+
return Children.map(node, (child) => {
|
|
11
|
+
if (!isValidElement(child)) {
|
|
12
|
+
return child;
|
|
13
|
+
}
|
|
14
|
+
const el = child;
|
|
15
|
+
const next = {};
|
|
16
|
+
if (typeof el.type === "string") {
|
|
17
|
+
next.strokeLinecap = "square";
|
|
18
|
+
next.strokeLinejoin = "miter";
|
|
19
|
+
if (ROUNDED_CORNER_TAGS.has(el.type)) {
|
|
20
|
+
next.rx = 0;
|
|
21
|
+
next.ry = 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const { children } = el.props;
|
|
25
|
+
if (children != null) {
|
|
26
|
+
next.children = sharpenTree(children);
|
|
27
|
+
}
|
|
28
|
+
return cloneElement(el, next);
|
|
29
|
+
});
|
|
61
30
|
}
|
|
62
|
-
/**
|
|
63
|
-
* The mirror of {@link sharpenTree}: round line caps and joins, and `<rect>`
|
|
64
|
-
* corners rounded to {@link ROUND_RADIUS_RATIO} of the shorter side.
|
|
65
|
-
*
|
|
66
|
-
* `rounded` reuses `paths.solid` exactly like `sharp` does, so without this pass
|
|
67
|
-
* it is indistinguishable from `solid`. Same override-don't-default rule — icons
|
|
68
|
-
* that hardcode square caps have to lose them here.
|
|
69
|
-
*
|
|
70
|
-
* A rect whose `width`/`height` cannot be read keeps whatever radius it had:
|
|
71
|
-
* guessing a radius without knowing the box would deform the shape. Rectangles
|
|
72
|
-
* drawn as `<path>` are out of reach either way — the same limitation
|
|
73
|
-
* `sharpenTree` documents above.
|
|
74
|
-
*/
|
|
75
31
|
function roundTree(node) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
32
|
+
return Children.map(node, (child) => {
|
|
33
|
+
if (!isValidElement(child)) {
|
|
34
|
+
return child;
|
|
35
|
+
}
|
|
36
|
+
const el = child;
|
|
37
|
+
const next = {};
|
|
38
|
+
if (typeof el.type === "string") {
|
|
39
|
+
next.strokeLinecap = "round";
|
|
40
|
+
next.strokeLinejoin = "round";
|
|
41
|
+
if (ROUNDED_CORNER_TAGS.has(el.type)) {
|
|
42
|
+
const width = toNumber(el.props.width);
|
|
43
|
+
const height = toNumber(el.props.height);
|
|
44
|
+
if (width !== void 0 && height !== void 0) {
|
|
45
|
+
const radius = Math.max(
|
|
46
|
+
toNumber(el.props.rx) ?? 0,
|
|
47
|
+
Math.min(width, height) * ROUND_RADIUS_RATIO
|
|
48
|
+
);
|
|
49
|
+
next.rx = radius;
|
|
50
|
+
next.ry = radius;
|
|
95
51
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const { children } = el.props;
|
|
55
|
+
if (children != null) {
|
|
56
|
+
next.children = roundTree(children);
|
|
57
|
+
}
|
|
58
|
+
return cloneElement(el, next);
|
|
59
|
+
});
|
|
102
60
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Stroke width of the `wireframe` variant — a thin, uniform construction line,
|
|
105
|
-
* deliberately independent of the caller's `strokeWidth` so a wireframe grid
|
|
106
|
-
* draws at one consistent weight.
|
|
107
|
-
*/
|
|
108
61
|
const WIREFRAME_STROKE = 1;
|
|
109
|
-
/**
|
|
110
|
-
* Turns a rendered tree into its `wireframe` equivalent: every shape becomes an
|
|
111
|
-
* unfilled thin outline in the primary colour, keeping the interior construction
|
|
112
|
-
* that `outline` drops (creases, inner discs, duotone underlays).
|
|
113
|
-
*
|
|
114
|
-
* Fed from `paths.solid`, because that layer carries the whole construction —
|
|
115
|
-
* `outline` is the silhouette only. Per-shape `opacity` is cleared as well, so a
|
|
116
|
-
* faint duotone wash does not survive as a ghost line.
|
|
117
|
-
*/
|
|
118
62
|
function wireTree(node, color) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
63
|
+
return Children.map(node, (child) => {
|
|
64
|
+
if (!isValidElement(child)) {
|
|
65
|
+
return child;
|
|
66
|
+
}
|
|
67
|
+
const el = child;
|
|
68
|
+
const next = {};
|
|
69
|
+
if (typeof el.type === "string") {
|
|
70
|
+
next.fill = "none";
|
|
71
|
+
next.stroke = color;
|
|
72
|
+
next.strokeWidth = WIREFRAME_STROKE;
|
|
73
|
+
next.strokeLinecap = "round";
|
|
74
|
+
next.strokeLinejoin = "round";
|
|
75
|
+
next.opacity = void 0;
|
|
76
|
+
}
|
|
77
|
+
const { children } = el.props;
|
|
78
|
+
if (children != null) {
|
|
79
|
+
next.children = wireTree(children, color);
|
|
80
|
+
}
|
|
81
|
+
return cloneElement(el, next);
|
|
82
|
+
});
|
|
139
83
|
}
|
|
140
|
-
|
|
141
|
-
|
|
84
|
+
export {
|
|
85
|
+
MINI_SCALE,
|
|
86
|
+
WIREFRAME_STROKE,
|
|
87
|
+
roundTree,
|
|
88
|
+
sharpenTree,
|
|
89
|
+
wireTree
|
|
90
|
+
};
|