@svp-chain-sdk/ui 0.1.3 → 0.1.5

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  `@svp-chain-sdk/ui` 当前的主要接入方式是 Tailwind provider:消费方把 `@svp-chain-sdk/ui/tailwind` 注册为 Tailwind 插件,然后直接在 HTML、React、Vue 或其他模板中组合 `.ui-button` 等 CSS class。
6
6
 
7
- 这是**框架无关、非 React 组件优先**的模式。包根入口仍提供可选的 React `Button`、`buttonVariants` 和 `cn`,也导出 `@svp-chain-sdk/ui/styles.css` 样式入口,但它们不是本文的主要接入方式。目前 Tailwind provider 只注册按钮相关 class,不应假定它包含表单、弹窗或其他尚未实现的组件。
7
+ 这是**框架无关样式优先**的模式。包根入口同时提供可选的 React `Button`、零配置 `NoticeMarquee`、`FeedbackWidget` 和 `cn`。Tailwind provider 当前注册按钮与通知走马灯样式;不应假定它包含其他尚未实现的组件。
8
8
 
9
9
  ## 2. 从公共 npm registry 安装
10
10
 
@@ -169,7 +169,8 @@ function submit() {
169
169
  `@svp-chain-sdk/ui/tailwind` 提供两个具名导出:
170
170
 
171
171
  - `uiButtonComponents`:当前按钮组件配置对象。
172
- - `uiComponents`:默认插件注册的完整组件配置;当前它与 `uiButtonComponents` 是同一个对象。未来若增加其他组件,应优先使用 `uiComponents` 来继承完整配置。
172
+ - `uiNoticeMarqueeComponents`:通知走马灯的完整样式配置对象。
173
+ - `uiComponents`:默认插件注册的完整组件配置,包含按钮和通知走马灯配置。
173
174
 
174
175
  如需在同一个插件中加入应用级 class,可组合 `uiComponents`:
175
176
 
@@ -263,14 +264,132 @@ npm run release:minor -- --dry-run
263
264
 
264
265
  `prepublishOnly` 保留为 npm 的独立发布保护,会再次运行质量检查;`release` 脚本不依赖 Git 提交或 tag。
265
266
 
266
- ## 11. 当前公开入口速查
267
+ ## 11. React FeedbackWidget
268
+
269
+ `FeedbackWidget` 是一个零配置 React 公共组件。其结构和样式对齐 `svp-website-frontend` 的 `.svp-contact-fab.js-contact-us`:桌面端为视口右侧垂直居中的 54px 渐变方形 FAB,560px 以下缩为 48px;点击后在新的浏览器标签页打开 Google Form。
270
+
271
+ 建议在应用最外层 Layout 或 AppShell 中只挂载一次:
272
+
273
+ ```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
+ }
285
+ ```
286
+
287
+ 表单短链接由组件内部的 `GOOGLE_FORM_URL` 统一维护,消费页面无需传入地址或了解表单字段。当前源码已内置项目提供的 Google Form 地址。
288
+
289
+ 组件使用带有 `target="_blank"` 和 `rel="noopener noreferrer"` 的链接打开表单,不读取、存储或转发表单内容,也不依赖 iframe 或消费站点的 `frame-src` 配置。
290
+
291
+ 可选 `className` 仅用于宿主页面协调多个悬浮控件。组件使用参考项目相同的 `--svp-primary` 和 `--svp-accent` 变量,并分别回退到 `#2563eb` 与 `#38bdf8`。
292
+
293
+ `FeedbackWidget` 属于包根入口的 React API,不属于 `@svp-chain-sdk/ui/tailwind` 提供的框架无关 class。
294
+
295
+ ## 12. 当前公开入口速查
267
296
 
268
297
  以 `packages/ui/package.json` 当前的 `exports` 为准:
269
298
 
270
299
  | 导入路径 | 当前内容 |
271
300
  | --- | --- |
272
- | `@svp-chain-sdk/ui/tailwind` | 默认 Tailwind plugin;具名 `uiButtonComponents`、`uiComponents` |
273
- | `@svp-chain-sdk/ui` | 可选 React `Button`、`buttonVariants`、`ButtonProps` 和 `cn` |
301
+ | `@svp-chain-sdk/ui/tailwind` | 默认 Tailwind plugin;具名 `uiButtonComponents`、`uiNoticeMarqueeComponents`、`uiComponents` |
302
+ | `@svp-chain-sdk/ui` | React `Button`、零配置 `NoticeMarquee` 与 `FeedbackWidget`、相关类型和常量、`buttonVariants` 和 `cn` |
274
303
  | `@svp-chain-sdk/ui/styles.css` | 包构建产出的 Tailwind v4 CSS 样式入口;当前不包含 provider 的 `.ui-button*` 规则 |
275
304
 
276
305
  所有 JavaScript 入口均按 ESM 使用。公开 API 之外的源码路径不属于 package exports,不应从消费项目直接导入。
306
+
307
+ ## 13. React NoticeMarquee 通知走马灯
308
+
309
+ `NoticeMarquee` 是零配置公共组件。业务页面只需要渲染组件,无需传入通知内容或文件地址:
310
+
311
+ ```tsx
312
+ import { NoticeMarquee } from '@svp-chain-sdk/ui'
313
+
314
+ export function Layout() {
315
+ return (
316
+ <>
317
+ <NoticeMarquee />
318
+ {/* 页面内容 */}
319
+ </>
320
+ )
321
+ }
322
+ ```
323
+
324
+ 组件默认读取 `DEFAULT_NOTICE_URL` 指向的公共 IPFS Gateway JSON。地址集中在 SDK 常量中,业务页面无需传入。组件首次加载后默认每 5 分钟静默重新请求一次,不显示 loading,也不会因一次网络失败导致页面报错。
325
+
326
+ 服务端 JSON 格式:
327
+
328
+ ```json
329
+ {
330
+ "en": "English notice",
331
+ "zh": "中文通知",
332
+ "fr": "Notification française"
333
+ }
334
+ ```
335
+
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` 选择。
348
+
349
+ 规则如下:
350
+
351
+ 1. 浏览器没有记录时,记录当前时间与完整公告快照,并播放当前语言文案。
352
+ 2. 完整远程公告与本地快照相同时,不播放;切换浏览器语言也不会把同一公告当作新公告。
353
+ 3. 任一语言或其他公告字段变化时,用当前时间和新的完整快照覆盖旧记录,并播放当前语言文案。
354
+ 4. 同一页面即使意外挂载多个实例(包括 React StrictMode),同一首次公告也最多由一个实例播放。
355
+ 5. 清除浏览器数据、使用无痕窗口或更换设备后,该通知会被视为首次看到。
356
+ 6. `localStorage` 不可用时组件不会报错,并在本次页面中播放获取到的内容。
357
+
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 变量调整滚动周期:
361
+
362
+ ```css
363
+ :root {
364
+ --ui-notice-marquee-duration: 30s;
365
+ }
366
+ ```
367
+
368
+ 高级场景可以覆盖可选参数,但普通业务页面不需要传参:
369
+
370
+ ```tsx
371
+ <NoticeMarquee
372
+ url="https://example.com/notice.json"
373
+ storageKey="my-app:notice"
374
+ refreshIntervalMs={5 * 60 * 1000}
375
+ />
376
+ ```
377
+
378
+ 公开常量和类型:
379
+
380
+ ```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'
388
+ ```
389
+
390
+ 服务器配置注意事项:
391
+
392
+ - 跨域地址必须正确配置 CORS。
393
+ - 响应必须是 JSON 对象,语言字段的值应为非空字符串。
394
+ - SDK 不携带 cookie、token 或其他认证信息。
395
+ - IPFS CID 对应不可变内容;发布新通知时需要更新 CID 或改用能指向最新 JSON 的稳定地址。
@@ -0,0 +1,2 @@
1
+ export { Button, buttonVariants } from './button';
2
+ export type { ButtonProps } from './button';
@@ -0,0 +1,4 @@
1
+ export interface FeedbackWidgetProps {
2
+ className?: string;
3
+ }
4
+ export declare function FeedbackWidget({ className }?: FeedbackWidgetProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export { FeedbackWidget } from './feedback-widget';
2
+ export type { FeedbackWidgetProps } from './feedback-widget';
@@ -0,0 +1,6 @@
1
+ export { Button, buttonVariants } from './button';
2
+ export type { ButtonProps } from './button';
3
+ export { FeedbackWidget } from './feedback-widget';
4
+ export type { FeedbackWidgetProps } from './feedback-widget';
5
+ export { DEFAULT_NOTICE_REFRESH_INTERVAL_MS, DEFAULT_NOTICE_STORAGE_KEY, DEFAULT_NOTICE_URL, NoticeMarquee, } from './notice-marquee';
6
+ export type { NoticeMarqueeProps } from './notice-marquee';
@@ -0,0 +1,2 @@
1
+ export { DEFAULT_NOTICE_REFRESH_INTERVAL_MS, DEFAULT_NOTICE_STORAGE_KEY, DEFAULT_NOTICE_URL, NoticeMarquee, } from './notice-marquee';
2
+ export type { NoticeMarqueeProps } from './notice-marquee';
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ export declare const DEFAULT_NOTICE_URL = "https://moccasin-glad-tyrannosaurus-244.mypinata.cloud/ipfs/bafkreiavwd7xwacprggfzpdcicluvv4tzdxdfzj6brlzayxsk64upezdwa";
3
+ export declare const DEFAULT_NOTICE_STORAGE_KEY = "@svp-chain-sdk/ui:notice-marquee";
4
+ export declare const DEFAULT_NOTICE_REFRESH_INTERVAL_MS: number;
5
+ export type NoticeMarqueeProps = {
6
+ /** Optional override for the SDK default multilingual JSON URL. */
7
+ url?: string;
8
+ /** Optional override for the localStorage key used to remember seen content. */
9
+ storageKey?: string;
10
+ /** Optional override for the default five-minute silent refresh interval. */
11
+ refreshIntervalMs?: number;
12
+ className?: string;
13
+ };
14
+ /**
15
+ * Zero-config remote notice marquee. It shows unseen localized content once per
16
+ * browser and remembers the content in localStorage.
17
+ */
18
+ export declare function NoticeMarquee({ url, storageKey, refreshIntervalMs, className, }?: NoticeMarqueeProps): React.JSX.Element | null;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { Button, buttonVariants } from './button';
2
- export type { ButtonProps } from './button';
3
- export { cn } from './utils';
1
+ export { Button, buttonVariants, DEFAULT_NOTICE_REFRESH_INTERVAL_MS, DEFAULT_NOTICE_STORAGE_KEY, DEFAULT_NOTICE_URL, FeedbackWidget, NoticeMarquee, } from './components';
2
+ export type { ButtonProps, FeedbackWidgetProps, NoticeMarqueeProps, } from './components';
3
+ export { cn } from './lib/utils';