@svp-chain-sdk/ui 0.1.3
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 +276 -0
- package/dist/button.d.ts +22 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2324 -0
- package/dist/styles.css +2 -0
- package/dist/tailwind.d.ts +84 -0
- package/dist/tailwind.js +54 -0
- package/dist/utils.d.ts +2 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# `@svp-chain-sdk/ui` Tailwind Provider 使用指南
|
|
2
|
+
|
|
3
|
+
## 1. 适用范围
|
|
4
|
+
|
|
5
|
+
`@svp-chain-sdk/ui` 当前的主要接入方式是 Tailwind provider:消费方把 `@svp-chain-sdk/ui/tailwind` 注册为 Tailwind 插件,然后直接在 HTML、React、Vue 或其他模板中组合 `.ui-button` 等 CSS class。
|
|
6
|
+
|
|
7
|
+
这是**框架无关、非 React 组件优先**的模式。包根入口仍提供可选的 React `Button`、`buttonVariants` 和 `cn`,也导出 `@svp-chain-sdk/ui/styles.css` 样式入口,但它们不是本文的主要接入方式。目前 Tailwind provider 只注册按钮相关 class,不应假定它包含表单、弹窗或其他尚未实现的组件。
|
|
8
|
+
|
|
9
|
+
## 2. 从公共 npm registry 安装
|
|
10
|
+
|
|
11
|
+
该包以 npm 默认的公共 registry 为标准安装来源,无需额外指定 registry:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @svp-chain-sdk/ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
消费方还需要使用 Tailwind CSS;该包的 provider 构建自 Tailwind v4,目前包本身不会把 `tailwindcss` 作为运行时依赖安装到消费项目中。
|
|
18
|
+
|
|
19
|
+
## 3. 注册 Tailwind provider
|
|
20
|
+
|
|
21
|
+
在消费项目的 Tailwind 配置中引入默认导出,并且只注册一次:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// tailwind.config.ts(Tailwind v4 兼容配置)
|
|
25
|
+
import svpUi from '@svp-chain-sdk/ui/tailwind'
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
plugins: [svpUi],
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`@svp-chain-sdk/ui` 是 ESM-only 包,因此配置文件和构建工具必须支持 ESM `import`。注册后仍需由消费项目现有的 Tailwind 构建流程产出并加载 CSS。
|
|
33
|
+
|
|
34
|
+
## 4. 使用示例
|
|
35
|
+
|
|
36
|
+
所有样式变体都要和基础 class `.ui-button` 组合使用。单独写 `.ui-button-primary` 或 `.ui-button-danger` 只会得到颜色,不会得到布局、间距、焦点态和禁用态。
|
|
37
|
+
|
|
38
|
+
### HTML
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<button type="button" class="ui-button ui-button-primary">
|
|
42
|
+
继续
|
|
43
|
+
</button>
|
|
44
|
+
|
|
45
|
+
<button type="button" class="ui-button ui-button-danger" disabled>
|
|
46
|
+
删除
|
|
47
|
+
</button>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### React
|
|
51
|
+
|
|
52
|
+
这里使用原生元素和 `className`,不依赖包根入口的 React `Button`:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
export function Actions() {
|
|
56
|
+
return (
|
|
57
|
+
<div>
|
|
58
|
+
<button type="button" className="ui-button ui-button-primary">
|
|
59
|
+
继续
|
|
60
|
+
</button>
|
|
61
|
+
<button type="button" className="ui-button ui-button-danger">
|
|
62
|
+
删除
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Vue
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<template>
|
|
73
|
+
<div>
|
|
74
|
+
<button type="button" class="ui-button ui-button-primary" @click="submit">
|
|
75
|
+
继续
|
|
76
|
+
</button>
|
|
77
|
+
<button type="button" class="ui-button ui-button-danger" :disabled="pending">
|
|
78
|
+
删除
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script setup lang="ts">
|
|
84
|
+
const pending = false
|
|
85
|
+
function submit() {
|
|
86
|
+
// 业务逻辑
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 5. 现有 class 与组合规则
|
|
92
|
+
|
|
93
|
+
| Class / 状态 | 用途 | 组合规则 |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `.ui-button` | 按钮基础布局、尺寸、字体、过渡、键盘焦点态和原生禁用态 | 每个按钮都应使用 |
|
|
96
|
+
| `.ui-button-primary` | 主操作背景色、前景色和 hover 色 | 与 `.ui-button` 一起使用 |
|
|
97
|
+
| `.ui-button-danger` | 危险操作背景色、前景色和 hover 色 | 与 `.ui-button` 一起使用 |
|
|
98
|
+
| `.ui-button:focus-visible` | 键盘等触发的可见焦点轮廓 | 由基础 class 自动提供 |
|
|
99
|
+
| `.ui-button:disabled` | 禁止指针事件并降低透明度 | 只匹配支持 `disabled` 的元素及其真实禁用状态 |
|
|
100
|
+
| `.ui-button-primary:hover` | 主操作 hover 背景色 | 由 primary class 自动提供 |
|
|
101
|
+
| `.ui-button-danger:hover` | 危险操作 hover 背景色 | 由 danger class 自动提供 |
|
|
102
|
+
|
|
103
|
+
当前没有 `secondary`、`outline`、`ghost`、尺寸或 loading 等 provider class。不能把可选 React `buttonVariants` 所支持的变体当作 provider class 使用。
|
|
104
|
+
|
|
105
|
+
## 6. 完整样式属性表
|
|
106
|
+
|
|
107
|
+
下表逐项列出 provider 当前注册的样式,数值与源码保持一致。
|
|
108
|
+
|
|
109
|
+
| 选择器 | CSS 属性 | 值 |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `.ui-button` | `display` | `inline-flex` |
|
|
112
|
+
| `.ui-button` | `align-items` | `center` |
|
|
113
|
+
| `.ui-button` | `justify-content` | `center` |
|
|
114
|
+
| `.ui-button` | `gap` | `0.5rem` |
|
|
115
|
+
| `.ui-button` | `white-space` | `nowrap` |
|
|
116
|
+
| `.ui-button` | `border-radius` | `0.375rem` |
|
|
117
|
+
| `.ui-button` | `padding` | `0.5rem 1rem` |
|
|
118
|
+
| `.ui-button` | `font-size` | `0.875rem` |
|
|
119
|
+
| `.ui-button` | `line-height` | `1.25rem` |
|
|
120
|
+
| `.ui-button` | `font-weight` | `500` |
|
|
121
|
+
| `.ui-button` | `transition` | `background-color 150ms, color 150ms, border-color 150ms, opacity 150ms` |
|
|
122
|
+
| `.ui-button:focus-visible` | `outline` | `2px solid var(--color-ring, #159bb5)` |
|
|
123
|
+
| `.ui-button:focus-visible` | `outline-offset` | `2px` |
|
|
124
|
+
| `.ui-button:disabled` | `pointer-events` | `none` |
|
|
125
|
+
| `.ui-button:disabled` | `opacity` | `0.5` |
|
|
126
|
+
| `.ui-button-primary` | `background-color` | `var(--color-primary, #159bb5)` |
|
|
127
|
+
| `.ui-button-primary` | `color` | `var(--color-primary-foreground, white)` |
|
|
128
|
+
| `.ui-button-primary:hover` | `background-color` | `color-mix(in srgb, var(--color-primary, #159bb5) 90%, transparent)` |
|
|
129
|
+
| `.ui-button-danger` | `background-color` | `var(--color-destructive, #e5484d)` |
|
|
130
|
+
| `.ui-button-danger` | `color` | `var(--color-destructive-foreground, white)` |
|
|
131
|
+
| `.ui-button-danger:hover` | `background-color` | `color-mix(in srgb, var(--color-destructive, #e5484d) 90%, transparent)` |
|
|
132
|
+
|
|
133
|
+
默认插件还通过 Tailwind `addBase` 注册:
|
|
134
|
+
|
|
135
|
+
```css
|
|
136
|
+
:root {
|
|
137
|
+
--svp-ui-brand: #159bb5;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
该变量目前仅被注册,现有按钮规则没有引用它。按钮实际读取的是下一节中的五个 `--color-*` 变量。
|
|
142
|
+
|
|
143
|
+
## 7. 用 CSS variables 自定义主题
|
|
144
|
+
|
|
145
|
+
在消费项目加载的 CSS 中覆盖变量即可,无需复制组件定义:
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
:root {
|
|
149
|
+
--color-primary: #006adc;
|
|
150
|
+
--color-primary-foreground: white;
|
|
151
|
+
--color-destructive: #d13415;
|
|
152
|
+
--color-destructive-foreground: white;
|
|
153
|
+
--color-ring: #006adc;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| 变量 | 使用位置 | 未设置时的 fallback |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `--color-primary` | primary 背景、primary hover 混色 | `#159bb5` |
|
|
160
|
+
| `--color-primary-foreground` | primary 文本 | `white` |
|
|
161
|
+
| `--color-destructive` | danger 背景、danger hover 混色 | `#e5484d` |
|
|
162
|
+
| `--color-destructive-foreground` | danger 文本 | `white` |
|
|
163
|
+
| `--color-ring` | `focus-visible` 轮廓 | `#159bb5` |
|
|
164
|
+
|
|
165
|
+
变量遵循普通 CSS 级联规则,也可以在某个容器上覆盖以实现局部主题。hover 使用 CSS `color-mix()`;目标浏览器需要支持该能力。
|
|
166
|
+
|
|
167
|
+
## 8. 扩展自定义 plugin
|
|
168
|
+
|
|
169
|
+
`@svp-chain-sdk/ui/tailwind` 提供两个具名导出:
|
|
170
|
+
|
|
171
|
+
- `uiButtonComponents`:当前按钮组件配置对象。
|
|
172
|
+
- `uiComponents`:默认插件注册的完整组件配置;当前它与 `uiButtonComponents` 是同一个对象。未来若增加其他组件,应优先使用 `uiComponents` 来继承完整配置。
|
|
173
|
+
|
|
174
|
+
如需在同一个插件中加入应用级 class,可组合 `uiComponents`:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import plugin from 'tailwindcss/plugin'
|
|
178
|
+
import { uiComponents } from '@svp-chain-sdk/ui/tailwind'
|
|
179
|
+
|
|
180
|
+
const appUi = plugin(({ addComponents }) => {
|
|
181
|
+
addComponents(uiComponents)
|
|
182
|
+
addComponents({
|
|
183
|
+
'.app-toolbar-button': {
|
|
184
|
+
padding: '0.375rem 0.75rem',
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
export default {
|
|
190
|
+
plugins: [appUi],
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
只想明确继承按钮配置时,也可以把上例中的 `uiComponents` 换成 `uiButtonComponents`。
|
|
195
|
+
|
|
196
|
+
默认插件与导出的配置对象来自同一份组件定义。请在以下两种方式中二选一,避免重复注册:
|
|
197
|
+
|
|
198
|
+
1. `plugins: [svpUi]`;或
|
|
199
|
+
2. 自定义 plugin 中 `addComponents(uiComponents)`。
|
|
200
|
+
|
|
201
|
+
注意:第二种方式只加入组件规则,不会自动加入默认插件通过 `addBase` 设置的 `--svp-ui-brand`。由于现有按钮规则未使用该变量,这不影响当前按钮样式;如果应用依赖该变量,应自行在 CSS 或自定义 plugin 中声明。
|
|
202
|
+
|
|
203
|
+
## 9. 常见问题
|
|
204
|
+
|
|
205
|
+
### class 写了但样式不生效
|
|
206
|
+
|
|
207
|
+
依次检查:
|
|
208
|
+
|
|
209
|
+
1. 已安装并能解析 `@svp-chain-sdk/ui/tailwind`。
|
|
210
|
+
2. provider 已加入实际生效的 Tailwind 配置,且没有同时使用默认插件和自定义重复注册。
|
|
211
|
+
3. Tailwind 构建流程已运行,产物 CSS 已被页面加载。
|
|
212
|
+
4. 基础 class 与变体 class 已组合,例如 `ui-button ui-button-primary`。
|
|
213
|
+
5. 消费项目的 CSS 是否以更高优先级覆盖了规则。
|
|
214
|
+
6. 若不使用 provider,可改为导入 `@svp-chain-sdk/ui/styles.css`。它是包构建时从当前 Tailwind v4 样式入口生成并复制的 CSS,但不是 provider 按钮组件规则的替代品;不要假定导入它会生成 `.ui-button`、`.ui-button-primary` 或 `.ui-button-danger`。
|
|
215
|
+
|
|
216
|
+
### 出现 CommonJS / `require()` 错误
|
|
217
|
+
|
|
218
|
+
包的 `package.json` 声明了 `"type": "module"`,根入口和 `./tailwind` export 只有 `import` 条件,没有 CommonJS `require` 条件。请使用 ESM:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import svpUi from '@svp-chain-sdk/ui/tailwind'
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
不要使用:
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
const svpUi = require('@svp-chain-sdk/ui/tailwind')
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
如果工具默认把 `tailwind.config` 当作 CommonJS,请切换到它支持的 ESM 配置形式;具体文件名和配置取决于消费项目的构建工具。
|
|
231
|
+
|
|
232
|
+
### 可以把 class 放在 `<div>` 上吗?
|
|
233
|
+
|
|
234
|
+
视觉上可以,但 class 不会让 `<div>` 自动获得按钮语义、键盘操作或原生禁用行为。优先使用原生 `<button type="button">`。
|
|
235
|
+
|
|
236
|
+
若业务确实必须使用 `<div>`,至少需要自行完整实现 `role="button"`、`tabindex="0"`、Enter/Space 键盘触发、禁用语义与事件拦截。尤其要注意 `.ui-button:disabled` 不会匹配 `<div aria-disabled="true">`,provider 也不会替你实现这些交互。能使用原生按钮时不要用 `<div>` 模拟。
|
|
237
|
+
|
|
238
|
+
## 10. 版本升级与发布
|
|
239
|
+
|
|
240
|
+
以下命令在 `packages/ui` 目录执行,默认发布 patch 版本:
|
|
241
|
+
|
|
242
|
+
```sh
|
|
243
|
+
npm run release
|
|
244
|
+
npm run release:patch
|
|
245
|
+
npm run release:minor
|
|
246
|
+
npm run release:major
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
发布前必须先完成 `npm login`,并确认当前账号有权发布 `@svp-chain-sdk/ui`。命令按顺序执行:
|
|
250
|
+
|
|
251
|
+
1. `npm run build`、`npm run typecheck`、`npm run test`;任一失败都会立即停止,版本不会被修改,也不会发布。
|
|
252
|
+
2. 通过后使用 `npm version <type> --no-git-tag-version` 更新 `package.json`,不创建 Git commit/tag。
|
|
253
|
+
3. 使用 `pnpm install --lockfile-only --ignore-scripts` 同步仓库的 `pnpm-lock.yaml`,再执行 `npm publish --access public`。
|
|
254
|
+
|
|
255
|
+
首次发布或正式发布前,建议先运行完整的安全演练:
|
|
256
|
+
|
|
257
|
+
```sh
|
|
258
|
+
npm run release -- --dry-run
|
|
259
|
+
npm run release:minor -- --dry-run
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`--dry-run` 仍会运行 build、typecheck、test,并执行 npm 的发布包校验,但不会升级版本、写入锁文件或上传 registry。它不会验证 npm 登录权限或版本是否已被占用。正式发布前请确认 package version 尚未存在于 npm;失败时脚本会输出失败步骤和退出码,不输出 npm 配置或凭据。版本升级成功后,若锁文件同步或 npm 发布失败,版本文件可能已改变,需要人工检查后再重试;脚本不会自动回滚或覆盖工作区改动。
|
|
263
|
+
|
|
264
|
+
`prepublishOnly` 保留为 npm 的独立发布保护,会再次运行质量检查;`release` 脚本不依赖 Git 提交或 tag。
|
|
265
|
+
|
|
266
|
+
## 11. 当前公开入口速查
|
|
267
|
+
|
|
268
|
+
以 `packages/ui/package.json` 当前的 `exports` 为准:
|
|
269
|
+
|
|
270
|
+
| 导入路径 | 当前内容 |
|
|
271
|
+
| --- | --- |
|
|
272
|
+
| `@svp-chain-sdk/ui/tailwind` | 默认 Tailwind plugin;具名 `uiButtonComponents`、`uiComponents` |
|
|
273
|
+
| `@svp-chain-sdk/ui` | 可选 React `Button`、`buttonVariants`、`ButtonProps` 和 `cn` |
|
|
274
|
+
| `@svp-chain-sdk/ui/styles.css` | 包构建产出的 Tailwind v4 CSS 样式入口;当前不包含 provider 的 `.ui-button*` 规则 |
|
|
275
|
+
|
|
276
|
+
所有 JavaScript 入口均按 ESM 使用。公开 API 之外的源码路径不属于 package exports,不应从消费项目直接导入。
|
package/dist/button.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
3
|
+
export declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
|
|
5
|
+
size?: "sm" | "md" | "lg" | "icon" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
type ButtonBaseProps = VariantProps<typeof buttonVariants> & {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type ButtonProps = ButtonBaseProps & React.HTMLAttributes<HTMLElement> & {
|
|
11
|
+
type?: React.ButtonHTMLAttributes<HTMLButtonElement>['type'];
|
|
12
|
+
};
|
|
13
|
+
/** With `asChild`, the ref targets the slotted child, which may not be a button. */
|
|
14
|
+
export declare const Button: React.ForwardRefExoticComponent<VariantProps<(props?: ({
|
|
15
|
+
variant?: "default" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
|
|
16
|
+
size?: "sm" | "md" | "lg" | "icon" | null | undefined;
|
|
17
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string> & {
|
|
18
|
+
asChild?: boolean;
|
|
19
|
+
} & React.HTMLAttributes<HTMLElement> & {
|
|
20
|
+
type?: React.ButtonHTMLAttributes<HTMLButtonElement>["type"];
|
|
21
|
+
} & React.RefAttributes<HTMLElement>>;
|
|
22
|
+
export {};
|
package/dist/index.d.ts
ADDED