weifuwu 0.70.0 → 0.72.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 (170) hide show
  1. package/README.md +66 -55
  2. package/dist/components/Accordion/Accordion.d.ts +1 -1
  3. package/dist/components/Affix/Affix.d.ts +1 -1
  4. package/dist/components/AiChat/AiChat.d.ts +2 -2
  5. package/dist/components/Alert/Alert.d.ts +1 -1
  6. package/dist/components/AlertGroup/AlertGroup.d.ts +1 -1
  7. package/dist/components/Anchor/Anchor.d.ts +1 -1
  8. package/dist/components/ApprovalCard/ApprovalCard.d.ts +3 -1
  9. package/dist/components/AspectRatio/AspectRatio.d.ts +1 -1
  10. package/dist/components/AutoComplete/AutoComplete.d.ts +1 -1
  11. package/dist/components/Avatar/Avatar.d.ts +1 -1
  12. package/dist/components/AvatarGroup/AvatarGroup.d.ts +1 -1
  13. package/dist/components/BackTop/BackTop.d.ts +1 -1
  14. package/dist/components/Badge/Badge.d.ts +7 -1
  15. package/dist/components/Breadcrumb/Breadcrumb.d.ts +1 -1
  16. package/dist/components/Button/Button.d.ts +1 -1
  17. package/dist/components/Calendar/Calendar.d.ts +1 -1
  18. package/dist/components/Card/Card.d.ts +1 -1
  19. package/dist/components/Carousel/Carousel.d.ts +1 -1
  20. package/dist/components/Cascader/Cascader.d.ts +7 -3
  21. package/dist/components/Chart/Chart.d.ts +1 -1
  22. package/dist/components/Checkbox/Checkbox.d.ts +1 -1
  23. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +1 -1
  24. package/dist/components/CodeBlock/CodeBlock.d.ts +1 -1
  25. package/dist/components/Collapse/Collapse.d.ts +1 -1
  26. package/dist/components/ColorPicker/ColorPicker.d.ts +1 -1
  27. package/dist/components/Command/Command.d.ts +1 -1
  28. package/dist/components/Confirm/Confirm.d.ts +2 -2
  29. package/dist/components/ContextMenu/ContextMenu.d.ts +1 -1
  30. package/dist/components/CopyButton/CopyButton.d.ts +1 -1
  31. package/dist/components/DatePicker/DatePicker.d.ts +1 -1
  32. package/dist/components/Descriptions/Descriptions.d.ts +1 -1
  33. package/dist/components/DiffView/DiffView.d.ts +1 -1
  34. package/dist/components/Divider/Divider.d.ts +1 -1
  35. package/dist/components/Drawer/Drawer.d.ts +1 -1
  36. package/dist/components/Dropdown/Dropdown.d.ts +1 -1
  37. package/dist/components/Editor/Editor.d.ts +1 -1
  38. package/dist/components/Editor/tools/toolbar.d.ts +1 -1
  39. package/dist/components/EmptyState/EmptyState.d.ts +3 -2
  40. package/dist/components/Field/Field.d.ts +1 -1
  41. package/dist/components/FileUpload/FileUpload.d.ts +1 -1
  42. package/dist/components/FloatButton/FloatButton.d.ts +1 -1
  43. package/dist/components/Form/Form.d.ts +1 -1
  44. package/dist/components/Grid/Grid.d.ts +1 -1
  45. package/dist/components/Highlight/Highlight.d.ts +1 -1
  46. package/dist/components/HoverCard/HoverCard.d.ts +2 -2
  47. package/dist/components/Icon/Icon.d.ts +1 -1
  48. package/dist/components/Img/Img.d.ts +1 -1
  49. package/dist/components/InView/InView.d.ts +1 -1
  50. package/dist/components/InfiniteScroll/InfiniteScroll.d.ts +1 -1
  51. package/dist/components/Input/Input.d.ts +1 -1
  52. package/dist/components/InputNumber/InputNumber.d.ts +3 -3
  53. package/dist/components/JSONViewer/JSONViewer.d.ts +1 -1
  54. package/dist/components/Kanban/Kanban.d.ts +1 -1
  55. package/dist/components/Label/Label.d.ts +1 -1
  56. package/dist/components/Layout/Layout.d.ts +3 -1
  57. package/dist/components/Link/Link.d.ts +1 -1
  58. package/dist/components/List/List.d.ts +1 -1
  59. package/dist/components/Loading/Loading.d.ts +1 -1
  60. package/dist/components/LogViewer/LogViewer.d.ts +1 -1
  61. package/dist/components/Markdown/Markdown.d.ts +1 -1
  62. package/dist/components/Markdown/parser.d.ts +11 -5
  63. package/dist/components/Mentions/Mentions.d.ts +1 -1
  64. package/dist/components/Menu/Menu.d.ts +2 -2
  65. package/dist/components/Menubar/Menubar.d.ts +1 -1
  66. package/dist/components/MessageBubble/MessageBubble.d.ts +1 -1
  67. package/dist/components/Modal/Modal.d.ts +1 -1
  68. package/dist/components/NavMenu/NavMenu.d.ts +1 -1
  69. package/dist/components/Notification/Notification.d.ts +2 -2
  70. package/dist/components/PageHeader/PageHeader.d.ts +1 -1
  71. package/dist/components/Pagination/Pagination.d.ts +1 -1
  72. package/dist/components/PasswordInput/PasswordInput.d.ts +1 -1
  73. package/dist/components/PinInput/PinInput.d.ts +1 -1
  74. package/dist/components/Pipeline/Pipeline.d.ts +1 -1
  75. package/dist/components/Popconfirm/Popconfirm.d.ts +2 -2
  76. package/dist/components/Popover/Popover.d.ts +2 -2
  77. package/dist/components/ProgressBar/ProgressBar.d.ts +6 -1
  78. package/dist/components/QRCode/QRCode.d.ts +1 -1
  79. package/dist/components/RadioGroup/RadioGroup.d.ts +1 -1
  80. package/dist/components/Rate/Rate.d.ts +3 -1
  81. package/dist/components/Resizable/Resizable.d.ts +1 -1
  82. package/dist/components/Result/Result.d.ts +1 -1
  83. package/dist/components/Scrollbar/Scrollbar.d.ts +1 -1
  84. package/dist/components/SearchInput/SearchInput.d.ts +1 -1
  85. package/dist/components/SegmentedControl/SegmentedControl.d.ts +1 -1
  86. package/dist/components/Select/Select.d.ts +1 -1
  87. package/dist/components/Skeleton/Skeleton.d.ts +1 -1
  88. package/dist/components/Slider/Slider.d.ts +1 -1
  89. package/dist/components/Space/Space.d.ts +1 -1
  90. package/dist/components/Sparkline/Sparkline.d.ts +3 -1
  91. package/dist/components/StatCard/StatCard.d.ts +5 -3
  92. package/dist/components/Steps/Steps.d.ts +1 -1
  93. package/dist/components/Switch/Switch.d.ts +1 -1
  94. package/dist/components/Table/Table.d.ts +1 -1
  95. package/dist/components/Tabs/Tabs.d.ts +1 -1
  96. package/dist/components/Tag/Tag.d.ts +1 -1
  97. package/dist/components/TagsInput/TagsInput.d.ts +1 -1
  98. package/dist/components/Textarea/Textarea.d.ts +1 -1
  99. package/dist/components/ThemeSwitch/ThemeSwitch.d.ts +1 -1
  100. package/dist/components/Timeline/Timeline.d.ts +6 -5
  101. package/dist/components/Toast/Toast.d.ts +2 -2
  102. package/dist/components/ToggleGroup/ToggleGroup.d.ts +1 -1
  103. package/dist/components/ToolCallCard/ToolCallCard.d.ts +1 -1
  104. package/dist/components/Tooltip/Tooltip.d.ts +2 -2
  105. package/dist/components/Tour/Tour.d.ts +1 -1
  106. package/dist/components/Transfer/Transfer.d.ts +7 -3
  107. package/dist/components/Tree/Tree.d.ts +4 -2
  108. package/dist/components/TreeSelect/TreeSelect.d.ts +1 -1
  109. package/dist/components/Typography/Typography.d.ts +1 -1
  110. package/dist/components/VirtualList/VirtualList.d.ts +1 -1
  111. package/dist/components/VirtualTable/VirtualTable.d.ts +10 -2
  112. package/dist/components/Watermark/Watermark.d.ts +1 -1
  113. package/dist/components/index.d.ts +1 -1
  114. package/dist/components/index.js +13 -13
  115. package/dist/components/style.css +803 -320
  116. package/dist/dev/index.js +1 -1
  117. package/dist/index.js +12 -5
  118. package/dist/layout/weifuwu-layout.css +133 -15
  119. package/dist/ui/index.d.ts +1 -1
  120. package/dist/ui/ssr-page.d.ts +1 -1
  121. package/dist/ui/ssr.d.ts +1 -1
  122. package/dist/ui-dom/Confirm.d.ts +44 -0
  123. package/dist/ui-dom/Notification.d.ts +70 -0
  124. package/dist/ui-dom/Toast.d.ts +43 -0
  125. package/dist/{client → ui-dom}/diff.d.ts +7 -6
  126. package/dist/ui-dom/index.d.ts +33 -0
  127. package/dist/ui-dom/index.js +18 -0
  128. package/dist/ui-dom/jsx-runtime.d.ts +4 -0
  129. package/dist/ui-dom/jsx-runtime.js +1 -0
  130. package/dist/ui-dom/popup-tracker.d.ts +36 -0
  131. package/dist/ui-dom/registry.d.ts +39 -0
  132. package/dist/{client → ui-dom}/render.d.ts +14 -6
  133. package/dist/ui-dom/router.d.ts +66 -0
  134. package/dist/ui-dom/serve.d.ts +28 -0
  135. package/dist/ui-dom/ssr.d.ts +56 -0
  136. package/dist/{client → ui-dom}/types.d.ts +63 -18
  137. package/dist/{client → ui-dom}/ui.d.ts +9 -1
  138. package/dist/{client → ui-dom}/vnode.d.ts +24 -16
  139. package/docs/components.md +2 -2
  140. package/docs/custom-components.md +2 -0
  141. package/docs/frontend-middleware.md +3 -1
  142. package/docs/frontend-ui-dom.md +110 -0
  143. package/docs/frontend.md +3 -1
  144. package/docs/layout.md +37 -9
  145. package/docs/realtime.md +2 -0
  146. package/docs/saas.md +2 -0
  147. package/package.json +7 -7
  148. package/dist/client/app.d.ts +0 -26
  149. package/dist/client/error-boundary.d.ts +0 -23
  150. package/dist/client/index.d.ts +0 -54
  151. package/dist/client/index.js +0 -6
  152. package/dist/client/registry.d.ts +0 -34
  153. package/dist/client/router.d.ts +0 -26
  154. package/dist/client/type-flow.test.d.ts +0 -7
  155. /package/dist/{client → ui-dom}/ai.d.ts +0 -0
  156. /package/dist/{client → ui-dom}/browser.d.ts +0 -0
  157. /package/dist/{client → ui-dom}/focus-trap.d.ts +0 -0
  158. /package/dist/{client → ui-dom}/hydration.d.ts +0 -0
  159. /package/dist/{client → ui-dom}/i18n.d.ts +0 -0
  160. /package/dist/{client → ui-dom}/locale/en_US.d.ts +0 -0
  161. /package/dist/{client → ui-dom}/locale/zh_CN.d.ts +0 -0
  162. /package/dist/{client → ui-dom}/middleware/api.d.ts +0 -0
  163. /package/dist/{client → ui-dom}/middleware/auth.d.ts +0 -0
  164. /package/dist/{client → ui-dom}/middleware/ws.d.ts +0 -0
  165. /package/dist/{client → ui-dom}/motion.d.ts +0 -0
  166. /package/dist/{client → ui-dom}/popup.d.ts +0 -0
  167. /package/dist/{client → ui-dom}/reactive.d.ts +0 -0
  168. /package/dist/{client → ui-dom}/route-match.d.ts +0 -0
  169. /package/dist/{client → ui-dom}/scroll-lock.d.ts +0 -0
  170. /package/dist/{client → ui-dom}/use-chat.d.ts +0 -0
package/dist/dev/index.js CHANGED
@@ -11,7 +11,7 @@ registerHooks({
11
11
  const result = transformSync(code, {
12
12
  loader: url.endsWith(".tsx") ? "tsx" : "ts",
13
13
  jsx: "automatic",
14
- jsxImportSource: "weifuwu/client",
14
+ jsxImportSource: "weifuwu/ui-dom",
15
15
  format: "esm",
16
16
  sourcemap: "inline",
17
17
  target: "node22"
package/dist/index.js CHANGED
@@ -4236,7 +4236,7 @@ var HtmlSafe = class {
4236
4236
  }
4237
4237
  };
4238
4238
 
4239
- // src/client/vnode.ts
4239
+ // src/ui-dom/vnode.ts
4240
4240
  var ASYNC_MARK = "__wfAsyncComponent";
4241
4241
  function isAsyncComponent(type) {
4242
4242
  return typeof type === "function" && type?.[ASYNC_MARK] === true;
@@ -4244,7 +4244,7 @@ function isAsyncComponent(type) {
4244
4244
  var Fragment = /* @__PURE__ */ Symbol("Fragment");
4245
4245
  var Portal = /* @__PURE__ */ Symbol("Portal");
4246
4246
 
4247
- // src/client/reactive.ts
4247
+ // src/ui-dom/reactive.ts
4248
4248
  function createReactiveState(dirty) {
4249
4249
  const proxyCache = /* @__PURE__ */ new WeakMap();
4250
4250
  const watchers = /* @__PURE__ */ new Set();
@@ -4690,7 +4690,7 @@ function ui() {
4690
4690
  format: "esm",
4691
4691
  platform: "browser",
4692
4692
  jsx: "automatic",
4693
- jsxImportSource: "weifuwu/client",
4693
+ jsxImportSource: "weifuwu/ui-dom",
4694
4694
  write: false,
4695
4695
  metafile: true
4696
4696
  });
@@ -4745,7 +4745,7 @@ function ui() {
4745
4745
  };
4746
4746
  }
4747
4747
 
4748
- // src/client/route-match.ts
4748
+ // src/ui-dom/route-match.ts
4749
4749
  function joinPaths(a, b) {
4750
4750
  if (!b || b === "/") return a || "/";
4751
4751
  const left = a.endsWith("/") ? a.slice(0, -1) : a;
@@ -4787,11 +4787,18 @@ function extractParams(path, match) {
4787
4787
  const m = path.match(match.re);
4788
4788
  if (m) {
4789
4789
  for (let i = 0; i < match.keys.length; i++) {
4790
- params[match.keys[i]] = decodeURIComponent(m[i + 1]);
4790
+ params[match.keys[i]] = safeDecode(m[i + 1]);
4791
4791
  }
4792
4792
  }
4793
4793
  return params;
4794
4794
  }
4795
+ function safeDecode(s) {
4796
+ try {
4797
+ return decodeURIComponent(s);
4798
+ } catch {
4799
+ return s;
4800
+ }
4801
+ }
4795
4802
 
4796
4803
  // src/ui/ssr-page.ts
4797
4804
  var DEFAULT_TEMPLATE = (p) => `<!DOCTYPE html>
@@ -46,6 +46,7 @@
46
46
  --wf-dark-bg-hover: rgba(255, 255, 255, 0.06); /* 暗色 hover 反白 */
47
47
  --wf-dark-surface-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
48
48
  --wf-dark-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
49
+ --wf-dark-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.3);
49
50
  --wf-dark-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
50
51
  --wf-dark-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
51
52
  --wf-dark-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4);
@@ -82,6 +83,7 @@
82
83
 
83
84
  /* ── 阴影 ── */
84
85
  --wf-shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
86
+ --wf-shadow-inset: inset 0 1px 2px rgba(0,0,0,0.04); /* 内阴影:凹槽/轨道深度(Switch/ThemeSwitch) */
85
87
  --wf-shadow: 0 1px 3px rgba(0,0,0,0.08);
86
88
  --wf-shadow-md: 0 4px 12px rgba(0,0,0,0.1);
87
89
  --wf-shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1);
@@ -222,6 +224,7 @@
222
224
 
223
225
  /* ── 浮层遮罩(Modal/Drawer overlay,暗色经 --wf-dark-overlay 映射) ── */
224
226
  --wf-overlay: rgba(0, 0, 0, 0.4);
227
+ --wf-overlay-blur: 4px; /* 遮罩毛玻璃(弹层现代质感,不支持 backdrop-filter 的环境自动降级为纯色) */
225
228
 
226
229
  /* ── 表单控件 ── */
227
230
  --wf-accent-color: var(--wf-color-primary);
@@ -307,6 +310,7 @@
307
310
  --wf-shadow: var(--wf-dark-shadow);
308
311
  --wf-shadow-md: var(--wf-dark-shadow-md);
309
312
  --wf-shadow-lg: var(--wf-dark-shadow-lg);
313
+ --wf-shadow-inset: var(--wf-dark-shadow-inset);
310
314
 
311
315
  --wf-color-primary-text: var(--wf-dark-brand-500);
312
316
  --wf-color-success-text: var(--wf-dark-green-500);
@@ -357,6 +361,7 @@
357
361
  --wf-shadow: var(--wf-dark-shadow);
358
362
  --wf-shadow-md: var(--wf-dark-shadow-md);
359
363
  --wf-shadow-lg: var(--wf-dark-shadow-lg);
364
+ --wf-shadow-inset: var(--wf-dark-shadow-inset);
360
365
 
361
366
  --wf-color-primary-text: var(--wf-dark-brand-500);
362
367
  --wf-color-success-text: var(--wf-dark-green-500);
@@ -377,6 +382,36 @@
377
382
  box-sizing: border-box;
378
383
  }
379
384
 
385
+ /* 选区色:primary 调(文字反白,与品牌一致) */
386
+ ::selection {
387
+ background: var(--wf-color-primary-bg);
388
+ color: var(--wf-color-primary-text);
389
+ }
390
+
391
+ /* 主题滚动条(全局——所有滚动区一致;Firefox thin + WebKit 样式) */
392
+ * {
393
+ scrollbar-width: thin;
394
+ scrollbar-color: var(--wf-color-border-dark) transparent;
395
+ }
396
+ ::-webkit-scrollbar {
397
+ width: 8px;
398
+ height: 8px;
399
+ }
400
+ ::-webkit-scrollbar-track {
401
+ background: transparent;
402
+ }
403
+ ::-webkit-scrollbar-thumb {
404
+ background: var(--wf-color-border-dark);
405
+ border-radius: var(--wf-radius-sm);
406
+ border: 2px solid transparent;
407
+ background-clip: padding-box;
408
+ }
409
+ ::-webkit-scrollbar-thumb:hover {
410
+ background: var(--wf-color-text-secondary);
411
+ background-clip: padding-box;
412
+ border: 2px solid transparent;
413
+ }
414
+
380
415
  :root {
381
416
  /* 原生控件/滚动条跟随主题;暗色激活时在 _dark.css 中切为 dark */
382
417
  color-scheme: light;
@@ -447,11 +482,20 @@ button {
447
482
  padding: var(--wf-control-pad-y) var(--wf-space-md);
448
483
  min-height: var(--wf-control-height);
449
484
  cursor: pointer;
485
+ transition: border-color var(--wf-dur-fast) var(--wf-ease-out),
486
+ color var(--wf-dur-fast) var(--wf-ease-out),
487
+ box-shadow var(--wf-dur-fast) var(--wf-ease-out),
488
+ background-color var(--wf-dur-fast) var(--wf-ease-out),
489
+ filter var(--wf-dur-fast) var(--wf-ease-out);
450
490
  }
451
491
  button:hover {
452
492
  border-color: var(--wf-color-primary);
453
493
  color: var(--wf-color-primary-text);
454
494
  }
495
+ button:active:not(:disabled),
496
+ [role="button"]:active {
497
+ filter: brightness(0.95); /* 按压反馈:不偏移布局,适用任意宽度(block/inline) */
498
+ }
455
499
 
456
500
  /* 键盘焦点:button 与 [tabindex] 统一 focus ring(仅键盘触发,鼠标点击不闪) */
457
501
  button:focus-visible,
@@ -460,6 +504,15 @@ button:focus-visible,
460
504
  box-shadow: var(--wf-focus-ring);
461
505
  }
462
506
 
507
+ [role="button"] {
508
+ cursor: pointer;
509
+ transition: background-color var(--wf-dur-fast) var(--wf-ease-out),
510
+ border-color var(--wf-dur-fast) var(--wf-ease-out),
511
+ box-shadow var(--wf-dur-fast) var(--wf-ease-out),
512
+ color var(--wf-dur-fast) var(--wf-ease-out),
513
+ filter var(--wf-dur-fast) var(--wf-ease-out);
514
+ }
515
+
463
516
  /* 触屏设备(coarse pointer):交互目标提升到 44px(Apple HIG / WCAG 2.5.8) */
464
517
  @media (pointer: coarse) {
465
518
  button,
@@ -571,10 +624,13 @@ body.wf-dragging {
571
624
  }
572
625
 
573
626
  @layer layout {
574
- /* stack — 纵向堆叠 */
627
+ /* stack — 纵向堆叠(L3:gap 默认值 :where() 零优先级——wf-gap-* 等覆盖工具
628
+ 靠优先级获胜,不再依赖 import 顺序) */
575
629
  .wf-stack {
576
630
  display: flex;
577
631
  flex-direction: column;
632
+ }
633
+ :where(.wf-stack) {
578
634
  gap: var(--wf-gap, var(--wf-gap-md));
579
635
  }
580
636
  @media (min-width: 640px) { .wf-stack\@sm { flex-direction: row; align-items: var(--wf-align, center); } }
@@ -585,6 +641,8 @@ body.wf-dragging {
585
641
  .wf-stack-reverse {
586
642
  display: flex;
587
643
  flex-direction: column-reverse;
644
+ }
645
+ :where(.wf-stack-reverse) {
588
646
  gap: var(--wf-gap, var(--wf-gap-md));
589
647
  }
590
648
  @media (min-width: 640px) { .wf-stack-reverse\@sm { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
@@ -593,10 +651,13 @@ body.wf-dragging {
593
651
  }
594
652
 
595
653
  @layer layout {
596
- /* row — 横向排列 */
654
+ /* row — 横向排列(L3:gap/align 默认值 :where() 零优先级——wf-gap-*、wf-top 等
655
+ 覆盖工具靠优先级获胜,不再依赖 import 顺序) */
597
656
  .wf-row {
598
657
  display: flex;
599
658
  flex-wrap: wrap;
659
+ }
660
+ :where(.wf-row) {
600
661
  gap: var(--wf-gap, var(--wf-gap-md));
601
662
  align-items: var(--wf-align, center);
602
663
  }
@@ -609,6 +670,8 @@ body.wf-dragging {
609
670
  display: flex;
610
671
  flex-direction: row-reverse;
611
672
  flex-wrap: wrap;
673
+ }
674
+ :where(.wf-row-reverse) {
612
675
  gap: var(--wf-gap, var(--wf-gap-md));
613
676
  align-items: var(--wf-align, center);
614
677
  }
@@ -618,10 +681,12 @@ body.wf-dragging {
618
681
  }
619
682
 
620
683
  @layer layout {
621
- /* split — 两端展开 */
684
+ /* split — 两端展开(L3:align/gap 默认值 :where() 零优先级) */
622
685
  .wf-split {
623
686
  display: flex;
624
687
  justify-content: space-between;
688
+ }
689
+ :where(.wf-split) {
625
690
  align-items: var(--wf-align, center);
626
691
  gap: var(--wf-gap, var(--wf-gap-md));
627
692
  }
@@ -641,10 +706,12 @@ body.wf-dragging {
641
706
  }
642
707
 
643
708
  @layer layout {
644
- /* between — 两端对齐(行内垂直居中) */
709
+ /* between — 两端对齐(行内垂直居中;L3:align/gap 默认值 :where() 零优先级) */
645
710
  .wf-between {
646
711
  display: flex;
647
712
  justify-content: space-between;
713
+ }
714
+ :where(.wf-between) {
648
715
  align-items: var(--wf-align, center);
649
716
  gap: var(--wf-gap, var(--wf-gap-md));
650
717
  }
@@ -654,57 +721,69 @@ body.wf-dragging {
654
721
  }
655
722
 
656
723
  @layer layout {
657
- /* right — 靠右对齐 */
724
+ /* right — 靠右对齐(L3:align/gap 默认值 :where() 零优先级) */
658
725
  .wf-right {
659
726
  display: flex;
660
727
  justify-content: flex-end;
728
+ }
729
+ :where(.wf-right) {
661
730
  align-items: var(--wf-align, center);
662
731
  gap: var(--wf-gap, var(--wf-gap-md));
663
732
  }
664
733
  }
665
734
 
666
735
  @layer layout {
667
- /* top — 顶部对齐 */
736
+ /* top — 顶部对齐(L3:gap 默认值 :where() 零优先级;align-items 是身份属性) */
668
737
  .wf-top {
669
738
  display: flex;
670
739
  align-items: flex-start;
740
+ }
741
+ :where(.wf-top) {
671
742
  gap: var(--wf-gap, var(--wf-gap-md));
672
743
  }
673
744
  }
674
745
 
675
746
  @layer layout {
676
- /* bottom — 底部对齐 */
747
+ /* bottom — 底部对齐(L3:gap 默认值 :where() 零优先级;align-items 是身份属性) */
677
748
  .wf-bottom {
678
749
  display: flex;
679
750
  align-items: flex-end;
751
+ }
752
+ :where(.wf-bottom) {
680
753
  gap: var(--wf-gap, var(--wf-gap-md));
681
754
  }
682
755
  }
683
756
 
684
757
  @layer layout {
685
- /* stretch — 拉伸对齐 */
758
+ /* stretch — 拉伸对齐(L3:gap 默认值 :where() 零优先级;align-items 是身份属性) */
686
759
  .wf-stretch {
687
760
  display: flex;
688
761
  align-items: stretch;
762
+ }
763
+ :where(.wf-stretch) {
689
764
  gap: var(--wf-gap, var(--wf-gap-md));
690
765
  }
691
766
  }
692
767
 
693
768
  @layer layout {
694
- /* around — 均匀环绕分布 */
769
+ /* around — 均匀环绕分布(L3:align/gap 默认值 :where() 零优先级) */
695
770
  .wf-around {
696
771
  display: flex;
697
772
  justify-content: space-around;
773
+ }
774
+ :where(.wf-around) {
698
775
  align-items: var(--wf-align, center);
699
776
  gap: var(--wf-gap, var(--wf-gap-md));
700
777
  }
701
778
  }
702
779
 
703
780
  @layer layout {
704
- /* evenly — 均匀分布 */
781
+ /* evenly — 均匀分布(L3:align/gap 默认值 :where() 零优先级) */
705
782
  .wf-evenly {
706
783
  display: flex;
707
784
  justify-content: space-evenly;
785
+ }
786
+ :where(.wf-evenly) {
708
787
  align-items: var(--wf-align, center);
709
788
  gap: var(--wf-gap, var(--wf-gap-md));
710
789
  }
@@ -720,7 +799,9 @@ body.wf-dragging {
720
799
  }
721
800
 
722
801
  @layer layout {
723
- /* fixed — 固定不伸缩 */
802
+ /* flex-none — 固定不伸缩(推荐名;wf-fixed 为兼容别名——易与 position:fixed 混淆,
803
+ position:fixed 请用 wf-pin) */
804
+ .wf-flex-none,
724
805
  .wf-fixed {
725
806
  flex: none;
726
807
  }
@@ -881,19 +962,24 @@ body.wf-dragging {
881
962
  }
882
963
 
883
964
  @layer layout {
884
- /* grid — 二维网格 */
965
+ /* grid — 二维网格(L3:gap 默认值 :where() 零优先级) */
885
966
  .wf-grid {
886
967
  display: grid;
887
968
  grid-template-columns: var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)));
969
+ }
970
+ :where(.wf-grid) {
888
971
  gap: var(--wf-gap, var(--wf-gap-lg));
889
972
  }
890
973
  }
891
974
 
892
975
  @layer layout {
893
- /* cluster — 换行簇 */
976
+ /* cluster — 换行簇(L3:justify/align/gap 默认值 :where() 零优先级——
977
+ wf-right 等分布工具叠加时靠优先级获胜) */
894
978
  .wf-cluster {
895
979
  display: flex;
896
980
  flex-wrap: wrap;
981
+ }
982
+ :where(.wf-cluster) {
897
983
  gap: var(--wf-gap, var(--wf-gap-sm));
898
984
  justify-content: var(--wf-justify, center);
899
985
  align-items: var(--wf-align, center);
@@ -901,7 +987,7 @@ body.wf-dragging {
901
987
  }
902
988
 
903
989
  @layer layout {
904
- /* scroll — 可滚动容器 */
990
+ /* scroll — 可滚动容器(全局滚动条样式见 _base.css;此类仅标记语义 + overflow) */
905
991
  .wf-scroll {
906
992
  overflow: auto;
907
993
  }
@@ -963,6 +1049,19 @@ body.wf-dragging {
963
1049
  }
964
1050
  }
965
1051
 
1052
+ @layer utilities {
1053
+ /* flex — 弹性盒 display 工具(补全 display 族:block/inline/inline-block/contents/hidden/flex)
1054
+ * 核心场景:响应式显隐的 flex 容器——`wf-hidden wf-flex@lg`(窄隐宽显且保持 flex 布局)。
1055
+ * 不可用 wf-block@lg 替代:block 会覆盖 wf-stack 的 display:flex,
1056
+ * 致 flex-direction/gap/mt-auto 全部静默失效(layouts-demo 侧栏 mt-auto 实测踩坑)。 */
1057
+ .wf-flex {
1058
+ display: flex;
1059
+ }
1060
+ @media (min-width: 640px) { .wf-flex\@sm { display: flex; } }
1061
+ @media (min-width: 768px) { .wf-flex\@md { display: flex; } }
1062
+ @media (min-width: 1024px) { .wf-flex\@lg { display: flex; } }
1063
+ }
1064
+
966
1065
  @layer layout {
967
1066
  /* container — 内容宽度约束居中 */
968
1067
  /* width: 100% 必须:margin: 0 auto 在 flex 父中阻止 stretch(宽度=内容)
@@ -992,10 +1091,13 @@ body.wf-dragging {
992
1091
 
993
1092
  @layer layout {
994
1093
  /* nowrap — 不换行(只管 flex-wrap——不定义 align-items,避免与
995
- wf-stretch 等对齐工具叠加冲突:双份 CSS 下 nowrap 后置曾覆盖 stretch) */
1094
+ wf-stretch 等对齐工具叠加冲突:双份 CSS 下 nowrap 后置曾覆盖 stretch;
1095
+ L3:gap 默认值 :where() 零优先级) */
996
1096
  .wf-nowrap {
997
1097
  display: flex;
998
1098
  flex-wrap: nowrap;
1099
+ }
1100
+ :where(.wf-nowrap) {
999
1101
  gap: var(--wf-gap, var(--wf-gap-md));
1000
1102
  }
1001
1103
  }
@@ -1038,6 +1140,20 @@ body.wf-dragging {
1038
1140
  .wf-py-xl { padding-top: var(--wf-space-xl); padding-bottom: var(--wf-space-xl); }
1039
1141
  .wf-py-2xl { padding-top: var(--wf-space-2xl); padding-bottom: var(--wf-space-2xl); }
1040
1142
 
1143
+ /* ── padding: 单侧顶/底(幽灵类防线抓出 wf-pt-md/wf-pb-md 误用——补全家族) ── */
1144
+ .wf-pt-xs { padding-top: var(--wf-space-xs); }
1145
+ .wf-pt-sm { padding-top: var(--wf-space-sm); }
1146
+ .wf-pt-md { padding-top: var(--wf-space-md); }
1147
+ .wf-pt-lg { padding-top: var(--wf-space-lg); }
1148
+ .wf-pt-xl { padding-top: var(--wf-space-xl); }
1149
+ .wf-pt-2xl { padding-top: var(--wf-space-2xl); }
1150
+ .wf-pb-xs { padding-bottom: var(--wf-space-xs); }
1151
+ .wf-pb-sm { padding-bottom: var(--wf-space-sm); }
1152
+ .wf-pb-md { padding-bottom: var(--wf-space-md); }
1153
+ .wf-pb-lg { padding-bottom: var(--wf-space-lg); }
1154
+ .wf-pb-xl { padding-bottom: var(--wf-space-xl); }
1155
+ .wf-pb-2xl { padding-bottom: var(--wf-space-2xl); }
1156
+
1041
1157
  /* ── margin:重置 ── */
1042
1158
  .wf-m-0 { margin: 0; }
1043
1159
  .wf-p-0 { padding: 0; }
@@ -1067,6 +1183,8 @@ body.wf-dragging {
1067
1183
  /* ── margin: auto(居中) ── */
1068
1184
  .wf-mx-auto { margin-left: auto; margin-right: auto; }
1069
1185
  .wf-my-auto { margin-top: auto; margin-bottom: auto; }
1186
+ .wf-mt-auto { margin-top: auto; } /* flex 列推底(侧栏 footer——曾写不存在类静默失效) */
1187
+ .wf-mb-auto { margin-bottom: auto; }
1070
1188
 
1071
1189
  /* ── gap:直接设置 gap 属性(不设 --wf-gap 变量——变量会继承污染子孙:
1072
1190
  壳 root wf-gap-none 曾让 KPI grid 的 gap: var(--wf-gap) = 0 卡无间距) ── */
@@ -26,7 +26,7 @@
26
26
  * ```
27
27
  */
28
28
  import type { Middleware } from '../types.ts';
29
- import type { Component, AsyncComponent } from '../client/vnode.ts';
29
+ import type { Component, AsyncComponent } from '../ui-dom/vnode.ts';
30
30
  declare module '../types.ts' {
31
31
  interface Context {
32
32
  ui: {
@@ -8,7 +8,7 @@
8
8
  * 与客户端 router() 共用同一份路由定义(route-match.ts),SPA/SSR 一个声明。
9
9
  */
10
10
  import type { Middleware } from '../types.ts';
11
- import type { RouteDef } from '../client/types.ts';
11
+ import type { RouteDef } from '../ui-dom/types.ts';
12
12
  export interface UiSsrOptions {
13
13
  /** 前端路由定义(与 router() 共享同一份) */
14
14
  routes: RouteDef[];
package/dist/ui/ssr.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * 产物为 HtmlSafe 标记的安全 HTML 片段,可直接内联进 ctx.ui.html 模板。
13
13
  */
14
- import type { Component, AsyncComponent } from '../client/vnode.ts';
14
+ import type { Component, AsyncComponent } from '../ui-dom/vnode.ts';
15
15
  import { HtmlSafe } from './html-safe.ts';
16
16
  export { HtmlSafe } from './html-safe.ts';
17
17
  export interface SsrOptions {
@@ -0,0 +1,44 @@
1
+ /**
2
+ * weifuwu/components — Confirm 确认对话框
3
+ *
4
+ * 声明式:基于 Modal 封装,footer 自带「取消 / 确定」按钮。
5
+ * 命令式:confirm() 中间件注入 ctx.confirm(),返回 Promise<boolean>。
6
+ */
7
+ import type { Component } from './vnode.ts';
8
+ import type { AppMiddleware } from './types.ts';
9
+ export interface ConfirmProps {
10
+ open?: boolean;
11
+ title?: string;
12
+ /** 提示内容(文本或任意 VNode) */
13
+ message?: any;
14
+ confirmText?: string;
15
+ cancelText?: string;
16
+ variant?: 'primary' | 'danger';
17
+ /** 对话框宽度,如 '500px'、'80%',默认 Modal 的 400px */
18
+ width?: string;
19
+ /** 遮罩点击是否取消(默认 false:危险操作防误触;显式传 true 可恢复) */
20
+ maskClosable?: boolean;
21
+ onConfirm?: () => void;
22
+ onCancel?: () => void;
23
+ }
24
+ /** 命令式 ctx.confirm 的选项(ConfirmProps 的子集) */
25
+ export interface ConfirmOptions {
26
+ title?: string;
27
+ confirmText?: string;
28
+ cancelText?: string;
29
+ variant?: 'primary' | 'danger';
30
+ width?: string;
31
+ maskClosable?: boolean;
32
+ }
33
+ /** 命令式 ctx.confirm 的注入类型(AppMiddleware<{}, ConfirmInjected>) */
34
+ export interface ConfirmInjected {
35
+ confirm: (message: string, options?: ConfirmOptions) => Promise<boolean>;
36
+ }
37
+ /**
38
+ * 命令式中间件:注入 ctx.confirm()
39
+ *
40
+ * 每次调用挂载 Confirm 组件到独立容器(mountVNode),
41
+ * resolve 后 callRefCleanup 清理(含 Modal 的 portal DOM)+ 移除容器。
42
+ */
43
+ export declare function confirm(): AppMiddleware<{}, ConfirmInjected>;
44
+ export declare const Confirm: Component<ConfirmProps>;
@@ -0,0 +1,70 @@
1
+ import type { Component } from './vnode.ts';
2
+ import type { AppMiddleware } from './types.ts';
3
+ export type NotificationType = 'success' | 'error' | 'info' | 'warning';
4
+ export type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
5
+ export interface NotificationItem {
6
+ id: string;
7
+ type: NotificationType;
8
+ title: string;
9
+ description?: string;
10
+ /** 自动关闭时间(ms),0 = 不自动关闭,默认 4500 */
11
+ duration?: number;
12
+ action?: {
13
+ label: string;
14
+ onClick: () => void;
15
+ };
16
+ }
17
+ export interface NotificationProps {
18
+ items?: NotificationItem[];
19
+ onRemove?: (id: string) => void;
20
+ position?: NotificationPosition;
21
+ /** 全局默认自动关闭时间(ms),默认 4500 */
22
+ duration?: number;
23
+ /** 最大显示条数,超出移除最早,默认 0 = 不限制 */
24
+ max?: number;
25
+ }
26
+ export interface NotificationOptions {
27
+ position?: NotificationPosition;
28
+ duration?: number;
29
+ max?: number;
30
+ }
31
+ /** 通知(对应 antd/EP Notification 队列式):title + description + icon + 操作,聚合角落 */
32
+ export declare const Notification: Component<NotificationProps>;
33
+ export interface NotificationInjected {
34
+ notification: {
35
+ (title: string, opts?: {
36
+ type?: NotificationType;
37
+ description?: string;
38
+ duration?: number;
39
+ action?: NotificationItem['action'];
40
+ }): void;
41
+ open: (opts: {
42
+ type?: NotificationType;
43
+ title: string;
44
+ description?: string;
45
+ duration?: number;
46
+ action?: NotificationItem['action'];
47
+ }) => void;
48
+ success: (opts: {
49
+ title: string;
50
+ description?: string;
51
+ duration?: number;
52
+ }) => void;
53
+ error: (opts: {
54
+ title: string;
55
+ description?: string;
56
+ duration?: number;
57
+ }) => void;
58
+ info: (opts: {
59
+ title: string;
60
+ description?: string;
61
+ duration?: number;
62
+ }) => void;
63
+ warning: (opts: {
64
+ title: string;
65
+ description?: string;
66
+ duration?: number;
67
+ }) => void;
68
+ };
69
+ }
70
+ export declare function notification(opts?: NotificationOptions): AppMiddleware<{}, NotificationInjected>;
@@ -0,0 +1,43 @@
1
+ import type { Component } from './vnode.ts';
2
+ import type { AppMiddleware } from './types.ts';
3
+ export type ToastType = 'success' | 'error' | 'info' | 'warning';
4
+ export type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center';
5
+ export interface ToastItem {
6
+ id: string;
7
+ type: ToastType;
8
+ message: string;
9
+ /** 此条目的自动消失时间(ms),覆盖 Toast 的默认 duration */
10
+ duration?: number;
11
+ /** 操作按钮(如"撤销"):点击不自动关闭,由回调自行移除 */
12
+ action?: {
13
+ label: string;
14
+ onClick: () => void;
15
+ };
16
+ }
17
+ export interface ToastProps {
18
+ toasts?: ToastItem[];
19
+ onRemove?: (id: string) => void;
20
+ /** 容器位置,默认 top-right */
21
+ position?: ToastPosition;
22
+ /** 全局默认自动消失时间(ms),0 = 不自动消失,默认 0 */
23
+ duration?: number;
24
+ /** 最大显示条数,超出时移除最早条目,默认 0 = 不限制 */
25
+ max?: number;
26
+ }
27
+ /** 命令式 ctx.toast 的全局配置 */
28
+ export interface ToastOptions {
29
+ position?: ToastPosition;
30
+ /** 默认自动消失时间(ms),0 = 不消失,默认 3000 */
31
+ duration?: number;
32
+ /** 最大显示条数,超出移除最早,默认 3 */
33
+ max?: number;
34
+ }
35
+ export declare const Toast: Component<ToastProps>;
36
+ /** 命令式 ctx.toast 的注入类型(AppMiddleware<{}, ToastInjected>) */
37
+ export interface ToastInjected {
38
+ toast: (message: string, type?: ToastType, duration?: number, action?: {
39
+ label: string;
40
+ onClick: () => void;
41
+ }) => void;
42
+ }
43
+ export declare function toast(opts?: ToastOptions): AppMiddleware<{}, ToastInjected>;
@@ -6,11 +6,12 @@
6
6
  * diff.ts → registry.ts(callRefCleanup)
7
7
  * render.ts 不依赖 diff.ts(单向,无环)
8
8
  */
9
+ import type { VNodeChild } from './vnode.ts';
9
10
  import type { WfuiContext } from './types.ts';
10
- export declare function patchValue(parent: Node, oldNode: Node | null, oldInput: any, newInput: any, ctx: WfuiContext): Node | null;
11
- export declare function patchProps(el: Element, oldProps: any, newProps: any): void;
11
+ export declare function patchValue(parent: Node, oldNode: Node | null, oldInput: VNodeChild, newInput: VNodeChild, ctx: WfuiContext): Node | null;
12
+ export declare function patchProps(el: Element, oldProps: Record<string, unknown> | null, newProps: Record<string, unknown>): void;
12
13
  /** 为无 key 的子节点自动分配位置 key,确保 keyed diff 正确性 */
13
- export declare function ensureKeys(oldChildren: any[], newChildren: any[]): void;
14
+ export declare function ensureKeys(oldChildren: VNodeChild[], newChildren: VNodeChild[]): void;
14
15
  /**
15
16
  * 将 children 映射到它们实际产生的 DOM 节点(每个 child 一个 Node[])。
16
17
  *
@@ -18,10 +19,10 @@ export declare function ensureKeys(oldChildren: any[], newChildren: any[]): void
18
19
  * null/boolean/Portal 产生 0 个。explicitNodes 提供限定范围(Fragment 子项
19
20
  * 用其自身 _childNodes),否则从 source(parent.childNodes 或给定快照)按计数游标分配。
20
21
  */
21
- export declare function mapChildDomNodes(source: Node[], children: any[]): (Node[] | null)[];
22
- export declare function normalize(children: any): any[];
22
+ export declare function mapChildDomNodes(source: Node[], children: VNodeChild[]): (Node[] | null)[];
23
+ export declare function normalize(children: VNodeChild): VNodeChild[];
23
24
  /**
24
25
  * keyed 子节点 diff。返回每个 new child 的 DOM 节点范围(newNodes,可为空)。
25
26
  * oldNodes:old children → 实际 DOM 节点(mapChildDomNodes 结果)。
26
27
  */
27
- export declare function patchKeyedChildren(parent: Node, oldChildren: any[], newChildren: any[], ctx: WfuiContext, oldNodes?: (Node[] | null)[], rangeStart?: Node | null): (Node[] | null)[];
28
+ export declare function patchKeyedChildren(parent: Node, oldChildren: VNodeChild[], newChildren: VNodeChild[], ctx: WfuiContext, oldNodes?: (Node[] | null)[], rangeStart?: Node | null): (Node[] | null)[];