@askrjs/lucide 0.0.9 → 0.2.1
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 +13 -6
- package/dist/create-icon.d.ts.map +1 -1
- package/dist/create-icon.js +24 -6
- package/dist/create-icon.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,13 +11,15 @@ Thin Askr wrappers for the [Lucide](https://lucide.dev) SVG icon set.
|
|
|
11
11
|
npm install @askrjs/lucide
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Requires `@askrjs/askr` `>=0.0.
|
|
15
|
-
The repo toolchain expects Node `
|
|
14
|
+
Requires `@askrjs/askr` `>=0.2.0 <0.3.0` as a peer dependency.
|
|
15
|
+
The repo toolchain expects Node `24+` for local builds and tests.
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
19
|
```tsx
|
|
20
|
-
import { SearchIcon
|
|
20
|
+
import { SearchIcon } from "@askrjs/lucide/icons/search";
|
|
21
|
+
import { XIcon } from "@askrjs/lucide/icons/x";
|
|
22
|
+
import { MenuIcon } from "@askrjs/lucide/icons/menu";
|
|
21
23
|
|
|
22
24
|
function App() {
|
|
23
25
|
return (
|
|
@@ -59,14 +61,19 @@ Passing a `title` removes `aria-hidden` and renders a `<title>` element inside t
|
|
|
59
61
|
|
|
60
62
|
## Tree shaking
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
For production applications, prefer per-icon subpath imports. They avoid loading
|
|
65
|
+
the roughly 2,000-module root barrel in development servers and bundlers that do
|
|
66
|
+
not aggressively eliminate unused exports:
|
|
63
67
|
|
|
64
68
|
```tsx
|
|
65
|
-
import { SearchIcon } from "@askrjs/lucide";
|
|
69
|
+
import { SearchIcon } from "@askrjs/lucide/icons/search";
|
|
66
70
|
```
|
|
67
71
|
|
|
72
|
+
The root barrel is convenient for prototyping. If you use it in production,
|
|
73
|
+
verify tree shaking in your bundler:
|
|
74
|
+
|
|
68
75
|
```tsx
|
|
69
|
-
import { SearchIcon } from "@askrjs/lucide
|
|
76
|
+
import { SearchIcon } from "@askrjs/lucide";
|
|
70
77
|
```
|
|
71
78
|
|
|
72
79
|
The package is marked `"sideEffects": false` and built with `preserveModules`, so bundlers can eliminate unused icons completely.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-icon.d.ts","names":[],"sources":["../src/create-icon.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"create-icon.d.ts","names":[],"sources":["../src/create-icon.tsx"],"mappings":";;iBAoEgB,WAAW,qBAAqB,UAAU;QAG7B,QAAA,+CAAS"}
|
package/dist/create-icon.js
CHANGED
|
@@ -11,24 +11,42 @@ const SAFE_TAGS = /* @__PURE__ */ new Set([
|
|
|
11
11
|
"polyline",
|
|
12
12
|
"rect"
|
|
13
13
|
]);
|
|
14
|
+
const SAFE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
15
|
+
"cx",
|
|
16
|
+
"cy",
|
|
17
|
+
"d",
|
|
18
|
+
"fill",
|
|
19
|
+
"height",
|
|
20
|
+
"points",
|
|
21
|
+
"r",
|
|
22
|
+
"rx",
|
|
23
|
+
"ry",
|
|
24
|
+
"width",
|
|
25
|
+
"x",
|
|
26
|
+
"x1",
|
|
27
|
+
"x2",
|
|
28
|
+
"y",
|
|
29
|
+
"y1",
|
|
30
|
+
"y2"
|
|
31
|
+
]);
|
|
14
32
|
const URL_ATTRIBUTE = /^(?:href|src|xlink:href)$/i;
|
|
15
33
|
const URL_VALUE = /url\s*\(/i;
|
|
16
|
-
function copyDefinition(iconNode) {
|
|
17
|
-
if (!Array.isArray(iconNode)) throw new TypeError(
|
|
34
|
+
function copyDefinition(displayName, iconNode) {
|
|
35
|
+
if (!Array.isArray(iconNode)) throw new TypeError(`${displayName}: icon definition must be an array`);
|
|
18
36
|
return iconNode.map((entry) => {
|
|
19
|
-
if (!Array.isArray(entry) || entry.length !== 2 || !SAFE_TAGS.has(entry[0])) throw new TypeError(
|
|
37
|
+
if (!Array.isArray(entry) || entry.length !== 2 || !SAFE_TAGS.has(entry[0])) throw new TypeError(`${displayName}: icon definition contains an unsafe SVG element`);
|
|
20
38
|
const attributes = entry[1];
|
|
21
|
-
if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) throw new TypeError(
|
|
39
|
+
if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) throw new TypeError(`${displayName}: icon definition attributes must be an object`);
|
|
22
40
|
const copied = Object.create(null);
|
|
23
41
|
for (const [name, value] of Object.entries(attributes)) {
|
|
24
|
-
if (/^on/i.test(name) || /^(?:__proto__|constructor|prototype)$/i.test(name) || URL_ATTRIBUTE.test(name) || typeof value !== "string" || URL_VALUE.test(value)) throw new TypeError(
|
|
42
|
+
if (/^on/i.test(name) || /^(?:__proto__|constructor|prototype)$/i.test(name) || URL_ATTRIBUTE.test(name) || !SAFE_ATTRIBUTES.has(name) || typeof value !== "string" || URL_VALUE.test(value)) throw new TypeError(`${displayName}: icon definition contains an unsafe SVG attribute (${name})`);
|
|
25
43
|
copied[name] = value;
|
|
26
44
|
}
|
|
27
45
|
return [entry[0], Object.freeze(copied)];
|
|
28
46
|
});
|
|
29
47
|
}
|
|
30
48
|
function createIcon(displayName, iconNode) {
|
|
31
|
-
const definition = Object.freeze(copyDefinition(iconNode));
|
|
49
|
+
const definition = Object.freeze(copyDefinition(displayName, iconNode));
|
|
32
50
|
function Icon({ ...rest }) {
|
|
33
51
|
return IconBase({
|
|
34
52
|
...rest,
|
package/dist/create-icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-icon.js","names":["createSvgNode"],"sources":["../src/create-icon.tsx"],"sourcesContent":["import { jsx as createSvgNode } from \"@askrjs/askr/jsx-runtime\";\nimport { IconBase } from \"@askrjs/askr/foundations/icon\";\nimport type { IconNode, IconProps } from \"./types\";\n\nconst SAFE_TAGS = new Set([\n \"circle\",\n \"ellipse\",\n \"g\",\n \"line\",\n \"path\",\n \"polygon\",\n \"polyline\",\n \"rect\",\n]);\nconst URL_ATTRIBUTE = /^(?:href|src|xlink:href)$/i;\nconst URL_VALUE = /url\\s*\\(/i;\n\nfunction copyDefinition(iconNode: IconNode): IconNode {\n if (!Array.isArray(iconNode)) throw new TypeError(
|
|
1
|
+
{"version":3,"file":"create-icon.js","names":["createSvgNode"],"sources":["../src/create-icon.tsx"],"sourcesContent":["import { jsx as createSvgNode } from \"@askrjs/askr/jsx-runtime\";\nimport { IconBase } from \"@askrjs/askr/foundations/icon\";\nimport type { IconNode, IconProps } from \"./types\";\n\nconst SAFE_TAGS = new Set([\n \"circle\",\n \"ellipse\",\n \"g\",\n \"line\",\n \"path\",\n \"polygon\",\n \"polyline\",\n \"rect\",\n]);\nconst SAFE_ATTRIBUTES = new Set([\n \"cx\",\n \"cy\",\n \"d\",\n \"fill\",\n \"height\",\n \"points\",\n \"r\",\n \"rx\",\n \"ry\",\n \"width\",\n \"x\",\n \"x1\",\n \"x2\",\n \"y\",\n \"y1\",\n \"y2\",\n]);\nconst URL_ATTRIBUTE = /^(?:href|src|xlink:href)$/i;\nconst URL_VALUE = /url\\s*\\(/i;\n\nfunction copyDefinition(displayName: string, iconNode: IconNode): IconNode {\n if (!Array.isArray(iconNode)) {\n throw new TypeError(`${displayName}: icon definition must be an array`);\n }\n\n return iconNode.map((entry) => {\n if (!Array.isArray(entry) || entry.length !== 2 || !SAFE_TAGS.has(entry[0])) {\n throw new TypeError(`${displayName}: icon definition contains an unsafe SVG element`);\n }\n const attributes = entry[1];\n if (!attributes || typeof attributes !== \"object\" || Array.isArray(attributes)) {\n throw new TypeError(`${displayName}: icon definition attributes must be an object`);\n }\n const copied = Object.create(null) as Record<string, string>;\n for (const [name, value] of Object.entries(attributes)) {\n if (\n /^on/i.test(name) ||\n /^(?:__proto__|constructor|prototype)$/i.test(name) ||\n URL_ATTRIBUTE.test(name) ||\n !SAFE_ATTRIBUTES.has(name) ||\n typeof value !== \"string\" ||\n URL_VALUE.test(value)\n ) {\n throw new TypeError(\n `${displayName}: icon definition contains an unsafe SVG attribute (${name})`,\n );\n }\n copied[name] = value;\n }\n return [entry[0], Object.freeze(copied)] as const;\n });\n}\n\nexport function createIcon(displayName: string, iconNode: IconNode) {\n const definition = Object.freeze(copyDefinition(displayName, iconNode));\n\n function Icon({ ...rest }: IconProps) {\n return IconBase({\n ...rest,\n iconName: displayName,\n children: definition.map(([tag, attrs], i) =>\n createSvgNode(tag, attrs as Record<string, unknown>, i),\n ),\n });\n }\n\n Icon.displayName = displayName;\n return Icon;\n}\n"],"mappings":";;;AAIA,MAAM,4BAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,gBAAgB;AACtB,MAAM,YAAY;AAElB,SAAS,eAAe,aAAqB,UAA8B;CACzE,IAAI,CAAC,MAAM,QAAQ,QAAQ,GACzB,MAAM,IAAI,UAAU,GAAG,YAAY,mCAAmC;CAGxE,OAAO,SAAS,KAAK,UAAU;EAC7B,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,KAAK,CAAC,UAAU,IAAI,MAAM,EAAE,GACxE,MAAM,IAAI,UAAU,GAAG,YAAY,iDAAiD;EAEtF,MAAM,aAAa,MAAM;EACzB,IAAI,CAAC,cAAc,OAAO,eAAe,YAAY,MAAM,QAAQ,UAAU,GAC3E,MAAM,IAAI,UAAU,GAAG,YAAY,+CAA+C;EAEpF,MAAM,SAAS,OAAO,OAAO,IAAI;EACjC,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,UAAU,GAAG;GACtD,IACE,OAAO,KAAK,IAAI,KAChB,yCAAyC,KAAK,IAAI,KAClD,cAAc,KAAK,IAAI,KACvB,CAAC,gBAAgB,IAAI,IAAI,KACzB,OAAO,UAAU,YACjB,UAAU,KAAK,KAAK,GAEpB,MAAM,IAAI,UACR,GAAG,YAAY,sDAAsD,KAAK,EAC5E;GAEF,OAAO,QAAQ;EACjB;EACA,OAAO,CAAC,MAAM,IAAI,OAAO,OAAO,MAAM,CAAC;CACzC,CAAC;AACH;AAEA,SAAgB,WAAW,aAAqB,UAAoB;CAClE,MAAM,aAAa,OAAO,OAAO,eAAe,aAAa,QAAQ,CAAC;CAEtE,SAAS,KAAK,EAAE,GAAG,QAAmB;EACpC,OAAO,SAAS;GACd,GAAG;GACH,UAAU;GACV,UAAU,WAAW,KAAK,CAAC,KAAK,QAAQ,MACtCA,IAAc,KAAK,OAAkC,CAAC,CACxD;EACF,CAAC;CACH;CAEA,KAAK,cAAc;CACnB,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/lucide",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Thin Askr wrappers for the Lucide SVG icon set",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"askr",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"test:unit": "vp test run -c vitest.config.ts"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@askrjs/askr": ">=0.0
|
|
69
|
+
"@askrjs/askr": ">=0.2.0 <0.3.0",
|
|
70
70
|
"@vitest/coverage-v8": "^4.1.10",
|
|
71
71
|
"jsdom": "^30.0.1",
|
|
72
72
|
"lucide": "1.30.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"vite-plus": "^0.2.8"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@askrjs/askr": ">=0.0
|
|
78
|
+
"@askrjs/askr": ">=0.2.0 <0.3.0"
|
|
79
79
|
},
|
|
80
80
|
"engines": {
|
|
81
81
|
"node": ">=24.0.0"
|