@svp-chain-sdk/ui 0.1.5 → 0.1.6

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,329 +1,224 @@
1
- # `@svp-chain-sdk/ui` Tailwind Provider 使用指南
1
+ # @svp-chain-sdk/ui
2
2
 
3
- ## 1. 适用范围
3
+ SVP Chain SDK 的 React UI 组件包,支持 React 18+,采用 ESM 格式。
4
4
 
5
- `@svp-chain-sdk/ui` 当前的主要接入方式是 Tailwind provider:消费方把 `@svp-chain-sdk/ui/tailwind` 注册为 Tailwind 插件,然后直接在 HTML、React、Vue 或其他模板中组合 `.ui-button` 等 CSS class。
5
+ ## 1. Package 使用方式
6
6
 
7
- 这是**框架无关样式优先**的模式。包根入口同时提供可选的 React `Button`、零配置 `NoticeMarquee`、`FeedbackWidget` 和 `cn`。Tailwind provider 当前注册按钮与通知走马灯样式;不应假定它包含其他尚未实现的组件。
8
-
9
- ## 2. 从公共 npm registry 安装
10
-
11
- 该包以 npm 默认的公共 registry 为标准安装来源,无需额外指定 registry:
7
+ ### 安装
12
8
 
13
9
  ```sh
14
- npm install @svp-chain-sdk/ui
10
+ npm install @svp-chain-sdk/ui \
11
+ @rainbow-me/rainbowkit@2.2.11 \
12
+ @tanstack/react-query wagmi viem
15
13
  ```
16
14
 
17
- 消费方还需要使用 Tailwind CSS;该包的 provider 构建自 Tailwind v4,目前包本身不会把 `tailwindcss` 作为运行时依赖安装到消费项目中。
15
+ ### React 接入
18
16
 
19
- ## 3. 注册 Tailwind provider
17
+ 在应用入口导入一次 SDK RainbowKit 样式:
20
18
 
21
- 在消费项目的 Tailwind 配置中引入默认导出,并且只注册一次:
22
-
23
- ```ts
24
- // tailwind.config.ts(Tailwind v4 兼容配置)
25
- import svpUi from '@svp-chain-sdk/ui/tailwind'
19
+ ```tsx
20
+ import {
21
+ Button,
22
+ ConnectWalletButton,
23
+ FeedbackWidget,
24
+ NoticeMarquee,
25
+ SvpWalletProvider,
26
+ } from '@svp-chain-sdk/ui'
27
+ import '@svp-chain-sdk/ui/styles.css'
28
+ import '@rainbow-me/rainbowkit/styles.css'
26
29
 
27
- export default {
28
- plugins: [svpUi],
30
+ export function Root() {
31
+ return (
32
+ <SvpWalletProvider
33
+ appName="SVP App"
34
+ projectId={import.meta.env.VITE_WALLETCONNECT_PROJECT_ID}
35
+ locale="zh-CN"
36
+ >
37
+ <NoticeMarquee />
38
+ <Button>Continue</Button>
39
+ <ConnectWalletButton />
40
+ <FeedbackWidget />
41
+ </SvpWalletProvider>
42
+ )
29
43
  }
30
44
  ```
31
45
 
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
46
+ `projectId` 应来自环境变量,不要把真实 WalletConnect Project ID 提交到仓库。
51
47
 
52
- 这里使用原生元素和 `className`,不依赖包根入口的 React `Button`:
48
+ ### Tailwind Provider
53
49
 
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
- ```
50
+ ```ts
51
+ // tailwind.config.ts
52
+ import svpUi from '@svp-chain-sdk/ui/tailwind'
68
53
 
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
- // 业务逻辑
54
+ export default {
55
+ plugins: [svpUi],
87
56
  }
88
- </script>
89
57
  ```
90
58
 
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
- }
59
+ ```html
60
+ <button type="button" class="ui-button ui-button-primary">Continue</button>
61
+ <button type="button" class="ui-button ui-button-danger">Delete</button>
139
62
  ```
140
63
 
141
- 该变量目前仅被注册,现有按钮规则没有引用它。按钮实际读取的是下一节中的五个 `--color-*` 变量。
64
+ `.ui-button-primary` `.ui-button-danger` 必须与 `.ui-button` 组合使用。
142
65
 
143
- ## 7. CSS variables 自定义主题
66
+ ## 2. 支持的 API
144
67
 
145
- 在消费项目加载的 CSS 中覆盖变量即可,无需复制组件定义:
68
+ ### Button
146
69
 
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
- }
70
+ ```tsx
71
+ <Button variant="default" size="md">Continue</Button>
72
+ <Button variant="outline" size="sm">Cancel</Button>
73
+ <Button variant="destructive">Delete</Button>
74
+ <Button disabled>Disabled</Button>
75
+
76
+ <Button asChild variant="outline">
77
+ <a href="/docs">Read docs</a>
78
+ </Button>
155
79
  ```
156
80
 
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
81
+ #### ButtonProps
168
82
 
169
- `@svp-chain-sdk/ui/tailwind` 提供两个具名导出:
83
+ | 参数 | 类型 | 默认值 | 说明 |
84
+ | --- | --- | --- | --- |
85
+ | `variant` | `'default' \| 'secondary' \| 'outline' \| 'ghost' \| 'destructive'` | `'default'` | 视觉变体 |
86
+ | `size` | `'sm' \| 'md' \| 'lg' \| 'icon'` | `'md'` | 尺寸 |
87
+ | `asChild` | `boolean` | `false` | 将属性与样式传递给唯一子元素 |
88
+ | `type` | button `type` | `'button'` | 原生按钮类型 |
89
+ | `className` | `string` | 无 | 附加 class |
90
+ | 其他参数 | `React.HTMLAttributes<HTMLElement>` | 无 | 原生属性和事件 |
170
91
 
171
- - `uiButtonComponents`:当前按钮组件配置对象。
172
- - `uiNoticeMarqueeComponents`:通知走马灯的完整样式配置对象。
173
- - `uiComponents`:默认插件注册的完整组件配置,包含按钮和通知走马灯配置。
92
+ ### buttonVariants
174
93
 
175
- 如需在同一个插件中加入应用级 class,可组合 `uiComponents`:
94
+ 生成 Button class
176
95
 
177
96
  ```ts
178
- import plugin from 'tailwindcss/plugin'
179
- import { uiComponents } from '@svp-chain-sdk/ui/tailwind'
180
-
181
- const appUi = plugin(({ addComponents }) => {
182
- addComponents(uiComponents)
183
- addComponents({
184
- '.app-toolbar-button': {
185
- padding: '0.375rem 0.75rem',
186
- },
187
- })
97
+ const className = buttonVariants({
98
+ variant: 'outline',
99
+ size: 'sm',
100
+ className: 'my-button',
188
101
  })
189
-
190
- export default {
191
- plugins: [appUi],
192
- }
193
102
  ```
194
103
 
195
- 只想明确继承按钮配置时,也可以把上例中的 `uiComponents` 换成 `uiButtonComponents`。
196
-
197
- 默认插件与导出的配置对象来自同一份组件定义。请在以下两种方式中二选一,避免重复注册:
198
-
199
- 1. `plugins: [svpUi]`;或
200
- 2. 自定义 plugin 中 `addComponents(uiComponents)`。
201
-
202
- 注意:第二种方式只加入组件规则,不会自动加入默认插件通过 `addBase` 设置的 `--svp-ui-brand`。由于现有按钮规则未使用该变量,这不影响当前按钮样式;如果应用依赖该变量,应自行在 CSS 或自定义 plugin 中声明。
203
-
204
- ## 9. 常见问题
104
+ 参数与 `Button` `variant`、`size`、`className` 相同。
205
105
 
206
- ### class 写了但样式不生效
106
+ ### SvpWalletProvider
207
107
 
208
- 依次检查:
108
+ 提供 Wagmi、TanStack Query 与 RainbowKit 上下文。应用中只挂载一次。
209
109
 
210
- 1. 已安装并能解析 `@svp-chain-sdk/ui/tailwind`。
211
- 2. provider 已加入实际生效的 Tailwind 配置,且没有同时使用默认插件和自定义重复注册。
212
- 3. Tailwind 构建流程已运行,产物 CSS 已被页面加载。
213
- 4. 基础 class 与变体 class 已组合,例如 `ui-button ui-button-primary`。
214
- 5. 消费项目的 CSS 是否以更高优先级覆盖了规则。
215
- 6. 若不使用 provider,可改为导入 `@svp-chain-sdk/ui/styles.css`。它是包构建时从当前 Tailwind v4 样式入口生成并复制的 CSS,但不是 provider 按钮组件规则的替代品;不要假定导入它会生成 `.ui-button`、`.ui-button-primary` 或 `.ui-button-danger`。
110
+ ```tsx
111
+ <SvpWalletProvider
112
+ projectId={walletConnectProjectId}
113
+ appName="SVP Bridge"
114
+ locale="zh-CN"
115
+ >
116
+ <App />
117
+ </SvpWalletProvider>
118
+ ```
216
119
 
217
- ### 出现 CommonJS / `require()` 错误
120
+ #### SvpWalletProviderProps
218
121
 
219
- 包的 `package.json` 声明了 `"type": "module"`,根入口和 `./tailwind` export 只有 `import` 条件,没有 CommonJS `require` 条件。请使用 ESM:
122
+ | 参数 | 类型 | 默认值 | 说明 |
123
+ | --- | --- | --- | --- |
124
+ | `children` | `React.ReactNode` | 必填 | 应用内容 |
125
+ | `projectId` | `string` | 必填 | WalletConnect Project ID |
126
+ | `appName` | `string` | `'SVP App'` | 应用名称 |
127
+ | `locale` | RainbowKit `Locale` | `'en'` | 钱包弹窗语言 |
220
128
 
221
- ```ts
222
- import svpUi from '@svp-chain-sdk/ui/tailwind'
223
- ```
129
+ 如果应用已经自行挂载 Wagmi、QueryClient 和 RainbowKit Provider,不要再重复使用 `SvpWalletProvider`。
224
130
 
225
- 不要使用:
131
+ ### ConnectWalletButton
226
132
 
227
- ```js
228
- const svpUi = require('@svp-chain-sdk/ui/tailwind')
133
+ ```tsx
134
+ <ConnectWalletButton
135
+ labels={{
136
+ connect: '连接钱包',
137
+ wrongNetwork: '网络错误',
138
+ }}
139
+ showChain
140
+ />
229
141
  ```
230
142
 
231
- 如果工具默认把 `tailwind.config` 当作 CommonJS,请切换到它支持的 ESM 配置形式;具体文件名和配置取决于消费项目的构建工具。
143
+ #### ConnectWalletButtonProps
232
144
 
233
- ### 可以把 class 放在 `<div>` 上吗?
145
+ | 参数 | 类型 | 默认值 | 说明 |
146
+ | --- | --- | --- | --- |
147
+ | `className` | `string` | 无 | 钱包操作按钮附加 class |
148
+ | `labels.connect` | `string` | `'Connect Wallet'` | 未连接文案 |
149
+ | `labels.wrongNetwork` | `string` | `'Wrong Network'` | 错误网络文案 |
150
+ | `showChain` | `boolean` | `true` | 已连接后是否展示网络按钮 |
234
151
 
235
- 视觉上可以,但 class 不会让 `<div>` 自动获得按钮语义、键盘操作或原生禁用行为。优先使用原生 `<button type="button">`。
152
+ 组件自动处理未连接、错误网络和已连接状态。
236
153
 
237
- 若业务确实必须使用 `<div>`,至少需要自行完整实现 `role="button"`、`tabindex="0"`、Enter/Space 键盘触发、禁用语义与事件拦截。尤其要注意 `.ui-button:disabled` 不会匹配 `<div aria-disabled="true">`,provider 也不会替你实现这些交互。能使用原生按钮时不要用 `<div>` 模拟。
154
+ ### createSvpWalletConfig
238
155
 
239
- ## 10. 版本升级与发布
156
+ 创建 SDK 默认 Wagmi 配置:
240
157
 
241
- 以下命令在 `packages/ui` 目录执行,默认发布 patch 版本:
242
-
243
- ```sh
244
- npm run release
245
- npm run release:patch
246
- npm run release:minor
247
- npm run release:major
158
+ ```ts
159
+ const config = createSvpWalletConfig({
160
+ projectId: walletConnectProjectId,
161
+ appName: 'SVP App',
162
+ })
248
163
  ```
249
164
 
250
- 发布前必须先完成 `npm login`,并确认当前账号有权发布 `@svp-chain-sdk/ui`。命令按顺序执行:
165
+ | 参数 | 类型 | 默认值 | 说明 |
166
+ | --- | --- | --- | --- |
167
+ | `projectId` | `string` | 必填 | WalletConnect Project ID |
168
+ | `appName` | `string` | `'SVP App'` | 应用名称 |
251
169
 
252
- 1. `npm run build`、`npm run typecheck`、`npm run test`;任一失败都会立即停止,版本不会被修改,也不会发布。
253
- 2. 通过后使用 `npm version <type> --no-git-tag-version` 更新 `package.json`,不创建 Git commit/tag。
254
- 3. 使用 `pnpm install --lockfile-only --ignore-scripts` 同步仓库的 `pnpm-lock.yaml`,再执行 `npm publish --access public`。
255
-
256
- 首次发布或正式发布前,建议先运行完整的安全演练:
257
-
258
- ```sh
259
- npm run release -- --dry-run
260
- npm run release:minor -- --dry-run
261
- ```
170
+ 默认包含 Sepolia、SVP Testnet、Arbitrum Sepolia,以及 SVP Wallet、MetaMask、OKX、Rainbow、WalletConnect、Base Account 和 Safe。
262
171
 
263
- `--dry-run` 仍会运行 build、typecheck、test,并执行 npm 的发布包校验,但不会升级版本、写入锁文件或上传 registry。它不会验证 npm 登录权限或版本是否已被占用。正式发布前请确认 package version 尚未存在于 npm;失败时脚本会输出失败步骤和退出码,不输出 npm 配置或凭据。版本升级成功后,若锁文件同步或 npm 发布失败,版本文件可能已改变,需要人工检查后再重试;脚本不会自动回滚或覆盖工作区改动。
172
+ ### 钱包工具与常量
264
173
 
265
- `prepublishOnly` 保留为 npm 的独立发布保护,会再次运行质量检查;`release` 脚本不依赖 Git 提交或 tag。
266
-
267
- ## 11. React FeedbackWidget
174
+ | 导出 | 说明 |
175
+ | --- | --- |
176
+ | `resolveSvpProvider()` | 从 `window.ethereum` provider 列表查找 SVP Wallet |
177
+ | `resolveSvpProviderForConnection(redirect?)` | 查找 SVP Wallet;未安装时跳转下载页 |
178
+ | `svpWallet()` | RainbowKit 的 SVP Wallet 定义 |
179
+ | `svpTestnet` | SVP Testnet 链配置 |
180
+ | `walletDefaults` | 默认应用名、链和钱包分组 |
181
+ | `walletTheme` | SDK RainbowKit 主题 |
182
+ | `SVP_WALLET_DOWNLOAD_URL` | SVP Wallet Chrome Web Store 地址 |
268
183
 
269
- `FeedbackWidget` 是一个零配置 React 公共组件。其结构和样式对齐 `svp-website-frontend` 的 `.svp-contact-fab.js-contact-us`:桌面端为视口右侧垂直居中的 54px 渐变方形 FAB,560px 以下缩为 48px;点击后在新的浏览器标签页打开 Google Form。
184
+ ### FeedbackWidget
270
185
 
271
- 建议在应用最外层 Layout 或 AppShell 中只挂载一次:
186
+ 页面右侧垂直居中的悬浮入口,点击后在新标签页打开内置 Google Form。
272
187
 
273
188
  ```tsx
274
- import { FeedbackWidget } from '@svp-chain-sdk/ui'
275
- import '@svp-chain-sdk/ui/styles.css'
276
-
277
- export function AppShell() {
278
- return (
279
- <>
280
- {/* 页面与路由内容 */}
281
- <FeedbackWidget />
282
- </>
283
- )
284
- }
189
+ <FeedbackWidget />
190
+ <FeedbackWidget className="my-feedback" />
285
191
  ```
286
192
 
287
- 表单短链接由组件内部的 `GOOGLE_FORM_URL` 统一维护,消费页面无需传入地址或了解表单字段。当前源码已内置项目提供的 Google Form 地址。
288
-
289
- 组件使用带有 `target="_blank"` 和 `rel="noopener noreferrer"` 的链接打开表单,不读取、存储或转发表单内容,也不依赖 iframe 或消费站点的 `frame-src` 配置。
193
+ #### FeedbackWidgetProps
290
194
 
291
- 可选 `className` 仅用于宿主页面协调多个悬浮控件。组件使用参考项目相同的 `--svp-primary` `--svp-accent` 变量,并分别回退到 `#2563eb` 与 `#38bdf8`。
195
+ | 参数 | 类型 | 默认值 | 说明 |
196
+ | --- | --- | --- | --- |
197
+ | `className` | `string` | 无 | 附加 class |
292
198
 
293
- `FeedbackWidget` 属于包根入口的 React API,不属于 `@svp-chain-sdk/ui/tailwind` 提供的框架无关 class。
199
+ 内置地址:`https://forms.gle/6semmo55DSLtcbnw7`。链接使用 `target="_blank"` `rel="noopener noreferrer"`。
294
200
 
295
- ## 12. 当前公开入口速查
201
+ ### NoticeMarquee
296
202
 
297
- `packages/ui/package.json` 当前的 `exports` 为准:
298
-
299
- | 导入路径 | 当前内容 |
300
- | --- | --- |
301
- | `@svp-chain-sdk/ui/tailwind` | 默认 Tailwind plugin;具名 `uiButtonComponents`、`uiNoticeMarqueeComponents`、`uiComponents` |
302
- | `@svp-chain-sdk/ui` | React `Button`、零配置 `NoticeMarquee` 与 `FeedbackWidget`、相关类型和常量、`buttonVariants` 和 `cn` |
303
- | `@svp-chain-sdk/ui/styles.css` | 包构建产出的 Tailwind v4 CSS 样式入口;当前不包含 provider 的 `.ui-button*` 规则 |
203
+ 顶部居中的高层级通知浮层,默认距顶部 `100px`。默认读取 SDK 内置 IPFS JSON,根据浏览器语言选择文案,并每 5 分钟静默刷新。用户可以点击“已知晓”或关闭按钮。
304
204
 
305
- 所有 JavaScript 入口均按 ESM 使用。公开 API 之外的源码路径不属于 package exports,不应从消费项目直接导入。
306
-
307
- ## 13. React NoticeMarquee 通知走马灯
308
-
309
- `NoticeMarquee` 是零配置公共组件。业务页面只需要渲染组件,无需传入通知内容或文件地址:
205
+ - **已知晓**:记录当前完整公告快照,本轮公告不再显示;远程公告内容发生变化后会再次显示。
206
+ - **关闭**:只关闭当前页面实例,不写入 localStorage;刷新页面后仍会再次显示。
310
207
 
311
208
  ```tsx
312
- import { NoticeMarquee } from '@svp-chain-sdk/ui'
209
+ <NoticeMarquee />
313
210
 
314
- export function Layout() {
315
- return (
316
- <>
317
- <NoticeMarquee />
318
- {/* 页面内容 */}
319
- </>
320
- )
321
- }
211
+ <NoticeMarquee
212
+ url="https://example.com/notice.json"
213
+ storageKey="my-app:notice"
214
+ refreshIntervalMs={5 * 60 * 1000}
215
+ acknowledgeLabel="已知晓"
216
+ closeLabel="关闭通知"
217
+ className="my-notice"
218
+ />
322
219
  ```
323
220
 
324
- 组件默认读取 `DEFAULT_NOTICE_URL` 指向的公共 IPFS Gateway JSON。地址集中在 SDK 常量中,业务页面无需传入。组件首次加载后默认每 5 分钟静默重新请求一次,不显示 loading,也不会因一次网络失败导致页面报错。
325
-
326
- 服务端 JSON 格式:
221
+ 远程 JSON
327
222
 
328
223
  ```json
329
224
  {
@@ -333,63 +228,58 @@ export function Layout() {
333
228
  }
334
229
  ```
335
230
 
336
- 组件根据 `navigator.language` 选择 `zh`、`fr` `en`。找不到对应语言时先回退到 `en`,再回退到第一个非空字符串。内容始终按纯文本展示,不使用 `innerHTML`。
337
-
338
- 浏览器会在 `localStorage` 的 `DEFAULT_NOTICE_STORAGE_KEY` 下保存:
339
-
340
- ```json
341
- {
342
- "seenAt": 1789445000000,
343
- "content": "{\"en\":\"English notice\",\"fr\":\"Notification française\",\"zh\":\"中文通知\"}"
344
- }
345
- ```
346
-
347
- `content` 不是当前语言的展示文案,而是完整远程公告对象的 canonical JSON 快照:对象 key 会递归排序,因此属性顺序不同但内容相同的 JSON 会得到相同值。展示文本仍独立地按 `navigator.language` 选择。
231
+ 中文读取 `zh`,法语读取 `fr`,其他语言读取 `en`;缺失时回退到 `en`,再回退到第一个非空字符串。内容按纯文本渲染。组件通过 localStorage 记录完整公告快照,相同公告不重复播放。
348
232
 
349
- 规则如下:
233
+ #### NoticeMarqueeProps
350
234
 
351
- 1. 浏览器没有记录时,记录当前时间与完整公告快照,并播放当前语言文案。
352
- 2. 完整远程公告与本地快照相同时,不播放;切换浏览器语言也不会把同一公告当作新公告。
353
- 3. 任一语言或其他公告字段变化时,用当前时间和新的完整快照覆盖旧记录,并播放当前语言文案。
354
- 4. 同一页面即使意外挂载多个实例(包括 React StrictMode),同一首次公告也最多由一个实例播放。
355
- 5. 清除浏览器数据、使用无痕窗口或更换设备后,该通知会被视为首次看到。
356
- 6. `localStorage` 不可用时组件不会报错,并在本次页面中播放获取到的内容。
235
+ | 参数 | 类型 | 默认值 | 说明 |
236
+ | --- | --- | --- | --- |
237
+ | `url` | `string` | `DEFAULT_NOTICE_URL` | 远程 JSON 地址,需要允许 CORS |
238
+ | `storageKey` | `string` | `DEFAULT_NOTICE_STORAGE_KEY` | localStorage key |
239
+ | `refreshIntervalMs` | `number` | `DEFAULT_NOTICE_REFRESH_INTERVAL_MS` | 静默刷新间隔;小于等于 0 时关闭轮询 |
240
+ | `acknowledgeLabel` | `string` | `'已知晓'` | 确认按钮文案 |
241
+ | `closeLabel` | `string` | `'关闭通知'` | 关闭按钮的无障碍文案与 title |
242
+ | `className` | `string` | 无 | 附加 class |
357
243
 
358
- 使用 `NoticeMarquee` 时,消费项目可以按第 3 节注册并构建 `@svp-chain-sdk/ui/tailwind` provider,也可以直接导入 `@svp-chain-sdk/ui/styles.css`。两条样式入口都提供相同的固定宽度、走马灯动画、hover 暂停和 `prefers-reduced-motion` 规则,不要同时重复引入。
359
-
360
- 样式与 `dex-website-frontend` Footer 的 InfiniteMarquee 保持一致:可视区宽度为 `16rem`,两份相同内容首尾衔接,轨道从 `0` 平移至 `-50%`,默认周期为 `32s`,仅在 hover 时原地暂停。可通过 CSS 变量调整滚动周期:
244
+ 桌面端默认宽度最大 `42rem`、距顶部 `100px`、层级 `2147483647`,动画周期 `32s`,hover 时暂停。560px 以下改为距安全区顶部 16px 的自适应卡片并停止滚动,以保证长文本可读。动画周期可以通过 CSS 调整:
361
245
 
362
246
  ```css
363
247
  :root {
364
- --ui-notice-marquee-duration: 30s;
248
+ --ui-notice-marquee-duration: 24s;
365
249
  }
366
250
  ```
367
251
 
368
- 高级场景可以覆盖可选参数,但普通业务页面不需要传参:
252
+ | 常量 | 说明 |
253
+ | --- | --- |
254
+ | `DEFAULT_NOTICE_URL` | 默认通知 JSON 地址 |
255
+ | `DEFAULT_NOTICE_STORAGE_KEY` | 默认 localStorage key |
256
+ | `DEFAULT_NOTICE_REFRESH_INTERVAL_MS` | 默认刷新间隔 `5 * 60 * 1000` |
369
257
 
370
- ```tsx
371
- <NoticeMarquee
372
- url="https://example.com/notice.json"
373
- storageKey="my-app:notice"
374
- refreshIntervalMs={5 * 60 * 1000}
375
- />
376
- ```
258
+ ### cn
377
259
 
378
- 公开常量和类型:
260
+ 合并条件 class 并处理 Tailwind class 冲突:
379
261
 
380
262
  ```ts
381
- import {
382
- DEFAULT_NOTICE_REFRESH_INTERVAL_MS,
383
- DEFAULT_NOTICE_STORAGE_KEY,
384
- DEFAULT_NOTICE_URL,
385
- NoticeMarquee,
386
- type NoticeMarqueeProps,
387
- } from '@svp-chain-sdk/ui'
263
+ const className = cn('px-4', active && 'bg-primary', disabled && 'opacity-50')
388
264
  ```
389
265
 
390
- 服务器配置注意事项:
266
+ ```ts
267
+ cn(...inputs: ClassValue[]): string
268
+ ```
391
269
 
392
- - 跨域地址必须正确配置 CORS。
393
- - 响应必须是 JSON 对象,语言字段的值应为非空字符串。
394
- - SDK 不携带 cookie、token 或其他认证信息。
395
- - IPFS CID 对应不可变内容;发布新通知时需要更新 CID 或改用能指向最新 JSON 的稳定地址。
270
+ ### Tailwind Provider 导出
271
+
272
+ ```ts
273
+ import svpUi, {
274
+ uiButtonComponents,
275
+ uiNoticeMarqueeComponents,
276
+ uiComponents,
277
+ } from '@svp-chain-sdk/ui/tailwind'
278
+ ```
279
+
280
+ | 导出 | 说明 |
281
+ | --- | --- |
282
+ | `svpUi` | 默认 Tailwind plugin |
283
+ | `uiButtonComponents` | 按钮 class 配置 |
284
+ | `uiNoticeMarqueeComponents` | 走马灯 class 与动画配置 |
285
+ | `uiComponents` | 全部 provider 配置 |
@@ -5,14 +5,16 @@ export declare const DEFAULT_NOTICE_REFRESH_INTERVAL_MS: number;
5
5
  export type NoticeMarqueeProps = {
6
6
  /** Optional override for the SDK default multilingual JSON URL. */
7
7
  url?: string;
8
- /** Optional override for the localStorage key used to remember seen content. */
8
+ /** Optional override for the localStorage key used to remember acknowledged content. */
9
9
  storageKey?: string;
10
10
  /** Optional override for the default five-minute silent refresh interval. */
11
11
  refreshIntervalMs?: number;
12
+ acknowledgeLabel?: string;
13
+ closeLabel?: string;
12
14
  className?: string;
13
15
  };
14
16
  /**
15
- * Zero-config remote notice marquee. It shows unseen localized content once per
16
- * browser and remembers the content in localStorage.
17
+ * Fixed remote notice. Acknowledging persists the current payload; closing only
18
+ * dismisses it for the current mounted page, so a browser refresh shows it again.
17
19
  */
18
- export declare function NoticeMarquee({ url, storageKey, refreshIntervalMs, className, }?: NoticeMarqueeProps): React.JSX.Element | null;
20
+ export declare function NoticeMarquee({ url, storageKey, refreshIntervalMs, acknowledgeLabel, closeLabel, className, }?: NoticeMarqueeProps): React.JSX.Element | null;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { Button, buttonVariants, DEFAULT_NOTICE_REFRESH_INTERVAL_MS, DEFAULT_NOTICE_STORAGE_KEY, DEFAULT_NOTICE_URL, FeedbackWidget, NoticeMarquee, } from './components';
2
2
  export type { ButtonProps, FeedbackWidgetProps, NoticeMarqueeProps, } from './components';
3
3
  export { cn } from './lib/utils';
4
+ export { ConnectWalletButton, createSvpWalletConfig, resolveSvpProvider, resolveSvpProviderForConnection, SVP_WALLET_DOWNLOAD_URL, svpTestnet, svpWallet, SvpWalletProvider, walletDefaults, walletTheme, } from './wallet';
5
+ export type { ConnectWalletButtonProps, ConnectWalletLabels, CreateSvpWalletConfigOptions, SvpWalletProviderProps, SvpWalletDefaults, } from './wallet';