weifuwu 0.65.1 → 0.67.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 (32) hide show
  1. package/README.md +12 -12
  2. package/dist/client/browser.d.ts +10 -0
  3. package/dist/client/index.js +4 -4
  4. package/dist/client/types.d.ts +51 -0
  5. package/dist/client/ui.d.ts +8 -0
  6. package/dist/components/Anchor/Anchor.d.ts +27 -0
  7. package/dist/components/DiffView/DiffView.d.ts +24 -0
  8. package/dist/components/DiffView/diff-utils.d.ts +19 -0
  9. package/dist/components/Editor/Editor.d.ts +1 -1
  10. package/dist/components/Editor/tools/format.d.ts +1 -1
  11. package/dist/components/FileUpload/FileUpload.d.ts +4 -0
  12. package/dist/components/JSONViewer/JSONViewer.d.ts +21 -0
  13. package/dist/components/Kanban/Kanban.d.ts +28 -0
  14. package/dist/components/LogViewer/LogViewer.d.ts +29 -0
  15. package/dist/components/Menu/Menu.d.ts +11 -2
  16. package/dist/components/Pipeline/Pipeline.d.ts +27 -0
  17. package/dist/components/Pipeline/dag-utils.d.ts +36 -0
  18. package/dist/components/Sparkline/Sparkline.d.ts +21 -0
  19. package/dist/components/Sparkline/sparkline-utils.d.ts +16 -0
  20. package/dist/components/Tour/Tour.d.ts +34 -0
  21. package/dist/components/Tree/Tree.d.ts +2 -0
  22. package/dist/components/TreeSelect/TreeSelect.d.ts +24 -0
  23. package/dist/components/VirtualTable/VirtualTable.d.ts +32 -0
  24. package/dist/components/index.d.ts +16 -0
  25. package/dist/components/index.js +15 -11
  26. package/dist/components/style.css +1048 -101
  27. package/dist/index.js +28 -1
  28. package/dist/layout/weifuwu-layout.css +7 -0
  29. package/docs/components-map.md +28 -7
  30. package/docs/custom-components.md +29 -0
  31. package/docs/frontend.md +28 -0
  32. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4371,7 +4371,7 @@ function createSsrContext(serverCtx, dataStore) {
4371
4371
  },
4372
4372
  useDrag: () => ({ onPointerDown: () => {
4373
4373
  } }),
4374
- useDragDrop: () => ({ dropProps: {} }),
4374
+ useDragDrop: () => ({ dropProps: {}, dragProps: {} }),
4375
4375
  useControlled: (options) => ({
4376
4376
  value: options.value,
4377
4377
  setValue: (v) => {
@@ -4426,8 +4426,35 @@ function createSsrContext(serverCtx, dataStore) {
4426
4426
  }
4427
4427
  })
4428
4428
  };
4429
+ const browser = {
4430
+ activeElement: () => null,
4431
+ byId: () => null,
4432
+ query: () => null,
4433
+ createElement: () => null,
4434
+ bodyAppend: () => {
4435
+ },
4436
+ bodyRemove: () => {
4437
+ },
4438
+ copyText: async () => false,
4439
+ execCommand: () => false,
4440
+ selectionText: () => null,
4441
+ getSelection: () => null,
4442
+ queryCommandState: () => false,
4443
+ queryCommandValue: () => "",
4444
+ viewportHeight: () => 0,
4445
+ scrollTop: () => 0,
4446
+ hash: () => "",
4447
+ setHash: () => {
4448
+ },
4449
+ timeout: () => 0,
4450
+ rootElement: () => null,
4451
+ storageGet: () => null,
4452
+ storageSet: () => {
4453
+ }
4454
+ };
4429
4455
  const ctx = Object.create(serverCtx ?? {});
4430
4456
  ctx.ui = ui2;
4457
+ ctx.browser = browser;
4431
4458
  ctx.data = {
4432
4459
  async get(key, fetcher) {
4433
4460
  if (dataStore.has(key)) return dataStore.get(key);
@@ -91,6 +91,13 @@
91
91
  --wf-z-sticky: 40;
92
92
  --wf-z-overlay: 80;
93
93
  --wf-z-modal: 100;
94
+ --wf-z-tour: 2000;
95
+ --wf-tour-min-width: 240px;
96
+ --wf-kanban-col-min-width: 200px;
97
+ --wf-kanban-col-max-width: 300px;
98
+ --wf-treeselect-min-width: 200px;
99
+ --wf-treeselect-max-width: 320px;
100
+ --wf-treeselect-dropdown-max-height: 260px;
94
101
  --wf-z-popover: 120; /* dropdown/select/datepicker 面板与 popover 同层 */
95
102
  --wf-z-toast: 140;
96
103
  --wf-z-tooltip: 160;
@@ -141,13 +141,34 @@
141
141
  <Badge variant="secondary">x</Badge> // → <Tag variant="secondary">x</Tag>
142
142
  ```
143
143
 
144
- ## weifuwu 尚未实现(三库有)→ 待补清单
144
+ ## weifuwu 已补齐(第六批,2026-08)→ 待补清单清零 ✅
145
145
 
146
- 仅 4 项:
146
+ 第六批 6 组件全部落地(TDD 红→绿 + style-audit + demo + agent-browser 实测):
147
147
 
148
- - **Anchor**(锚点导航,三库均有)
149
- - **Menu 子菜单/折叠**(分组 group 已支持,子级/折叠待补)
150
- - **FileUpload 增强**(拖拽已支持;文件列表/预览/进度待补)
151
- - **VirtualTable**(VirtualList 已有,表格虚拟化待补)
148
+ | 组件 | 类型 | 要点 |
149
+ |------|------|------|
150
+ | **Menu 子菜单/折叠** | 增强 | `children` 子菜单 + `collapsible` 折叠侧栏 + 多级键盘流 |
151
+ | **FileUpload 增强** | 增强 | 图片缩略图(objectURL revoke)+ 进度条 + 受控纪律 |
152
+ | **VirtualTable** | 新增 | 固定表头 + 虚拟滚动(10k 行 ~17 DOM)+ 排序 |
153
+ | **Anchor** | 新增 | 滚动高亮跟随 + 点击平滑滚动 + useHash |
154
+ | **LogViewer** | 新增 | ANSI 着色 + 虚拟滚动 + follow 自动跟随 + maxLines |
155
+ | **JSONViewer** | 新增 | 递归折叠 + 类型色 + 路径复制 + 懒展开(ToolCallCard 已接入) |
152
156
 
153
- > 难度阶梯(L1-L6)与验证的 client 能力点:见 `design/components-cdd.md`;三库 → weifuwu 覆盖矩阵:见 `design/components-migration.md`。
157
+ > 三库共识覆盖度 ~100%(剩余均为已声明裁剪项,见 `design/components-roadmap.md` 第六批裁剪清单)。
158
+
159
+ ## 第七批:AI 开发者工具深化(96 → 102 组件)
160
+
161
+ > 追平期结束(三库共识 ~100%),差异化期——本批全部组件三库没有的直接等价物。
162
+
163
+ | 组件 | 类型 | 要点 |
164
+ |------|------|------|
165
+ | **DiffView** | 新增 | LCS 行级 diff(自研算法):三态行 + 未变块折叠 + maxLines 防超大 |
166
+ | **Sparkline** | 新增 | 迷你趋势线:SVG 自绘 + 归一化 + 平滑曲线 + 面积填充 + 等值防抖 |
167
+ | **Tour** | 新增 | 新手引导:目标高亮(rect 精确跟随)+ 遮罩 + 步骤气泡 + 全局 Escape |
168
+ | **Kanban** | 新增 | 拖拽看板:原生 DnD + 跨列/重排 + 悬停高亮 + 受控纪律 |
169
+ | **Pipeline** | 新增 | Agent 工作流 DAG:Kahn 拓扑分层 + 贝塞尔连线 + 状态语义色 + 环检测 |
170
+ | **TreeSelect** | 新增 | 树形选择:单选/多选(父子联动)+ label 回显 + 受控纪律 |
171
+
172
+ > AI 开发者工具链成型:AiChat / Command / JSONViewer / LogViewer / DiffView /
173
+ > Pipeline——三库差异化最深的完整工具线。
174
+ > 裁剪声明见 `design/components-roadmap.md` 第七批。
@@ -207,6 +207,35 @@ const CollapseItem: Component<{ active?: boolean; onChange?: (v: boolean) => voi
207
207
 
208
208
  **纪律**:组件内动画事件监听**唯一入口是 `useAnimationEnd`**——禁直接 `addEventListener('animationend')`(DatePicker 已收敛);退场优先 `usePresence`(声明式状态机)或 `animateOut`(命令式)。
209
209
 
210
+ ## 8.6 浏览器环境纪律(ctx.browser)
211
+
212
+ > **自定义组件禁止直接引用 window/document**——统一经 `ctx.browser`:
213
+ > SSR 安全(shim 安全默认)+ 测试 mock 单点 + 环境差异隔离。
214
+
215
+ ```tsx
216
+ const MyComp: Component = (_init, ctx) => {
217
+ // mount 层取 browser(ctx.browser 优先,测试/无注入环境 fallback jsdom)
218
+ const browser = ctx.browser ?? createClientBrowser()
219
+ return (props) =>
220
+ h('button', {
221
+ onClick: () => {
222
+ // 复制/查询/存储/滚动——全部经 browser
223
+ void browser.copyText('hello')
224
+ const el = browser.byId('target')
225
+ }
226
+ })
227
+ }
228
+ ```
229
+
230
+ **规则**:
231
+ - 拖拽统一 `ctx.ui.useDragDrop`(drop 侧 dropProps + drag 侧 dragProps:draggable/
232
+ onDragStart/onDragEnd)——**dragstart 期间禁止重渲染**(渲染替换源元素中断拖拽;
233
+ 身份/位置在渲染期闭包绑定,拖拽视觉高亮用 CSS :hover)
234
+ - 复制统一 `browser.copyText`(clipboard + 降级——勿自建 textarea+execCommand)
235
+ - 键盘导航用 `browser.activeElement()`(勿 document.activeElement)
236
+ - 存储用 `browser.storageGet/Set`(勿 localStorage 裸调)
237
+ - SSR 场景(render/mount 期)绝对不碰环境 API(shim 返回 null——需防御)
238
+
210
239
  ## 9. 样式纪律(style-audit 强制)
211
240
 
212
241
  - 动效用 Token:`--wf-dur-*` / `--wf-ease-*` / `--wf-motion-*`(禁硬编码)
package/docs/frontend.md CHANGED
@@ -143,6 +143,34 @@ ctx.ui.render(['name'])
143
143
 
144
144
  ---
145
145
 
146
+ ## 浏览器环境抽象(ctx.browser)
147
+
148
+ > 组件**不直接引用 window/document**——统一经 `ctx.browser`(环境 API):
149
+ > SSR 安全(shim 返回安全默认)+ 测试可 mock + 环境差异单点隔离。
150
+
151
+ | 方法 | 说明 |
152
+ |------|------|
153
+ | `activeElement()` | 当前焦点元素(键盘导航) |
154
+ | `byId(id)` / `query(sel)` | 元素查询(getElementById / querySelector) |
155
+ | `createElement(tag)` / `bodyAppend(el)` / `bodyRemove(el)` | 动态创建/挂载容器 |
156
+ | `copyText(text)` | **复制统一入口**(clipboard API + execCommand 降级) |
157
+ | `execCommand(cmd, value?)` | 富文本编辑器命令 |
158
+ | `selectionText()` / `getSelection()` | 编辑器选区(文本 / 完整 Selection 对象) |
159
+ | `viewportHeight()` / `scrollTop()` | 视口高度 / 滚动量(scrollingElement 优先) |
160
+ | `hash()` / `setHash(h)` | 锚点 hash |
161
+ | `timeout(fn, ms)` | 定时器(SSR no-op) |
162
+ | `rootElement()` | document.documentElement(主题应用) |
163
+ | `storageGet(key)` / `storageSet(key, val)` | localStorage(SSR/隐私模式安全) |
164
+
165
+ **三态实现**:客户端 `createClientBrowser`(惰性 typeof 防御)· SSR shim(null/0/no-op)· 测试 mock 或 jsdom fallback。
166
+
167
+ ```tsx
168
+ // 组件内(mount 层)
169
+ const browser = ctx.browser ?? createClientBrowser()
170
+ // 事件回调
171
+ await browser.copyText(text)
172
+ ```
173
+
146
174
  ## 状态管理
147
175
 
148
176
  ### ctx.ui 方法速查
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.65.1",
4
+ "version": "0.67.0",
5
5
  "description": "AI SaaS framework — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {