@puzzle-ui/icons 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,85 @@
1
- # Temporary Holding Version
1
+ # @puzzle-ui/icons
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React icon components backed by Iconify. Use named icons in your application
4
+ or alongside Puzzle UI components.
5
+
6
+ > Puzzle is under active development. APIs and framework compatibility may
7
+ > change; use it for experimentation and evaluation rather than production.
8
+
9
+ ## Installation
10
+
11
+ ```sh
12
+ npm install @puzzle-ui/icons
13
+ # or
14
+ bun add @puzzle-ui/icons
15
+ # or
16
+ pnpm add @puzzle-ui/icons
17
+ # or
18
+ yarn add @puzzle-ui/icons
19
+ ```
20
+
21
+ Requires React and React DOM 19 (`^19.0.0`). No theme provider is required.
22
+
23
+ ## Usage
24
+
25
+ ```tsx
26
+ import { Icon } from "@puzzle-ui/icons";
27
+
28
+ export const HomeIcon = () => (
29
+ <Icon name="lucide:house" size={24} aria-hidden="true" />
30
+ );
31
+ ```
32
+
33
+ `Icon` accepts a collection-prefixed `name`, optional numeric `size` in
34
+ pixels, optional `color`, and SVG attributes. Without an explicit color,
35
+ it can inherit the surrounding text color.
36
+
37
+ For icon-only controls, label the control and keep its icon decorative:
38
+
39
+ ```tsx
40
+ <button type="button" aria-label="Search">
41
+ <Icon name="lucide:search" aria-hidden="true" />
42
+ </button>
43
+ ```
44
+
45
+ ## Server rendering
46
+
47
+ The package also exports `SSRIcon` and `SSRIconProps`. `SSRIcon` is an async
48
+ component that fetches icon data on the server and falls back to Iconify's
49
+ client-side loading when data is unavailable.
50
+
51
+ Use it only in rendering environments that support async components, such
52
+ as an appropriate React Server Component setup. It is not a drop-in async
53
+ component for ordinary client-side React rendering.
54
+
55
+ Icon loading can make external requests to Iconify. Account for network
56
+ availability and your Content Security Policy. Framework compatibility is
57
+ still being evaluated.
58
+
59
+ ## Exports
60
+
61
+ - `Icon`, `IconProps`
62
+ - `SSRIcon`, `SSRIconProps`
63
+
64
+ Import from `@puzzle-ui/icons`; generated internal icon-set files are not
65
+ exported package entry points. ESM and CommonJS builds and TypeScript
66
+ declarations are included.
67
+
68
+ ## Development
69
+
70
+ ```sh
71
+ # From the repository root
72
+ npm run build --workspace=@puzzle-ui/icons
73
+
74
+ # From this package directory
75
+ bun run vitest
76
+ ```
77
+
78
+ `prepack` rebuilds the package before packing or publishing. See the root
79
+ [publishing guide](../../README.md#publishing-packages).
80
+
81
+ ## License
82
+
83
+ Package code is MIT; see [LICENSE](../../LICENSE), also included at
84
+ `dist/LICENSE` in published packages. Individual icon collections may carry
85
+ their own licenses; check the collection's terms before using its artwork.
package/dist/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sjoerd van Den Berg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,62 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _iconify_react = require("@iconify/react");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let _iconify_utils = require("@iconify/utils");
5
+ // src/icon.tsx
6
+ const Icon = ({ name, size, color, ...props }) => {
7
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_iconify_react.Icon, {
8
+ ...props,
9
+ icon: name ?? "",
10
+ width: size,
11
+ height: size,
12
+ style: {
13
+ color,
14
+ width: size ? `${size}px` : void 0,
15
+ height: size ? `${size}px` : void 0
16
+ }
17
+ });
18
+ };
19
+ // src/ssr-icon.tsx
20
+ async function fetchIconDataServer(iconName) {
21
+ const iconObj = (0, _iconify_utils.stringToIcon)(iconName);
22
+ if (!iconObj) return null;
23
+ try {
24
+ const response = await fetch(`https://iconify.design/${iconObj.prefix}.json?icons=${iconObj.name}`);
25
+ if (!response.ok) return null;
26
+ const json = await response.json();
27
+ return (0, _iconify_utils.getIconData)(json, iconObj.name);
28
+ } catch (error) {
29
+ console.error(`[SSR] Error fetching icon ${iconName}:`, error);
30
+ return null;
31
+ }
32
+ }
33
+ const SSRIcon = async ({ name, size, color, ...props }) => {
34
+ const iconData = await fetchIconDataServer(name);
35
+ if (iconData) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_iconify_react.Icon, {
36
+ ...props,
37
+ icon: iconData,
38
+ width: size,
39
+ height: size,
40
+ style: {
41
+ color,
42
+ width: size ? `${size}px` : void 0,
43
+ height: size ? `${size}px` : void 0
44
+ }
45
+ });
46
+ console.warn(`[SSR] Fallback to client-side for icon: ${name}`);
47
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_iconify_react.Icon, {
48
+ ...props,
49
+ icon: name ?? "",
50
+ width: size,
51
+ height: size,
52
+ style: {
53
+ color,
54
+ width: size ? `${size}px` : void 0,
55
+ height: size ? `${size}px` : void 0
56
+ }
57
+ });
58
+ };
59
+ exports.Icon = Icon;
60
+ exports.SSRIcon = SSRIcon;
61
+
62
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["IconifyIcon","stringToIcon","getIconData","IconifyIcon"],"sources":["../src/icon.tsx","../src/ssr-icon.tsx"],"sourcesContent":["import { Icon as IconifyIcon } from \"@iconify/react\";\nimport type { ComponentProps } from \"react\";\n\ntype IconProps = Omit<ComponentProps<\"svg\">, \"mode\" | \"onLoad\" | \"rotate\"> & {\n name: string;\n size?: number;\n color?: string;\n};\n\nconst Icon = ({ name, size, color, ...props }: IconProps) => {\n return (\n <IconifyIcon\n {...props}\n icon={name ?? \"\"}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n};\n\nexport { Icon, type IconProps };\n","import { Icon as IconifyIcon } from \"@iconify/react\";\nimport type { ComponentProps } from \"react\";\nimport { getIconData, stringToIcon } from \"@iconify/utils\";\n\nasync function fetchIconDataServer(iconName: string) {\n const iconObj = stringToIcon(iconName);\n if (!iconObj) return null;\n\n try {\n const response = await fetch(\n `https://iconify.design/${iconObj.prefix}.json?icons=${iconObj.name}`,\n );\n if (!response.ok) return null;\n\n const json = await response.json();\n return getIconData(json, iconObj.name);\n } catch (error) {\n console.error(`[SSR] Error fetching icon ${iconName}:`, error);\n return null;\n }\n}\n\ntype SSRIconProps = Omit<\n ComponentProps<\"svg\">,\n \"mode\" | \"onLoad\" | \"rotate\"\n> & {\n name: string;\n size?: number;\n color?: string;\n};\n\nconst SSRIcon = async ({ name, size, color, ...props }: SSRIconProps) => {\n const iconData = await fetchIconDataServer(name);\n if (iconData) {\n return (\n <IconifyIcon\n {...props}\n icon={iconData}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n }\n console.warn(`[SSR] Fallback to client-side for icon: ${name}`);\n return (\n <IconifyIcon\n {...props}\n icon={name ?? \"\"}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n};\n\nexport { SSRIcon, type SSRIconProps };\n"],"mappings":";;;;;AASA,MAAM,QAAQ,EAAE,MAAM,MAAM,OAAO,GAAG,YAAuB;CAC3D,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,MAAD;EACE,GAAI;EACJ,MAAM,QAAQ;EACd,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;AAEL;;ACnBA,eAAe,oBAAoB,UAAkB;CACnD,MAAM,WAAA,GAAUC,eAAAA,aAAAA,CAAa,QAAQ;CACrC,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;EACF,MAAM,WAAW,MAAM,MACrB,0BAA0B,QAAQ,OAAO,cAAc,QAAQ,MACjE;EACA,IAAI,CAAC,SAAS,IAAI,OAAO;EAEzB,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,QAAA,GAAOC,eAAAA,YAAAA,CAAY,MAAM,QAAQ,IAAI;CACvC,SAAS,OAAO;EACd,QAAQ,MAAM,6BAA6B,SAAS,IAAI,KAAK;EAC7D,OAAO;CACT;AACF;AAWA,MAAM,UAAU,OAAO,EAAE,MAAM,MAAM,OAAO,GAAG,YAA0B;CACvE,MAAM,WAAW,MAAM,oBAAoB,IAAI;CAC/C,IAAI,UACF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,MAAD;EACE,GAAI;EACJ,MAAM;EACN,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;CAGL,QAAQ,KAAK,2CAA2C,MAAM;CAC9D,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,MAAD;EACE,GAAI;EACJ,MAAM,QAAQ;EACd,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;AAEL"}
@@ -0,0 +1,14 @@
1
+ import { ComponentProps } from "react";
2
+ type IconProps = Omit<ComponentProps<"svg">, "mode" | "onLoad" | "rotate"> & {
3
+ name: string;
4
+ size?: number;
5
+ color?: string;
6
+ };
7
+ declare const Icon: ({ name, size, color, ...props }: IconProps) => import("react").JSX.Element;
8
+ type SSRIconProps = Omit<ComponentProps<"svg">, "mode" | "onLoad" | "rotate"> & {
9
+ name: string;
10
+ size?: number;
11
+ color?: string;
12
+ };
13
+ declare const SSRIcon: ({ name, size, color, ...props }: SSRIconProps) => Promise<import("react").JSX.Element>;
14
+ export { Icon, type IconProps, SSRIcon, type SSRIconProps };
@@ -0,0 +1,14 @@
1
+ import { ComponentProps } from "react";
2
+ type IconProps = Omit<ComponentProps<"svg">, "mode" | "onLoad" | "rotate"> & {
3
+ name: string;
4
+ size?: number;
5
+ color?: string;
6
+ };
7
+ declare const Icon: ({ name, size, color, ...props }: IconProps) => import("react").JSX.Element;
8
+ type SSRIconProps = Omit<ComponentProps<"svg">, "mode" | "onLoad" | "rotate"> & {
9
+ name: string;
10
+ size?: number;
11
+ color?: string;
12
+ };
13
+ declare const SSRIcon: ({ name, size, color, ...props }: SSRIconProps) => Promise<import("react").JSX.Element>;
14
+ export { Icon, type IconProps, SSRIcon, type SSRIconProps };
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ import { Icon as Icon$1 } from "@iconify/react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { getIconData, stringToIcon } from "@iconify/utils";
4
+ // src/icon.tsx
5
+ const Icon = ({ name, size, color, ...props }) => {
6
+ return /* @__PURE__ */ jsx(Icon$1, {
7
+ ...props,
8
+ icon: name ?? "",
9
+ width: size,
10
+ height: size,
11
+ style: {
12
+ color,
13
+ width: size ? `${size}px` : void 0,
14
+ height: size ? `${size}px` : void 0
15
+ }
16
+ });
17
+ };
18
+ // src/ssr-icon.tsx
19
+ async function fetchIconDataServer(iconName) {
20
+ const iconObj = stringToIcon(iconName);
21
+ if (!iconObj) return null;
22
+ try {
23
+ const response = await fetch(`https://iconify.design/${iconObj.prefix}.json?icons=${iconObj.name}`);
24
+ if (!response.ok) return null;
25
+ const json = await response.json();
26
+ return getIconData(json, iconObj.name);
27
+ } catch (error) {
28
+ console.error(`[SSR] Error fetching icon ${iconName}:`, error);
29
+ return null;
30
+ }
31
+ }
32
+ const SSRIcon = async ({ name, size, color, ...props }) => {
33
+ const iconData = await fetchIconDataServer(name);
34
+ if (iconData) return /* @__PURE__ */ jsx(Icon$1, {
35
+ ...props,
36
+ icon: iconData,
37
+ width: size,
38
+ height: size,
39
+ style: {
40
+ color,
41
+ width: size ? `${size}px` : void 0,
42
+ height: size ? `${size}px` : void 0
43
+ }
44
+ });
45
+ console.warn(`[SSR] Fallback to client-side for icon: ${name}`);
46
+ return /* @__PURE__ */ jsx(Icon$1, {
47
+ ...props,
48
+ icon: name ?? "",
49
+ width: size,
50
+ height: size,
51
+ style: {
52
+ color,
53
+ width: size ? `${size}px` : void 0,
54
+ height: size ? `${size}px` : void 0
55
+ }
56
+ });
57
+ };
58
+ export { Icon, SSRIcon };
59
+
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["IconifyIcon","IconifyIcon"],"sources":["../src/icon.tsx","../src/ssr-icon.tsx"],"sourcesContent":["import { Icon as IconifyIcon } from \"@iconify/react\";\nimport type { ComponentProps } from \"react\";\n\ntype IconProps = Omit<ComponentProps<\"svg\">, \"mode\" | \"onLoad\" | \"rotate\"> & {\n name: string;\n size?: number;\n color?: string;\n};\n\nconst Icon = ({ name, size, color, ...props }: IconProps) => {\n return (\n <IconifyIcon\n {...props}\n icon={name ?? \"\"}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n};\n\nexport { Icon, type IconProps };\n","import { Icon as IconifyIcon } from \"@iconify/react\";\nimport type { ComponentProps } from \"react\";\nimport { getIconData, stringToIcon } from \"@iconify/utils\";\n\nasync function fetchIconDataServer(iconName: string) {\n const iconObj = stringToIcon(iconName);\n if (!iconObj) return null;\n\n try {\n const response = await fetch(\n `https://iconify.design/${iconObj.prefix}.json?icons=${iconObj.name}`,\n );\n if (!response.ok) return null;\n\n const json = await response.json();\n return getIconData(json, iconObj.name);\n } catch (error) {\n console.error(`[SSR] Error fetching icon ${iconName}:`, error);\n return null;\n }\n}\n\ntype SSRIconProps = Omit<\n ComponentProps<\"svg\">,\n \"mode\" | \"onLoad\" | \"rotate\"\n> & {\n name: string;\n size?: number;\n color?: string;\n};\n\nconst SSRIcon = async ({ name, size, color, ...props }: SSRIconProps) => {\n const iconData = await fetchIconDataServer(name);\n if (iconData) {\n return (\n <IconifyIcon\n {...props}\n icon={iconData}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n }\n console.warn(`[SSR] Fallback to client-side for icon: ${name}`);\n return (\n <IconifyIcon\n {...props}\n icon={name ?? \"\"}\n width={size}\n height={size}\n style={{\n color: color,\n width: size ? `${size}px` : undefined,\n height: size ? `${size}px` : undefined,\n }}\n />\n );\n};\n\nexport { SSRIcon, type SSRIconProps };\n"],"mappings":";;;;AASA,MAAM,QAAQ,EAAE,MAAM,MAAM,OAAO,GAAG,YAAuB;CAC3D,OACE,oBAACA,QAAD;EACE,GAAI;EACJ,MAAM,QAAQ;EACd,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;AAEL;;ACnBA,eAAe,oBAAoB,UAAkB;CACnD,MAAM,UAAU,aAAa,QAAQ;CACrC,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;EACF,MAAM,WAAW,MAAM,MACrB,0BAA0B,QAAQ,OAAO,cAAc,QAAQ,MACjE;EACA,IAAI,CAAC,SAAS,IAAI,OAAO;EAEzB,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,OAAO,YAAY,MAAM,QAAQ,IAAI;CACvC,SAAS,OAAO;EACd,QAAQ,MAAM,6BAA6B,SAAS,IAAI,KAAK;EAC7D,OAAO;CACT;AACF;AAWA,MAAM,UAAU,OAAO,EAAE,MAAM,MAAM,OAAO,GAAG,YAA0B;CACvE,MAAM,WAAW,MAAM,oBAAoB,IAAI;CAC/C,IAAI,UACF,OACE,oBAACC,QAAD;EACE,GAAI;EACJ,MAAM;EACN,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;CAGL,QAAQ,KAAK,2CAA2C,MAAM;CAC9D,OACE,oBAACA,QAAD;EACE,GAAI;EACJ,MAAM,QAAQ;EACd,OAAO;EACP,QAAQ;EACR,OAAO;GACE;GACP,OAAO,OAAO,GAAG,KAAK,MAAM,KAAA;GAC5B,QAAQ,OAAO,GAAG,KAAK,MAAM,KAAA;EAC/B;CACD,CAAA;AAEL"}
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
2
  "name": "@puzzle-ui/icons",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Icons for Puzzle",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "type": "module",
11
+ "sideEffects": false,
12
+ "main": "./dist/index.cjs",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "import": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "require": {
22
+ "types": "./dist/index.d.cts",
23
+ "default": "./dist/index.cjs"
24
+ }
25
+ }
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsdown",
32
+ "vitest": "bunx vitest run --passWithNoTests",
33
+ "vitest:watch": "bunx vitest",
34
+ "clean": "rm -rf dist",
35
+ "prepack": "tsdown"
36
+ },
37
+ "dependencies": {
38
+ "@iconify/react": "^6.0.3",
39
+ "@iconify/utils": "^3.1.7",
40
+ "@puzzle-ui/core": "^0.2.0"
41
+ },
42
+ "peerDependencies": {
43
+ "react": "^19.0.0",
44
+ "react-dom": "^19.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "^19.0.0",
48
+ "@types/react-dom": "^19.0.0",
49
+ "tsdown": "^0.23.1",
50
+ "typescript": "^6.0.3",
51
+ "vitest": "latest"
52
+ }
53
+ }