@open-dy/lucide-taro 0.0.1-beta.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 ADDED
@@ -0,0 +1,147 @@
1
+ # @open-dy/lucide-taro
2
+
3
+ 面向 Taro 小程序的 Lucide 图标组件库,并提供生成小程序 TabBar PNG 图标的命令行工具。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm add @open-dy/lucide-taro
9
+ ```
10
+
11
+ 项目需要同时安装兼容版本的 React 与 `@tarojs/components`。
12
+
13
+ ## 使用图标组件
14
+
15
+ 图标名和常用 API 与 `lucide-react` 保持一致,业务代码必须从 `@open-dy/lucide-taro` 导入:
16
+
17
+ ```tsx
18
+ import { House, Search, Settings } from '@open-dy/lucide-taro'
19
+ import { View } from '@tarojs/components'
20
+
21
+ export function Actions() {
22
+ return (
23
+ <View className="flex items-center gap-3">
24
+ <House size={24} color="#1677ff" strokeWidth={2} />
25
+ <Search size="20" color="#111827" />
26
+ <Settings size={20} color="#6b7280" />
27
+ </View>
28
+ )
29
+ }
30
+ ```
31
+
32
+ ### 图标属性
33
+
34
+ | 属性 | 类型 | 默认值 | 说明 |
35
+ | --- | --- | --- | --- |
36
+ | `size` | `string \| number` | `24` | 图标宽高 |
37
+ | `color` | `string` | `currentColor` | 描边颜色;小程序中建议始终显式传入 |
38
+ | `strokeWidth` | `string \| number` | `2` | 描边宽度 |
39
+ | `filled` | `boolean` | `false` | 使用 `color` 填充图标 |
40
+ | `absoluteStrokeWidth` | `boolean` | `false` | 缩放尺寸时保持视觉描边宽度 |
41
+ | `className` | `string` | - | 添加到外层 Taro `Image` |
42
+ | `style` | `CSSProperties` | - | 添加到外层 Taro `Image` |
43
+
44
+ 原生小程序不能直接渲染内联 SVG。本包会把图标序列化为 SVG data URI,并通过 Taro `Image` 组件显示。因此:
45
+
46
+ - `className` 和 `style` 只影响外层 `Image`,不会把 CSS `color` 传入 SVG。
47
+ - 不要依赖 `currentColor` 或 `text-*` class 改变图标笔画,始终显式传递 `color`。
48
+ - 图标所在的按钮或容器应提供明确宽高和居中布局。
49
+
50
+ ## 全局默认属性
51
+
52
+ 可以使用 `LucideProvider` 为子树设置默认值:
53
+
54
+ ```tsx
55
+ import {
56
+ Bell,
57
+ LucideProvider,
58
+ MessageCircle,
59
+ } from '@open-dy/lucide-taro'
60
+
61
+ export function IconGroup() {
62
+ return (
63
+ <LucideProvider size={20} color="#475569" strokeWidth={2}>
64
+ <Bell />
65
+ <MessageCircle color="#1677ff" />
66
+ </LucideProvider>
67
+ )
68
+ }
69
+ ```
70
+
71
+ 组件自身的属性会覆盖 Provider 默认值。`useLucideContext()` 可读取当前默认配置。
72
+
73
+ ## 查找可用图标
74
+
75
+ 包会导出 Lucide 的 PascalCase 图标名及常见兼容别名。不要猜测图标是否存在,使用前搜索类型声明:
76
+
77
+ ```bash
78
+ rg "declare const House" node_modules/@open-dy/lucide-taro/dist/lucide-taro.d.ts
79
+ ```
80
+
81
+ 常见命名形态包括 `House`、`HouseIcon` 和部分历史别名。准确导出列表以 `dist/lucide-taro.d.ts` 为准。
82
+
83
+ ## 生成 TabBar PNG
84
+
85
+ 小程序 TabBar 不支持 SVG 或 data URI,需要使用本地 PNG。安装 `sharp` 后,可使用包内命令生成普通态和选中态图标:
86
+
87
+ ```bash
88
+ pnpm add -D sharp
89
+
90
+ pnpm exec generate-tabbar-png House Search User \
91
+ -o ./src/assets/tabbar \
92
+ -c "#999999" \
93
+ -a "#1677ff"
94
+ ```
95
+
96
+ 生成结果:
97
+
98
+ ```text
99
+ src/assets/tabbar/
100
+ ├── House.png
101
+ ├── House-active.png
102
+ ├── Search.png
103
+ ├── Search-active.png
104
+ ├── User.png
105
+ └── User-active.png
106
+ ```
107
+
108
+ ### CLI 参数
109
+
110
+ | 参数 | 说明 |
111
+ | --- | --- |
112
+ | `<icon...>` | 一个或多个 PascalCase 图标名 |
113
+ | `-o, --out <dir>` | 输出目录,必填 |
114
+ | `--output <name>` | 单图模式的输出文件名前缀 |
115
+ | `-s, --size <n>` | PNG 尺寸,默认 `81` |
116
+ | `-c, --color <hex>` | 普通态颜色,默认 `#999999` |
117
+ | `-a, --active-color <hex>` | 选中态颜色;传入后额外生成 `-active.png` |
118
+ | `-w, --stroke-width <n>` | 描边宽度,默认 `2` |
119
+ | `-h, --help` | 显示帮助 |
120
+
121
+ 单图自定义文件名示例:
122
+
123
+ ```bash
124
+ pnpm exec generate-tabbar-png House \
125
+ -o ./src/assets/tabbar \
126
+ --output home \
127
+ -c "#999999" \
128
+ -a "#1677ff"
129
+ ```
130
+
131
+ ## 当前能力
132
+
133
+ - 以 Taro `Image` 渲染 Lucide 图标,支持 H5 与小程序构建。
134
+ - 提供完整 TypeScript 图标类型与常见 Lucide 命名别名。
135
+ - 支持单图属性和 `LucideProvider` 全局默认属性。
136
+ - 支持通过 CLI 批量生成 TabBar 普通态与选中态 PNG。
137
+ - 支持尺寸、颜色、描边宽度和单图输出文件名配置。
138
+
139
+ ## 开发与验证
140
+
141
+ ```bash
142
+ pnpm build
143
+ pnpm test
144
+ pnpm pack:local
145
+ ```
146
+
147
+ `dist/` 是该包直接发布的源码产物。修改图标导出或 TabBar 工具后,需要同步验证 `dist/lucide-taro.mjs`、`dist/lucide-taro.d.ts`、`dist/iconNodes.mjs` 与 `dist/generate-tabbar-png.mjs`。
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @license lucide-taro v0.0.1 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import{mkdir as h,writeFile as v}from"fs/promises";import{isAbsolute as z,resolve as p,dirname as $}from"path";import{zM as W,zN as x}from"./iconNodes.mjs";const s={xmlns:"http://www.w3.org/2000/svg",size:24,viewBox:"0 0 24 24",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};function H(u){return u.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function L(u){return u==="viewBox"?u:H(u)}function w(u){return Object.entries(u).map(([t,e])=>`${L(t)}="${P(e)}"`).join(" ")}function P(u){return String(u).replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function C(u,t={}){const e=t.size??s.size,r=t.color??"#000",o=t.strokeWidth??s.strokeWidth,i={xmlns:s.xmlns,width:e,height:e,viewBox:s.viewBox,fill:s.fill,stroke:r,strokeWidth:o,strokeLinecap:s.strokeLinecap,strokeLinejoin:s.strokeLinejoin},n=u.map(([F,a])=>`<${F} ${w(a)} />`).join("");return`<svg ${w(i)}>${n}</svg>`}let E;async function y(){return E||(E=(async()=>{try{const u=await import("sharp"),t=u.default??u;if(typeof t!="function")throw new Error("unexpected sharp export");return t}catch{throw new Error(`[lucide-taro] \u9700\u8981 sharp \u6765\u751F\u6210 PNG\u3002
9
+ \u8BF7\u5728\u5F53\u524D\u9879\u76EE\u5B89\u88C5\uFF1A
10
+ pnpm add -D sharp`)}})()),E}async function g(u,t={}){let e=(await y())(Buffer.from(u));t.size&&(e=e.resize(t.size,t.size));const r=await e.png().toBuffer();return new Uint8Array(r)}function S(u){let t=u;return t.startsWith("Lucide")&&(t=t.slice(6)),t.endsWith("Icon")&&(t=t.slice(0,-4)),x[t]??t}function N(u){const t=S(u),e=W[t];if(!e)throw new Error(`[lucide-taro] \u672A\u627E\u5230\u56FE\u6807 "${u}"\u3002\u8BF7\u4F7F\u7528\u4E0E lucide-taro \u5BFC\u51FA\u7684\u7EC4\u4EF6\u540D\u4E00\u81F4\u7684 PascalCase\uFF0C\u4F8B\u5982 'House' / 'HouseIcon' / 'LucideHouse' / 'Home'\u3002`);return e}async function A(u,t){await h($(u),{recursive:!0}),await v(u,t)}async function j(u){const t=process.cwd(),e=z(u.outDir)?u.outDir:p(t,u.outDir);await h(e,{recursive:!0});const r=[];for(const o of u.icons){const i=o.size??u.defaultSize??81,n=o.strokeWidth??u.defaultStrokeWidth??2,F=o.color??u.defaultColor??"#999999",a=o.activeColor??u.defaultActiveColor,c=o.output??o.name,B=o.activeSuffix??"-active",f=N(o.name),m=C(f,{size:i,color:F,strokeWidth:n}),D=await g(m,{size:i}),l=p(e,`${c}.png`);if(await A(l,D),r.push({icon:o.name,output:c,file:l,active:!1,size:i}),u.onProgress?.(`[lucide-taro] ${o.name} -> ${l}`),a){const b=C(f,{size:i,color:a,strokeWidth:n}),k=await g(b,{size:i}),d=p(e,`${c}${B}.png`);await A(d,k),r.push({icon:o.name,output:c,file:d,active:!0,size:i}),u.onProgress?.(`[lucide-taro] ${o.name} (active) -> ${d}`)}}return{outDir:e,entries:r}}function I(u){const t={icons:[]};for(let e=0;e<u.length;e+=1){const r=u[e],o=()=>u[++e];switch(r){case"-h":case"--help":t.help=!0;break;case"-o":case"--out":case"--out-dir":t.out=o();break;case"--output":t.output=o();break;case"-s":case"--size":t.size=Number(o());break;case"-c":case"--color":t.color=o();break;case"-a":case"--active-color":t.activeColor=o();break;case"-w":case"--stroke-width":t.strokeWidth=Number(o());break;default:if(r.startsWith("-"))throw new Error(`\u672A\u77E5\u53C2\u6570: ${r}`);t.icons.push(r)}}return t}function G(){process.stdout.write(`lucide-taro-tabbar-png
11
+
12
+ \u7528\u6CD5\uFF1A
13
+ lucide-taro-tabbar-png <icon...> [options]
14
+
15
+ \u793A\u4F8B\uFF1A
16
+ lucide-taro-tabbar-png House -o ./tabbar -c '#999999' -a '#1677ff'
17
+ lucide-taro-tabbar-png House Search User Settings -o ./tabbar -c '#999' -a '#1677ff'
18
+
19
+ \u53C2\u6570\uFF1A
20
+ <icon...> \u4E00\u4E2A\u6216\u591A\u4E2A lucide \u56FE\u6807\u540D\uFF0C\u4F7F\u7528 PascalCase\uFF0C
21
+ \u4E0E lucide-taro \u5BFC\u51FA\u7684\u7EC4\u4EF6\u540D\u4FDD\u6301\u4E00\u81F4\uFF08\u5982 House /
22
+ HouseIcon / LucideHouse / Home / LucideHome\uFF09\uFF0C
23
+ \u8F93\u51FA\u6587\u4EF6\u540D\u4F1A\u76F4\u63A5\u4F7F\u7528\u8BE5\u540D\u79F0
24
+ -o, --out <dir> \u8F93\u51FA\u76EE\u5F55\uFF0C\u5FC5\u586B
25
+ --output <name> \u4EC5\u5355\u56FE\u65F6\u751F\u6548\uFF1B\u8F93\u51FA\u6587\u4EF6\u540D\u524D\u7F00\uFF0C\u9ED8\u8BA4\u4E0E\u56FE\u6807\u540D\u76F8\u540C
26
+ -s, --size <n> PNG \u5C3A\u5BF8\uFF0C\u9ED8\u8BA4 81
27
+ -c, --color <hex> \u666E\u901A\u6001\u989C\u8272\uFF0C\u9ED8\u8BA4 '#999999'
28
+ -a, --active-color <hex> \u9009\u4E2D\u6001\u989C\u8272\uFF1B\u7ED9\u51FA\u4F1A\u989D\u5916\u751F\u6210 <name>-active.png
29
+ -w, --stroke-width <n> \u63CF\u8FB9\u5BBD\u5EA6\uFF0C\u9ED8\u8BA4 2
30
+ -h, --help \u663E\u793A\u5E2E\u52A9
31
+ `)}async function U(){const u=I(process.argv.slice(2));if(u.help||process.argv.length<=2){G();return}if(u.icons.length===0)throw new Error("\u81F3\u5C11\u4F20\u5165\u4E00\u4E2A\u56FE\u6807\u540D\uFF0C\u4F8B\u5982: lucide-taro-tabbar-png house -o ./tabbar");if(!u.out)throw new Error("\u7F3A\u5C11 --out/-o \u53C2\u6570\uFF0C\u5FC5\u987B\u6307\u5B9A\u8F93\u51FA\u76EE\u5F55");if(u.output&&u.icons.length>1)throw new Error("--output \u4EC5\u652F\u6301\u5355\u56FE\u6807\uFF1B\u6279\u91CF\u6A21\u5F0F\u4E0B\u6587\u4EF6\u540D\u5C06\u4F7F\u7528\u56FE\u6807\u540D\u672C\u8EAB");const t=u.icons.map(r=>({name:r,output:u.icons.length===1?u.output:void 0,size:u.size,color:u.color,activeColor:u.activeColor,strokeWidth:u.strokeWidth})),e=await j({outDir:u.out,icons:t,onProgress:r=>process.stdout.write(`${r}
32
+ `)});process.stdout.write(`
33
+ [lucide-taro] \u751F\u6210\u5B8C\u6210\uFF0C\u5171 ${e.entries.length} \u5F20 PNG
34
+ `),process.stdout.write(`[lucide-taro] \u8F93\u51FA\u76EE\u5F55: ${e.outDir}
35
+ `)}U().catch(u=>{process.stderr.write(`[lucide-taro] \u751F\u6210\u5931\u8D25: ${u instanceof Error?u.message:String(u)}
36
+ `),process.exit(1)});