weifuwu 0.78.0 → 0.80.0

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.
Files changed (84) hide show
  1. package/README.md +12 -11
  2. package/dist/ai/client.d.ts +1 -1
  3. package/dist/ai/sse.d.ts +1 -1
  4. package/dist/ai/types.d.ts +2 -2
  5. package/dist/components/AlertGroup/AlertGroup.d.ts +1 -1
  6. package/dist/components/Anchor/Anchor.d.ts +1 -1
  7. package/dist/components/AuthPage/AuthPage.d.ts +36 -0
  8. package/dist/components/AutoComplete/AutoComplete.d.ts +3 -1
  9. package/dist/components/AvatarGroup/AvatarGroup.d.ts +1 -1
  10. package/dist/components/Calendar/Calendar.d.ts +1 -1
  11. package/dist/components/Carousel/Carousel.d.ts +1 -1
  12. package/dist/components/Cascader/Cascader.d.ts +1 -1
  13. package/dist/components/ChatInput/ChatInput.d.ts +61 -0
  14. package/dist/components/ColorPicker/ColorPicker.d.ts +1 -1
  15. package/dist/components/DatePicker/DatePicker.d.ts +2 -0
  16. package/dist/components/FloatButton/FloatButton.d.ts +1 -1
  17. package/dist/components/Grid/Grid.d.ts +1 -1
  18. package/dist/components/Input/Input.d.ts +2 -0
  19. package/dist/components/InputNumber/InputNumber.d.ts +1 -1
  20. package/dist/components/JSONViewer/JSONViewer.d.ts +1 -1
  21. package/dist/components/Link/Link.d.ts +1 -1
  22. package/dist/components/LogViewer/LogViewer.d.ts +1 -1
  23. package/dist/components/Markdown/parser.d.ts +1 -1
  24. package/dist/components/Mentions/Mentions.d.ts +1 -1
  25. package/dist/components/Menu/Menu.d.ts +1 -1
  26. package/dist/components/Menubar/Menubar.d.ts +1 -1
  27. package/dist/components/MessageBubble/MessageBubble.d.ts +1 -1
  28. package/dist/components/NavMenu/NavMenu.d.ts +1 -1
  29. package/dist/components/Popconfirm/Popconfirm.d.ts +1 -1
  30. package/dist/components/Result/Result.d.ts +1 -1
  31. package/dist/components/Scrollbar/Scrollbar.d.ts +1 -1
  32. package/dist/components/SearchInput/SearchInput.d.ts +1 -0
  33. package/dist/components/Slider/Slider.d.ts +1 -0
  34. package/dist/components/TagsInput/TagsInput.d.ts +1 -1
  35. package/dist/components/Timeline/Timeline.d.ts +1 -1
  36. package/dist/components/Transfer/Transfer.d.ts +1 -1
  37. package/dist/components/TreeSelect/TreeSelect.d.ts +2 -0
  38. package/dist/components/VirtualList/VirtualList.d.ts +3 -1
  39. package/dist/components/VirtualTable/VirtualTable.d.ts +1 -1
  40. package/dist/components/Watermark/Watermark.d.ts +1 -1
  41. package/dist/components/index.d.ts +4 -0
  42. package/dist/components/index.js +12 -12
  43. package/dist/components/style.css +77 -23
  44. package/dist/index.js +166 -149
  45. package/dist/ui-dom/ai.d.ts +1 -1
  46. package/dist/ui-dom/context.d.ts +32 -0
  47. package/dist/ui-dom/index.d.ts +9 -9
  48. package/dist/ui-dom/index.js +11 -11
  49. package/dist/ui-dom/jsx-runtime.js +1 -1
  50. package/dist/ui-dom/{vdom → middleware}/serve.d.ts +5 -8
  51. package/dist/ui-dom/testing.js +1 -1
  52. package/dist/ui-dom/use-chat.d.ts +1 -1
  53. package/dist/ui-dom/{vdom → vdom2}/audit.d.ts +5 -5
  54. package/dist/ui-dom/{vdom → vdom2}/build.d.ts +5 -5
  55. package/dist/ui-dom/vdom2/ctx.d.ts +32 -0
  56. package/dist/ui-dom/vdom2/hydrate.d.ts +13 -0
  57. package/dist/ui-dom/vdom2/index.d.ts +13 -0
  58. package/dist/ui-dom/vdom2/kind.d.ts +35 -0
  59. package/dist/ui-dom/vdom2/mount.d.ts +63 -0
  60. package/dist/ui-dom/vdom2/patch.d.ts +47 -0
  61. package/dist/ui-dom/vdom2/render.d.ts +19 -0
  62. package/dist/ui-dom/vdom2/ssr.d.ts +32 -0
  63. package/dist/ui-dom/vdom2/trace.d.ts +52 -0
  64. package/dist/ui-dom/{vdom → vdom2}/transform.d.ts +22 -1
  65. package/dist/ui-dom/vdom2/transitions.d.ts +23 -0
  66. package/dist/ui-dom/vdom2/x2html.d.ts +23 -0
  67. package/dist/ui-dom/vnode.d.ts +64 -67
  68. package/docs/ai-contract.md +418 -0
  69. package/docs/components-map.md +7 -5
  70. package/docs/components.md +6 -3
  71. package/docs/frontend-ui-dom.md +2 -2
  72. package/docs/frontend.md +2 -2
  73. package/docs/layout.md +1 -1
  74. package/docs/mobile.md +1 -1
  75. package/docs/saas.md +2 -2
  76. package/docs/style-guide.md +182 -0
  77. package/package.json +1 -1
  78. package/dist/ui-dom/vdom/diff.d.ts +0 -33
  79. package/dist/ui-dom/vdom/hydration.d.ts +0 -17
  80. package/dist/ui-dom/vdom/index.d.ts +0 -23
  81. package/dist/ui-dom/vdom/mount.d.ts +0 -58
  82. package/dist/ui-dom/vdom/render.d.ts +0 -17
  83. package/dist/ui-dom/vdom/ssr.d.ts +0 -44
  84. /package/dist/ui-dom/{vdom → vdom2}/registry.d.ts +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 本页为 weifuwu 官方文档拆分页 · [返回 README](../README.md)
4
4
 
5
- 113 个 HTML 原语组件。每个是 `async (initProps, ctx) => (props) => Promise<VNode>`(两阶段组件,与前端框架同一模型——外层工厂 + 内层 renderFn 强制异步),引用 `--wf-*` CSS 变量做主题。另含 `confirm()` / `toast()` 命令式中间件。
5
+ 115 个 HTML 原语组件。每个是 `async (initProps, ctx) => (props) => Promise<VNode>`(两阶段组件,与前端框架同一模型——外层工厂 + 内层 renderFn 强制异步),引用 `--wf-*` CSS 变量做主题。另含 `confirm()` / `toast()` 命令式中间件。
6
6
 
7
7
  > **组件速查(weifuwu 组件 ↔ antd / Element Plus / shadcn-ui 对应 + 迁移示例)**:见 [`docs/components-map.md`](components-map.md)——从其他组件库迁来的开发者按功能直接找对应组件。
8
8
  > **自定义组件开发**:见 [docs/custom-components.md](custom-components.md)——usePopup/useControlled/对话框/AI 组件/类型纪律逐步指南。
@@ -301,6 +301,7 @@ props 变化 ──────────────────────
301
301
  | `onChange` | `(value: string) => void` | — |
302
302
  | `placeholder` | `string` | — |
303
303
  | `disabled` | `boolean` | — |
304
+ | `error` | `string` | 错误态——输入框错误样式 + aria-invalid(F2 状态矩阵) |
304
305
 
305
306
  ### Form(表单增强)
306
307
  | Prop | 类型 | 说明 |
@@ -614,7 +615,7 @@ props 变化 ──────────────────────
614
615
  | ContextMenu | `ContextMenu` | `items: ContextMenuItem[]`(`{ label, onClick, variant: 'danger' }`) | 右键菜单(光标定位 + 方向键) |
615
616
  | Mentions | `Mentions` | `options: { value, label }[]`, `value`, `onChange`, `prefix` | @提及(composition 抑制) |
616
617
  | Collapse | `Collapse` | `items: CollapseItem[]`(`{ key, title, content, loading }`), `active`, `multiple` | 行内折叠(异步 loading) |
617
- | Tree | `Tree` | `data: TreeNode[]`, `expandedKeys`, `checkedKeys`, `checkable`, `selectedKeys`, `onCheck/onExpand/onSelect` | 树(递归 + 勾选父子联动 + 半选传播) |
618
+ | Tree | `Tree` | `data: TreeNode[]`, `expandedKeys`, `checkedKeys`, `checkable`, `selectedKeys`, `onCheck/onExpand/onSelect` | 树(递归 + 勾选父子联动 + 半选传播;空数据「暂无数据」) |
618
619
  | Cascader | `Cascader` | `options: CascaderOption[]`, `value: string[]`, `onChange` | 级联选择(多列推进) |
619
620
  | Transfer | `Transfer` | `data: { key, label }[]`, `targetKeys`, `onChange`, `titles` | 穿梭框(选中 + 批量移动) |
620
621
  | Command | `Command` | `items: CommandItem[]`, `open`, `onOpenChange`, `shortcut` | 命令面板(⌘K 全局 + 键盘流) |
@@ -623,7 +624,7 @@ props 变化 ──────────────────────
623
624
  | Resizable | `Resizable` | `direction`, `defaultSize`, `min/maxSize` | 拖拽分割面板(pointer + 键盘方向键) |
624
625
  | Calendar | `Calendar` | `month`, `year`, `events`, `selectedDate`, `onMonthChange/onSelectDate` | 月历(事件点 + 月切换 + 选日) |
625
626
  | Watermark | `Watermark` | `text`, `fontSize`, `rotate`, `zIndex` | 水印(canvas 平铺) |
626
- | VirtualList | `VirtualList` | `items`, `height`, `itemHeight`, `renderItem`, `overscan` | 虚拟列表(spacer + 可见窗口,1000+ 条) |
627
+ | VirtualList | `VirtualList` | `items`, `height`, `itemHeight`, `renderItem`, `overscan`, `emptyText` | 虚拟列表(spacer + 可见窗口,1000+ 条;空态占位) |
627
628
  | InfiniteScroll | `InfiniteScroll` | `hasMore`, `loadMore`, `children`, `loader` | 触底加载(IntersectionObserver) |
628
629
  | QRCode | `QRCode` | `value`, `ecLevel`, `size`, `color`, `bgColor` | 二维码(自研 Reed-Solomon,版本 1-6) |
629
630
 
@@ -640,12 +641,14 @@ props 变化 ──────────────────────
640
641
  | 组件 | 导入名 | 关键 Props | 说明 |
641
642
  |-----|--------|-----------|------|
642
643
  | Divider | `Divider` | `vertical` | 分割线(水平带文字放 children,`vertical` 垂直) |
644
+ | AuthPage | `AuthPage` | `title`, `subtitle?`, `logo?`, `children`, `footer?`, `submitLabel`, `loading?`, `error?`, `onSubmit?` | 认证页骨架:居中卡片 + logo + 标题/副标题 + 表单插槽 + 错误条 + 提交 loading + 底部链接(登录/注册复用;认证流程/跳转由消费方提供) |
643
645
 
644
646
  ### AI 交互原语(wf: 协议配套)
645
647
 
646
648
  | 组件 | 导入名 | 关键 Props | 说明 |
647
649
  |-----|--------|-----------|------|
648
650
  | AiChat | `AiChat` | `chat`, `maxHeight?`, `labels?`, `renderMessage?`, `renderToolArgs?` | 标准 AI 对话界面:气泡 + 工具卡 + 审批卡 + 自动滚动 + 错误重试(接收 `ctx.ui.useChat()` handle) |
651
+ | ChatInput | `ChatInput` | `value`, `onChange`, `onSend`, `streaming?`, `onStop?`, `error?`, `onRetry?`, `multiline?`, `actions?` | 独立聊天输入条(AiChat 抽取):单行/多行(Enter 发送/Shift+Enter 换行)+ streaming 停止切换 + §5.3 IME 受控输入纪律——纯输入层,聊天逻辑(useChat)由消费方组合 |
649
652
  | MessageBubble | `MessageBubble` | `content`, `role`, `status`, `actions` | 独立消息气泡(业务聊天页复用) |
650
653
  | ToolCallCard | `ToolCallCard` | `call`, `progress?`, `result?`, `renderArgs?` | 工具调用卡片:running(进度条)/ ok / error 三态(协议 §4) |
651
654
  | JsonSchemaForm | `JsonSchemaForm` | `schema`, `value?`, `onChange?`, `onSubmit?`, `submitLabel?` | JSON Schema(对象子集)→ 参数输入表单:类型映射 + required/范围校验 + 嵌套/数组(工具参数输入面;不支持项告警降级) |
@@ -31,7 +31,7 @@ const Counter = async (initProps, ctx) => {
31
31
  ```
32
32
 
33
33
  - **没有 hooks 规则、没有依赖数组、没有闭包陷阱**。外层 = 初始化(一次),内层 = 渲染(每次变化)。
34
- - **render-only 确定性渲染**(design/render-only-plan.md):渲染只发生在 `ctx.ui.render()` 调用处——改状态后显式 `render()`,行为可静态推导。无 `$` Proxy、无隐式触发;跨组件共享用 `createStore` + `ctx.ui.useExternal()`。
34
+ - **render-only 确定性渲染**:渲染只发生在 `ctx.ui.render()` 调用处——改状态后显式 `render()`,行为可静态推导。无 `$` Proxy、无隐式触发;跨组件共享用 `createStore` + `ctx.ui.useExternal()`。
35
35
 
36
36
  ### 框架即纪律:浏览器环境抽象把常见坑变成编译期/审计期错误
37
37
 
@@ -42,7 +42,7 @@ const Counter = async (initProps, ctx) => {
42
42
 
43
43
  - **零 npm 运行时依赖**(对比 React + react-dom + react-router + 状态库 + SSR 工具 5+ 依赖)。
44
44
  - **自研 VDOM/diff**(keyed children、style diff、CSS 变量、Portal、hydration 游标收养)——每个算法都有对应测试与纪律条目(真实事故沉淀)。**读源码即可完全理解框架行为**。
45
- - **VDOM 对开发者透明(占位法 + 单一规则源)**:写 JSX → 看 DOM 即真相——`data-wf-key`(数组项身份,元素/组件一致)、`data-wf-id`(组件实例身份)、`<!--wf-hole: xxx-->`(条件渲染 false 的占位注释)直接在 DOM 可见;非法输入(对象/数字 type)→ 诊断占位 + warn,不崩溃不静默;`?vdom_debug=1` 开启 patch trace + 结构 audit。**转化路径唯一清晰、无 magic、可推导**(规则表:design/vdom-transform-rules.md)
45
+ - **VDOM 对开发者透明(占位法 + 单一规则源)**:写 JSX → 看 DOM 即真相——`data-wf-key`(数组项身份,元素/组件一致)、`data-wf-id`(组件实例身份)、`<!--wf-hole: xxx-->`(条件渲染 false 的占位注释)直接在 DOM 可见;非法输入(对象/数字 type)→ 诊断占位 + warn,不崩溃不静默;`?vdom_debug=1` 开启 patch trace + 结构 audit。**转化路径唯一清晰、无 magic、可推导**(规则表为内部开发契约)
46
46
  - **零构建步骤**:`weifuwu/dev` loader + `ctx.ui.js/css` 动态编译,服务端直接跑 `.tsx`,改组件刷新即生效。
47
47
 
48
48
  ### 弹层/浮层体系:最难的 UI 类别变成复用的原语
package/docs/frontend.md CHANGED
@@ -233,7 +233,7 @@ const Counter: Component = async (_init, ctx) => {
233
233
  }
234
234
  ```
235
235
 
236
- **render-only 唯一规则**:渲染只发生在 `render()` 调用处(design/render-only-plan.md)——
236
+ **render-only 唯一规则**:渲染只发生在 `render()` 调用处——
237
237
  状态是普通对象(`let` / `createStore`),**没有 `$` Proxy、没有赋值自动渲染**。改状态后必须显式 `ctx.ui.render()`。
238
238
 
239
239
  ### `createStore` + `ctx.ui.useExternal()` — 跨组件共享状态
@@ -448,7 +448,7 @@ ctx.ui.render(['stats'])
448
448
 
449
449
  #### `ctx.ui.useChat(options)` — AI 对话会话(AiChat 配套)
450
450
 
451
- 会话语义的流式 AI 状态容器:消息累积 / 工具调用内嵌 / HITL 审批 / stop / retry,协议对页面完全透明(wf: 协议见 `design/ai-contract.md`)。返回 handle 带 `subscribe(cb)`——子组件用 `ctx.ui.useExternal(chat)` 订阅会话变化(render-only 共享状态原语):
451
+ 会话语义的流式 AI 状态容器:消息累积 / 工具调用内嵌 / HITL 审批 / stop / retry,协议对页面完全透明(wf: 协议见 `docs/ai-contract.md`)。返回 handle 带 `subscribe(cb)`——子组件用 `ctx.ui.useExternal(chat)` 订阅会话变化(render-only 共享状态原语):
452
452
 
453
453
  ```tsx
454
454
  // mount 阶段(服务端 `ai()` 中间件 + `AiChat` 组件配套)
package/docs/layout.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  纯 CSS 58 个布局原语 + 136 个工具类 + 167 个主题 Token。不绑定任何 JS 框架。
6
6
 
7
- > **学习路径与命名规范**:见 [`design/style-guide.md`](../design/style-guide.md)——统一语法 `wf-<域>-<名>`、三档学习(组件 → 10 核心原语 → 完整速查)、场景速查、变量定制。
7
+ > **学习路径与命名规范**:见 [`docs/style-guide.md`](style-guide.md)——统一语法 `wf-<域>-<名>`、三档学习(组件 → 10 核心原语 → 完整速查)、场景速查、变量定制。
8
8
 
9
9
  > **全栈 weifuwu 项目**:`weifuwu/components/style.css` 已包含布局系统,一条 import 就够了,无需单独引用本页。
10
10
  > 本页仅适用于**非 weifuwu 项目**或**只需 CSS 布局**的场景。
package/docs/mobile.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # 移动端开发指南(weifuwu)
2
2
 
3
3
  > 移动端友好由框架构造保证:**用对原语 + 守 audit 规则**,不靠每个组件"记得"。
4
- > 落地依据:`design/mobile-support-plan.md`(P0/P1 已完成,P2 进行中)。
4
+ > 落地依据:移动端支持计划(P0-P3 全落地——usePopup 全系 + safe-area + 44px 命中区 + docs/mobile 指南)。
5
5
 
6
6
  ## 一、断点体系(布局原语)
7
7
 
package/docs/saas.md CHANGED
@@ -147,7 +147,7 @@ import { ai } from 'weifuwu'
147
147
  const a = ai() // DEEPSEEK_API_KEY / BASE_URL / MODEL 自动读 env,默认 deepseek-v4-flash
148
148
  app.use(a) // 注入 ctx.ai(worker/非请求场景也可直接 a.chat())
149
149
 
150
- // 流式对话:路由一行返回 SSE(wf: 协议,详见 design/ai-contract.md)
150
+ // 流式对话:路由一行返回 SSE(wf: 协议,详见 docs/ai-contract.md)
151
151
  app.post('/api/chat', async (req, ctx) => {
152
152
  const { messages } = await req.json()
153
153
  return ctx.ai.stream({ messages }, {
@@ -217,7 +217,7 @@ return () => <AiChat chat={$} />
217
217
 
218
218
  > 分层:`ctx.ai`(后端协议)→ `aiStream`(传输解码)→ `useChat`(会话语义)→ `AiChat`(标准界面)。要完全自定义 UI 的应用用 useChat + 自有渲染;要 5 分钟出界面用 AiChat。
219
219
 
220
- - **协议**:`wf:` 命名空间(message_start/token/tool_call/tool_progress/usage/done/error + agent 扩展 step/approval_request),SSE 下行 + POST 上行,错误即值、未知事件透传、`x:*` 自定义事件(详见 [design/ai-contract.md](../design/ai-contract.md))
220
+ - **协议**:`wf:` 命名空间(message_start/token/tool_call/tool_progress/usage/done/error + agent 扩展 step/approval_request),SSE 下行 + POST 上行,错误即值、未知事件透传、`x:*` 自定义事件(详见 [docs/ai-contract.md](ai-contract.md))
221
221
  - **agent 引擎**:`a.agent({ systemPrompt, tools, humanInTheLoop })` 工具循环(LLM → tool_call → 执行 → 回喂 → 重复);工具可 `emit` 进度/自定义事件、接收 `signal` 取消;HITL 审批(`ctx.ai.approve` 响应,拒绝≠终止、modified 改参、超时兜底)
222
222
  - **emitter 抽象**:`agent.stream(messages, { emit })`——`wf:*` 事件(step/token/tool_result/usage/done)可接任意通道(SSE/WS/回调),协议不焊死在传输层;`agent.runToResult(messages)` 返回结构化结果 `{ content, steps, usage }`(非流式/worker 场景)
223
223
  - **embedding**:`ctx.ai.embed(text)` / `embedMany(texts)` 向量化(默认 `DASHSCOPE_API_KEY` + `text-embedding-v4`,compatible-mode 端点);未配置抛 `AiError('unsupported')`(惰性检查,不静默降级)——知识库/语义检索开箱即用
@@ -0,0 +1,182 @@
1
+ # weifuwu/style 使用指南(wf-* 命名规范 + 三档学习路径)
2
+
3
+ > 一个 CSS 文件(`weifuwu/components/style.css`)= Token + 布局原语 + 工具类 + 组件样式。
4
+ > 本文档是**学习路径**与**命名规范**——看完第二档即可上手 90% 页面。
5
+
6
+ ## 统一语法:`wf-<域>-<名字>`
7
+
8
+ 所有类遵循一个规则:`wf-` + **域** + 名字。
9
+
10
+ | 域 | 例子 | 说明 |
11
+ |---|---|---|
12
+ | `layout`(布局原语) | `wf-layout-stack` `wf-layout-split` `wf-layout-grid` | 元素之间的空间关系 |
13
+ | `p/m/gap/w/h`(间距尺寸) | `wf-p-md` `wf-mt-lg` `wf-gap-sm` `wf-w-full` | padding/margin/gap/width/height |
14
+ | `border/rounded`(边框圆角) | `wf-border-b` `wf-rounded-md` `wf-pill` | |
15
+ | `bg/text/weight/leading/align/tracking`(视觉) | `wf-bg-primary` `wf-text-secondary` `wf-weight-semibold` `wf-leading-base` | |
16
+ | `btn/card/modal/…`(组件域) | `wf-btn--primary` `wf-card--hover` | 组件由 props 渲染,一般不需手写 |
17
+
18
+ **修饰符号**:
19
+ ```
20
+ wf-card--active -- = 变体/状态(选中/激活/hover)
21
+ wf-modal-header - = 子元素(组件内部结构,不手写)
22
+ wf-layout-stack@md @ = 断点变体(≥768px 时横向)
23
+ ```
24
+
25
+ **值类(裸词)**:单值工具没有属性域——`wf-uppercase` `wf-truncate` `wf-pre-wrap` `wf-dim` `wf-pill`。
26
+
27
+ ## 三档学习路径
28
+
29
+ ### 第一档:只用组件(0 成本)
30
+
31
+ 48 个组件覆盖页面功能块,完全不需要 wf-*:
32
+
33
+ ```tsx
34
+ <PageHeader title="订单"><Button variant="primary">+ 新建</Button></PageHeader>
35
+ <Table data={orders} columns={cols} />
36
+ <Card hover><StatCard value="1,234" label="总用户" /></Card>
37
+ ```
38
+
39
+ ### 第二档:10 个核心原语(半小时,覆盖 90% 页面)
40
+
41
+ ```
42
+ wf-layout-stack 垂直堆叠 + gap
43
+ wf-layout-row 水平排列 + wrap
44
+ wf-layout-split 两端分布
45
+ wf-layout-fill flex: 1 撑满
46
+ wf-gap-md 设置间距(配合上面)
47
+ wf-p-md 内边距
48
+ wf-text-secondary 次级文字
49
+ wf-bg-primary 品牌浅底
50
+ wf-border-b 下边框
51
+ wf-rounded-md 圆角
52
+ ```
53
+
54
+ ```tsx
55
+ <div class="wf-layout-split">
56
+ <div class="wf-layout-row wf-gap-md">
57
+ <Card>…</Card>
58
+ </div>
59
+ <Button variant="primary">提交</Button>
60
+ </div>
61
+ ```
62
+
63
+ ### 第三档:完整速查(按需查 IDE 补全)
64
+
65
+ 输入 `wf-layout-` / `wf-text-` / `wf-bg-` 弹出全部候选。完整清单见 README「布局系统」。
66
+
67
+ ## 场景速查("我要做什么")
68
+
69
+ | 需求 | 写法 |
70
+ |---|---|
71
+ | 两个元素两端分布 | `wf-layout-split` |
72
+ | 一列堆叠带间距 | `wf-layout-stack wf-gap-md` |
73
+ | 一行换行居中对齐 | `wf-layout-row wf-gap-md wf-layout-cluster` |
74
+ | 卡片网格 | `<div class="wf-layout-grid">` |
75
+ | 状态色文字/背景 | `wf-text-success` / `wf-bg-error` |
76
+ | 卡片 hover 抬升 | `<Card hover>` 或 `wf-elevate` |
77
+ | 聊天气泡 | `wf-bubble` / `wf-bubble--own` |
78
+ | 文章正文排版 | `<article class="wf-prose">` |
79
+ | 隐藏元素(桌面显示/移动隐藏) | `wf-layout-hidden@sm` |
80
+ | 按钮变胶囊 | `:root { --wf-btn-radius: 999px }` |
81
+ | 数字防抖(统计/表格数值) | `wf-nums`(StatCard 已默认套用) |
82
+ | 顶级页面大标题 | `<PageHeader display>` 或 `wf-text-display` |
83
+ | 状态/计数徽章 | `<Badge variant>`(不可交互,含 dot) |
84
+ | 可关闭标签 | `<Tag closable>`(可交互,有关闭钮) |
85
+ | 图标 | `<Icon name="close" />`(禁止裸 emoji/字形) |
86
+
87
+ ## 定制(零 CSS 文件)
88
+
89
+ ### 品牌换色 — 改原始层一个值,全站跟随
90
+
91
+ ```html
92
+ <style>
93
+ :root { --wf-brand-500: #7c3aed; } /* 亮色品牌 */
94
+ :root { --wf-dark-brand-500: #a78bfa; } /* 暗色品牌(可选) */
95
+ </style>
96
+ ```
97
+
98
+ ### 组件定制 — 设一个变量
99
+
100
+ ```html
101
+ <style>
102
+ :root {
103
+ --wf-modal-width: 640px;
104
+ --wf-btn-radius: 999px;
105
+ --wf-field-height: 44px;
106
+ --wf-card-shadow: 0 8px 24px rgba(0,0,0,.12);
107
+ }
108
+ </style>
109
+ ```
110
+
111
+ 完整钩子清单:`--wf-btn-*` `--wf-card-*` `--wf-field-*` `--wf-modal-*` `--wf-drawer-width` `--wf-toast-*` `--wf-alert-radius` `--wf-badge-radius` `--wf-tag-radius` `--wf-switch-radius` `--wf-popover-*` `--wf-tooltip-radius` `--wf-dropdown-min-width` `--wf-datepicker-*`。
112
+
113
+ ### 动效定制 — 时长/缓动/位移
114
+
115
+ ```html
116
+ <style>
117
+ :root {
118
+ --wf-dur-base: 300ms; /* 默认动画时长 */
119
+ --wf-ease-out: cubic-bezier(0.22, 1, 0.36, 1); /* 入场缓动 */
120
+ --wf-motion-lg: 32px; /* 抽屉全幅位移 */
121
+ }
122
+ </style>
123
+ ```
124
+
125
+ ### 覆盖优先级(@layer)
126
+
127
+ ```
128
+ @layer tokens, base, layout, utilities, components; ← weifuwu 的层
129
+ 未分层的用户 CSS 天然最高优先级 ← 你写的普通规则直接生效
130
+ 用户 @layer utilities 可精准盖过 weifuwu 的 utilities
131
+ ```
132
+
133
+ ## 主题 Token(141 个,双层)
134
+
135
+ - **原始层**(`--wf-brand-*` `--wf-slate-*` `--wf-dark-*`):色值只定义一次,品牌/暗色调校改这里
136
+ - **语义层**(`--wf-color-*` `--wf-space-*` `--wf-radius-*` …):组件消费,主题切换覆盖这里
137
+ - 暗色模式:`--wf-dark-*` 间接层映射,两段激活(`data-theme` / 系统偏好),无硬编码
138
+
139
+ ### 动效 Token(P8 新增,全站动效统一引用)
140
+
141
+ | Token | 默认 | 用途 |
142
+ |---|---|---|
143
+ | `--wf-dur-fast/base/slow` | 120/200/300ms | 动画时长阶梯 |
144
+ | `--wf-ease-out` | `cubic-bezier(0.16,1,0.3,1)` | 入场(快出缓停) |
145
+ | `--wf-ease-in` | `cubic-bezier(0.4,0,1,1)` | 退场(渐入加速) |
146
+ | `--wf-ease-snap` | `cubic-bezier(0.34,1.56,0.64,1)` | 选中/弹跳(Segmented 等) |
147
+ | `--wf-motion-sm/md/lg` | 4/8/24px | 位移量(toast 退场/抽屉) |
148
+
149
+ ### 语义文字色(P2 新增,浅底可读)
150
+
151
+ `--wf-color-{primary,success,warning,error,info}-text`(700 级,对 50 级底对比度 ≥ 4.5:1)——**文字用 `-text` 变体,500 级只做填充/边框/焦点**。实心填充上的文字用 `--wf-color-on-brand`;遮罩用 `--wf-overlay`。
152
+
153
+ ### CJK / 数字(P5 新增)
154
+
155
+ - `--wf-heading-case: none`(默认)——表头/分组标题文本变换,英文项目可覆盖 `uppercase`
156
+ - `--wf-nums`——`wf-nums` 工具类的取值(tabular-nums,数字防宽度抖动)
157
+
158
+ ## 图标(Icon 组件)
159
+
160
+ 组件库内置 `Icon`(stroke SVG、`currentColor`、`1em` 随字号、`aria-hidden`),组件内部图标统一用它——**禁止裸文本字形**(✕✓⚠▲▼ 等):
161
+
162
+ ```tsx
163
+ h(Icon, { name: 'close' }) // 随上下文颜色/字号
164
+ h(Icon, { name: 'check', size: 16 })
165
+ ```
166
+
167
+ 内置 25 个:方向(chevron/arrow/sort)、状态(check/close/alert/info/warning)、操作(search/send/stop/retry/upload/trash/edit/plus)等。业务图标自备(`Icon` 只做基础集)。
168
+
169
+ ## 浮层退场语义(P0/P4 变更,注意时序)
170
+
171
+ Modal/Drawer/Confirm/Toast 关闭时**先播退场动画再卸载**:
172
+
173
+ - `open=false` 后 DOM 仍存在约 200ms(播 `--exit` 动画)——时序敏感代码(测量/立即重开)需知悉
174
+ - `prefers-reduced-motion: reduce` 下动画降为 0.01ms,等效立即卸载
175
+ - Confirm 默认 `maskClosable=false`(遮罩点击不取消,防误触);Escape 仍可关闭
176
+
177
+ ## 边界(诚实说明)
178
+
179
+ - 业务具体尺寸(`width: 220px`、`min-height: 120px`)用内联——设计系统不背业务值
180
+ - 深度定制组件结构用覆盖 CSS(@layer 友好支持)
181
+ - 低频 CSS(float/filter)不做类——用内联或组件
182
+ - 动效已统一由 Token 驱动:新增动画禁止硬编码时长/缓动(audit 把关)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.78.0",
4
+ "version": "0.80.0",
5
5
  "description": "AI SaaS framework — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {
@@ -1,33 +0,0 @@
1
- /**
2
- * vdom/diff — 同步 patch(阶段 2)
3
- *
4
- * **不变量:diff 只处理已构建树**——组件 vnode 必已 `_render`/`_child`(buildVNode 预构建)。
5
- * 遇未构建组件 → throw(开发期暴露;生产路径 renderByIds/导航都先 buildVNode await)。
6
- * 这是第 1 代死循环的根治:diff 永不调用组件工厂、无 resolve 回调、无补全循环。
7
- *
8
- * 三态 skip:props 同 + 无 dirty + ctx 版本同 → 复用旧 _child(renderFn 不重跑)。
9
- */
10
- import type { VNodeChild } from '../vnode.ts';
11
- import { normalizeChildren } from '../vnode.ts';
12
- export { normalizeChildren };
13
- export interface PatchCtx {
14
- browser: any;
15
- registry: import('./registry.ts').Registry;
16
- /** 当前 ctx 版本号(三态 skip 版本比较:组件 _ctxVersion !== 当前版本 → 不 skip,
17
- * 强制重渲染——bumpCtxVersion 递增后所有组件重跑 renderFn,如 i18n 切换语言) */
18
- ctxVersion?: number;
19
- /** force:跳过三态 skip(mountRoot.rerender 全量重跑用) */
20
- force?: boolean;
21
- }
22
- /**
23
- * patchValue — 同步 diff 单一节点。
24
- * @returns newInput 的实际 DOM(null = 无 DOM)
25
- */
26
- export declare function patchValue(parent: Node, oldNode: Node | null, oldInput: VNodeChild, newInput: VNodeChild, ctx: PatchCtx): Node | null;
27
- /** 属性 patch(只设不删语义保持简单;差异删除由 diff 上层处理) */
28
- export declare function patchProps(el: Element, oldProps: Record<string, any>, newProps: Record<string, any>): void;
29
- /**
30
- * patchChildren — 数组 diff。
31
- * @returns 每个新子项的 DOM 范围(Fragment 展开对齐)
32
- */
33
- export declare function patchChildren(parent: Node, oldInput: VNodeChild | null | undefined, newInput: VNodeChild | null | undefined, ctx: PatchCtx, oldRange?: Node[], oldAnchors?: (Node | null)[], anchorOut?: (Node | null)[]): (Node | null)[];
@@ -1,17 +0,0 @@
1
- /**
2
- * vdom/hydration — 游标收养(SSR HTML → 客户端,不重建 DOM)
3
- *
4
- * 与第 1 代 hydration 的区别:**先 buildVNode 预构建**(await 工厂——组件已 resolve、
5
- * _child 已展开)→ 再游标收养(只接线属性/事件/ref——不重跑 renderFn/工厂)。
6
- *
7
- * 游标不变量:元素/文本 VNode 恰好消耗一个游标节点;组件/Fragment/数组透明;
8
- * null 消耗零;创建时 insertBefore(游标) 且游标不动;收养/替换时游标前进。
9
- */
10
- import type { VNode } from '../vnode.ts';
11
- import type { WfuiContext } from '../types.ts';
12
- import { mountAsyncComponent } from './build.ts';
13
- /** Hydration 入口:buildVNode 预构建(await 工厂)→ 游标收养 */
14
- export declare function hydrateVNode(container: Element, vnode: VNode, ctx: WfuiContext): Promise<void>;
15
- /** 给组件 vnode 分配 id(hydration 需要——注册表定位) */
16
- export declare function ensureHydrationId(vnode: VNode, ctx: WfuiContext): void;
17
- export { mountAsyncComponent };
@@ -1,23 +0,0 @@
1
- /**
2
- * vdom — 全新虚拟 DOM 引擎(第 2 代)
3
- *
4
- * 设计初衷(修复第 1 代死循环/动态挂载问题):
5
- * - 组件 vnode 进入 diff 前**必须已构建**(`_render` 已设)——diff 永不调用组件工厂
6
- * - 构建(buildVNode)是 async 的,统一在渲染入口完成(首帧 / renderByIds / 导航)
7
- * - 动态挂载组件在 buildVNode 阶段被 await(构建完成)→ diff 同步渲染——
8
- * 无占位、无注释、无「resolve 回调触发补全」(第 1 代死循环根因)
9
- * - 工厂只跑一次(vnode 级缓存 + 旧树同位置同类型复用)——无无限挂载
10
- *
11
- * 两阶段异步组件(唯一签名):
12
- * async (initProps, ctx) => Promise<(props) => VNode | null>
13
- */
14
- export { buildVNode } from './build.ts';
15
- export { renderValue } from './render.ts';
16
- export { patchValue } from './diff.ts';
17
- export { createRenderer, type Renderer } from './mount.ts';
18
- export { createRegistry, type Registry } from './registry.ts';
19
- export { createStore, type ExternalStore } from '../store.ts';
20
- export { mountRoot, createVdomContext, mountCommand, unmountCommand, createCommandContainer } from './mount.ts';
21
- export { hydrateVNode } from './hydration.ts';
22
- export { renderSsr, ssrPage, ssrToString, serializeData, createSsrContext } from './ssr.ts';
23
- export { uiServe, type UIServeOptions, type UIServeHandle } from './serve.ts';
@@ -1,58 +0,0 @@
1
- /**
2
- * vdom/mount — 挂载入口(首帧 + ctx/ui 组装)
3
- *
4
- * 渲染管线:buildVNode(async 预构建)→ renderValue(同步落地)。
5
- * ctx.ui:render/setMounting/endMounting——render-only(design/render-only-plan.md)。
6
- */
7
- import type { VNode, VNodeChild, Component } from '../vnode.ts';
8
- import type { WfuiContext } from '../types.ts';
9
- import type { BrowserEnv } from '../types.ts';
10
- import { type Registry } from './registry.ts';
11
- export interface MountOptions {
12
- browser: BrowserEnv;
13
- root: HTMLElement;
14
- registry?: Registry;
15
- renderer?: Renderer;
16
- onError?: (e: unknown) => void;
17
- }
18
- export interface MountHandle {
19
- ctx: WfuiContext;
20
- registry: Registry;
21
- renderer: Renderer;
22
- /** 挂载根组件 */
23
- mount(comp: Component | VNodeChild): Promise<void>;
24
- /** 整树强制重渲染(force——测试辅助/手动刷新:renderFn 重跑 + patch) */
25
- rerender(): Promise<void>;
26
- /** 卸载(清理 DOM) */
27
- unmount(): void;
28
- }
29
- export interface VdomContext {
30
- ctx: WfuiContext;
31
- registry: Registry;
32
- renderer: Renderer;
33
- rootUi: any;
34
- destroyPopupListeners: () => void;
35
- }
36
- export interface Renderer {
37
- render(ids?: string[]): Promise<void>;
38
- }
39
- export interface RendererOptions {
40
- registry: Registry;
41
- ctx: WfuiContext;
42
- rootEl?: HTMLElement;
43
- onError?: (e: unknown) => void;
44
- }
45
- export declare function createRenderer(opts: RendererOptions): Renderer;
46
- /** 组装 vdom 渲染上下文(ctx/registry/renderer/rootUi——含完整 hooks 转发) */
47
- export declare function createVdomContext(opts: MountOptions): VdomContext;
48
- export declare function mountRoot(opts: MountOptions): MountHandle;
49
- /** vdom 命令式挂载:buildVNode(await 工厂)→ renderValue → append + _parentNode */
50
- export declare function mountCommand(container: HTMLElement, vnode: VNode, ctx: WfuiContext, opts?: {
51
- onMounted?: () => void;
52
- }): {
53
- id: string;
54
- };
55
- /** vdom 命令式卸载:ref 清理 + 卸载钩子 + 容器移除 */
56
- export declare function unmountCommand(container: HTMLElement, vnode: VNode | null, ctx: WfuiContext): void;
57
- /** 创建命令式挂载容器(body 下独立 div) */
58
- export declare function createCommandContainer(): HTMLDivElement | null;
@@ -1,17 +0,0 @@
1
- /**
2
- * vdom/render — DOM 落地(阶段 2 同步)
3
- *
4
- * **只处理已构建的组件**(`_render` 已设——buildVNode 已 await 工厂)。
5
- * 遇未构建组件 → 抛错(开发期暴露 bug;生产路径 renderByIds 先 build 后 patch,
6
- * 不会出现未构建组件)。
7
- */
8
- import type { VNodeChild } from '../vnode.ts';
9
- import type { BrowserEnv } from '../types.ts';
10
- export { EVENT_RE, eventTarget, ENUMERATED_VALUE_BASED, holeDetail } from './transform.ts';
11
- export declare const SVG_TAGS: Set<string>;
12
- export declare function setProp(el: Element, key: string, value: any): void;
13
- /** 占位内容(规则表 §1——wf-hole 内容可见可审计:false/null/undefined/true/对象摘要/bad-vnode) */
14
- /** 创建占位节点(数组上下文的无渲染值 → 注释节点,childNodes 与数组同构——规则表 §1) */
15
- export declare function createHole(browser: BrowserEnv, v: unknown): Node | null;
16
- /** 递归渲染(同步——组件必须已构建) */
17
- export declare function renderValue(v: VNodeChild, ctx: any, browser?: BrowserEnv): Node | null;
@@ -1,44 +0,0 @@
1
- /**
2
- * vdom/ssr — 服务端渲染(无 DOM,纯字符串)
3
- *
4
- * SSR 与引擎无关(vnode → HTML 字符串)——vdom 独立实现:
5
- * - renderSsr:await 工厂 → renderFn → 递归(组件签名两阶段 async)
6
- * - createSsrContext:SSR ctx shim(hooks no-op、$ 普通对象、ctx.data 预取)
7
- * - ssrPage:router.execute → renderSsr → 完整 HTML(__DATA__ 种子)
8
- *
9
- * 渲染期非确定性(Date/Math.random/locale)导致 SSR/hydration mismatch——
10
- * dev 检测,文档红线(AGENTS.md §3.5 诚实裁剪)。
11
- */
12
- import type { VNodeChild, Component } from '../vnode.ts';
13
- import type { WfuiContext } from '../types.ts';
14
- import type { UIRouter } from '../router.ts';
15
- /** HTML 转义(文本/属性值) */
16
- export declare function escape(s: string): string;
17
- /** 渲染 vnode → HTML 字符串(服务端) */
18
- export declare function renderSsr(input: VNodeChild, ctx: WfuiContext): Promise<string>;
19
- /** 创建 SSR ctx(serverCtx 注入 + dataStore 预取 + hooks shim) */
20
- export declare function createSsrContext(serverCtx: any, dataStore: Map<string, unknown>): WfuiContext;
21
- /** 序列化数据存储 → window.__DATA__ 脚本(防 XSS:转义 <) */
22
- export declare function serializeData(data: Map<string, unknown>): string;
23
- export interface SsrPageResult {
24
- html: string;
25
- /** __DATA__ 脚本(hydration 种子) */
26
- dataScript: string;
27
- /** 完整 HTML(含 dataScript) */
28
- page: string;
29
- }
30
- /**
31
- * SSR 渲染路由页面 → 完整 HTML(Node 无 DOM)。
32
- * 客户端 uiServe(router, { root, hydrate: true }) 收养。
33
- */
34
- export declare function ssrPage(router: UIRouter, opts: {
35
- url: string;
36
- title?: string;
37
- lang?: string;
38
- rootId?: string;
39
- styles?: string[];
40
- }): Promise<SsrPageResult>;
41
- /** SSR 渲染组件 → HTML 片段 */
42
- export declare function ssrToString(Comp: Component, props: Record<string, any>, serverCtx: any, opts?: {
43
- data?: Map<string, unknown>;
44
- }): Promise<string>;
File without changes