weifuwu 0.66.0 → 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.
@@ -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;
@@ -3417,6 +3424,104 @@ code {
3417
3424
  .wf-descriptions--sm .wf-descriptions-value { font-size: var(--wf-font-size-xs); }
3418
3425
  .wf-descriptions--lg .wf-descriptions-value { font-size: var(--wf-font-size-base); }
3419
3426
 
3427
+ .wf-diffview {
3428
+ display: flex;
3429
+ flex-direction: column;
3430
+ border: 1px solid var(--wf-color-border);
3431
+ border-radius: var(--wf-radius-md);
3432
+ overflow: hidden;
3433
+ background: var(--wf-color-bg);
3434
+ font-family: var(--wf-font-mono, 'SFMono-Regular', Consolas, monospace);
3435
+ font-size: 13px;
3436
+ line-height: 1.6;
3437
+ min-width: 0;
3438
+ }
3439
+
3440
+ /* ── header ── */
3441
+ .wf-diffview-header {
3442
+ display: flex;
3443
+ align-items: center;
3444
+ gap: 8px;
3445
+ padding: 8px 12px;
3446
+ background: var(--wf-color-fill);
3447
+ border-bottom: 1px solid var(--wf-color-border);
3448
+ font-size: 12px;
3449
+ flex-shrink: 0;
3450
+ }
3451
+ .wf-diffview-title--old {
3452
+ color: var(--wf-color-danger-text);
3453
+ }
3454
+ .wf-diffview-title--new {
3455
+ color: var(--wf-color-success-text);
3456
+ }
3457
+ .wf-diffview-arrow {
3458
+ color: var(--wf-color-text-tertiary);
3459
+ }
3460
+
3461
+ /* ── body ── */
3462
+ .wf-diffview-body {
3463
+ overflow: auto;
3464
+ max-height: 480px;
3465
+ padding: 8px 0;
3466
+ }
3467
+
3468
+ .wf-diffview-row {
3469
+ display: flex;
3470
+ gap: 8px;
3471
+ padding: 0 12px;
3472
+ white-space: pre;
3473
+ }
3474
+ .wf-diffview-sign {
3475
+ width: 14px;
3476
+ flex-shrink: 0;
3477
+ user-select: none;
3478
+ color: var(--wf-color-text-tertiary);
3479
+ }
3480
+ .wf-diffview-line {
3481
+ min-width: 0;
3482
+ overflow: visible;
3483
+ }
3484
+
3485
+ .wf-diffview-row--add {
3486
+ background: var(--wf-color-success-bg, rgba(0, 128, 0, 0.08));
3487
+ }
3488
+ .wf-diffview-row--add .wf-diffview-sign {
3489
+ color: var(--wf-color-success-text);
3490
+ }
3491
+ .wf-diffview-row--remove {
3492
+ background: var(--wf-color-danger-bg, rgba(255, 0, 0, 0.06));
3493
+ }
3494
+ .wf-diffview-row--remove .wf-diffview-sign {
3495
+ color: var(--wf-color-danger-text);
3496
+ }
3497
+
3498
+ /* ── 折叠块 ── */
3499
+ .wf-diffview-fold {
3500
+ display: flex;
3501
+ align-items: center;
3502
+ justify-content: center;
3503
+ margin: 2px 12px;
3504
+ padding: 4px 8px;
3505
+ border: 1px dashed var(--wf-color-border);
3506
+ border-radius: var(--wf-radius-sm);
3507
+ color: var(--wf-color-text-secondary);
3508
+ font-size: 12px;
3509
+ cursor: pointer;
3510
+ background: var(--wf-color-bg-subtle, var(--wf-color-fill));
3511
+ user-select: none;
3512
+ min-height: 28px;
3513
+ }
3514
+ .wf-diffview-fold:hover {
3515
+ background: var(--wf-color-fill);
3516
+ }
3517
+
3518
+ .wf-diffview-overflow {
3519
+ padding: 8px 12px;
3520
+ color: var(--wf-color-text-tertiary);
3521
+ font-size: 12px;
3522
+ text-align: center;
3523
+ }
3524
+
3420
3525
  /* weifuwu/components — Divider */
3421
3526
 
3422
3527
  .wf-divider {
@@ -4742,6 +4847,93 @@ code {
4742
4847
  }
4743
4848
  }
4744
4849
 
4850
+ .wf-kanban {
4851
+ display: flex;
4852
+ gap: 12px;
4853
+ align-items: flex-start;
4854
+ overflow-x: auto;
4855
+ padding: 4px;
4856
+ }
4857
+
4858
+ .wf-kanban-col {
4859
+ flex: 1 1 220px;
4860
+ min-width: var(--wf-kanban-col-min-width);
4861
+ max-width: var(--wf-kanban-col-max-width);
4862
+ background: var(--wf-color-bg-subtle, var(--wf-color-fill));
4863
+ border-radius: var(--wf-radius-md);
4864
+ border: 1px solid var(--wf-color-border);
4865
+ display: flex;
4866
+ flex-direction: column;
4867
+ transition: border-color var(--wf-dur-fast) var(--wf-ease-out);
4868
+ }
4869
+ .wf-kanban-col:hover {
4870
+ border-color: var(--wf-color-primary);
4871
+ border-style: dashed;
4872
+ }
4873
+
4874
+ .wf-kanban-col-header {
4875
+ display: flex;
4876
+ align-items: center;
4877
+ justify-content: space-between;
4878
+ padding: 10px 12px;
4879
+ font-weight: 600;
4880
+ font-size: 13px;
4881
+ }
4882
+ .wf-kanban-col-count {
4883
+ font-size: 12px;
4884
+ color: var(--wf-color-text-tertiary);
4885
+ background: var(--wf-color-fill);
4886
+ border-radius: 50%;
4887
+ padding: 1px 8px;
4888
+ }
4889
+
4890
+ .wf-kanban-col-body {
4891
+ padding: 0 8px 8px;
4892
+ display: flex;
4893
+ flex-direction: column;
4894
+ gap: 8px;
4895
+ min-height: 40px;
4896
+ }
4897
+
4898
+ .wf-kanban-card {
4899
+ background: var(--wf-color-bg);
4900
+ border: 1px solid var(--wf-color-border);
4901
+ border-radius: var(--wf-radius-sm);
4902
+ padding: 10px 12px;
4903
+ cursor: grab;
4904
+ display: flex;
4905
+ align-items: center;
4906
+ gap: 8px;
4907
+ transition: border-color var(--wf-dur-fast) var(--wf-ease-out), transform var(--wf-dur-fast) var(--wf-ease-out);
4908
+ }
4909
+ .wf-kanban-card:hover {
4910
+ border-color: var(--wf-color-primary);
4911
+ }
4912
+ .wf-kanban-card:active {
4913
+ cursor: grabbing;
4914
+ }
4915
+ .wf-kanban-card:hover {
4916
+ border-color: var(--wf-color-primary);
4917
+ }
4918
+ .wf-kanban-card[aria-grabbed='true'] {
4919
+ opacity: 0.4;
4920
+ }
4921
+
4922
+ .wf-kanban-card-title {
4923
+ font-size: 13px;
4924
+ line-height: 1.5;
4925
+ min-width: 0;
4926
+ }
4927
+
4928
+ .wf-kanban-tag {
4929
+ font-size: 11px;
4930
+ color: var(--wf-color-primary-text);
4931
+ background: var(--wf-color-primary-bg, rgba(79, 110, 247, 0.12));
4932
+ border-radius: var(--wf-radius-xs);
4933
+ padding: 1px 6px;
4934
+ flex-shrink: 0;
4935
+ }
4936
+
4745
4937
  /* weifuwu/components — Label(与 Input/Field 的 label 样式同源) */
4746
4938
 
4747
4939
  .wf-label {
@@ -5731,6 +5923,77 @@ code {
5731
5923
  .wf-pin-input--sm .wf-pin-input-cell { font-size: var(--wf-font-size-base); width: 2.4em; height: 2.4em; }
5732
5924
  .wf-pin-input--lg .wf-pin-input-cell { font-size: var(--wf-font-size-2xl); width: 2.8em; height: 2.8em; }
5733
5925
 
5926
+ .wf-pipeline {
5927
+ position: relative;
5928
+ display: inline-block;
5929
+ max-width: 100%;
5930
+ }
5931
+
5932
+ .wf-pipeline-svg {
5933
+ display: block;
5934
+ overflow: visible;
5935
+ }
5936
+
5937
+ .wf-pipeline-edge {
5938
+ fill: none;
5939
+ stroke: var(--wf-color-border);
5940
+ stroke-width: 1.5;
5941
+ }
5942
+
5943
+ .wf-pipeline-nodes {
5944
+ position: absolute;
5945
+ inset: 0;
5946
+ pointer-events: none;
5947
+ }
5948
+
5949
+ .wf-pipeline-node {
5950
+ position: absolute;
5951
+ transform: translate(-50%, -50%);
5952
+ padding: 8px 14px;
5953
+ min-width: 72px;
5954
+ max-width: 120px;
5955
+ text-align: center;
5956
+ background: var(--wf-color-bg);
5957
+ border: 1px solid var(--wf-color-border);
5958
+ border-radius: var(--wf-radius-md);
5959
+ font-size: 13px;
5960
+ font-weight: 500;
5961
+ pointer-events: auto;
5962
+ white-space: nowrap;
5963
+ overflow: hidden;
5964
+ text-overflow: ellipsis;
5965
+ box-shadow: var(--wf-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));
5966
+ }
5967
+
5968
+ .wf-pipeline-node--success {
5969
+ border-color: var(--wf-color-success-text);
5970
+ color: var(--wf-color-success-text);
5971
+ background: var(--wf-color-success-bg, rgba(20, 83, 45, 0.06));
5972
+ }
5973
+ .wf-pipeline-node--running {
5974
+ border-color: var(--wf-color-primary);
5975
+ color: var(--wf-color-primary-text);
5976
+ background: var(--wf-color-primary-bg, rgba(79, 110, 247, 0.08));
5977
+ }
5978
+ .wf-pipeline-node--error {
5979
+ border-color: var(--wf-color-danger-text);
5980
+ color: var(--wf-color-danger-text);
5981
+ background: var(--wf-color-danger-bg, rgba(255, 0, 0, 0.06));
5982
+ }
5983
+ .wf-pipeline-node--pending {
5984
+ border-color: var(--wf-color-border);
5985
+ color: var(--wf-color-text-tertiary);
5986
+ background: var(--wf-color-fill);
5987
+ }
5988
+
5989
+ .wf-pipeline-warn {
5990
+ position: absolute;
5991
+ bottom: -24px;
5992
+ left: 0;
5993
+ font-size: 12px;
5994
+ color: var(--wf-color-warning-text);
5995
+ }
5996
+
5734
5997
  /* weifuwu/components — Popover */
5735
5998
 
5736
5999
  .wf-popover-wrap {
@@ -6532,6 +6795,12 @@ code {
6532
6795
  text-align: center;
6533
6796
  }
6534
6797
 
6798
+ .wf-sparkline {
6799
+ display: inline-block;
6800
+ vertical-align: middle;
6801
+ flex-shrink: 0;
6802
+ }
6803
+
6535
6804
  /* weifuwu/components — StatCard */
6536
6805
 
6537
6806
  .wf-stat {
@@ -7522,6 +7791,99 @@ code {
7522
7791
  to { opacity: 1; }
7523
7792
  }
7524
7793
 
7794
+ .wf-tour-overlay {
7795
+ position: fixed;
7796
+ inset: 0;
7797
+ z-index: var(--wf-z-tour);
7798
+ outline: none;
7799
+ }
7800
+
7801
+ .wf-tour-mask {
7802
+ position: absolute;
7803
+ inset: 0;
7804
+ background: var(--wf-overlay);
7805
+ }
7806
+
7807
+ .wf-tour-highlight {
7808
+ position: fixed;
7809
+ border-radius: var(--wf-radius-sm);
7810
+ box-shadow: 0 0 0 9999px var(--wf-overlay), 0 0 0 2px var(--wf-color-primary);
7811
+ z-index: 1;
7812
+ pointer-events: none;
7813
+ transition: all var(--wf-dur-fast) var(--wf-ease-out);
7814
+ }
7815
+
7816
+ .wf-tour-bubble {
7817
+ position: fixed;
7818
+ z-index: 1; /* 同层 DOM 顺序裁决(bubble 在 highlight 后 = 最上) */
7819
+ min-width: var(--wf-tour-min-width);
7820
+ max-width: 360px;
7821
+ background: var(--wf-color-bg);
7822
+ border: 1px solid var(--wf-color-border);
7823
+ border-radius: var(--wf-radius-md);
7824
+ box-shadow: var(--wf-shadow-lg, 0 12px 32px rgba(0, 0, 0, 0.12));
7825
+ padding: 16px;
7826
+ display: flex;
7827
+ flex-direction: column;
7828
+ gap: 8px;
7829
+ }
7830
+
7831
+ .wf-tour-bubble-header {
7832
+ display: flex;
7833
+ align-items: center;
7834
+ justify-content: space-between;
7835
+ gap: 8px;
7836
+ }
7837
+ .wf-tour-title {
7838
+ font-weight: 600;
7839
+ font-size: 14px;
7840
+ }
7841
+ .wf-tour-step {
7842
+ font-size: 12px;
7843
+ color: var(--wf-color-text-tertiary);
7844
+ flex-shrink: 0;
7845
+ }
7846
+
7847
+ .wf-tour-content {
7848
+ font-size: 13px;
7849
+ color: var(--wf-color-text-secondary);
7850
+ line-height: 1.6;
7851
+ }
7852
+
7853
+ .wf-tour-actions {
7854
+ display: flex;
7855
+ justify-content: flex-end;
7856
+ gap: 8px;
7857
+ margin-top: 4px;
7858
+ }
7859
+
7860
+ .wf-tour-btn {
7861
+ min-height: 32px;
7862
+ padding: 0 14px;
7863
+ border-radius: var(--wf-radius-sm);
7864
+ border: 1px solid var(--wf-color-border);
7865
+ background: var(--wf-color-bg);
7866
+ color: var(--wf-color-text);
7867
+ font-size: 13px;
7868
+ cursor: pointer;
7869
+ display: inline-flex;
7870
+ align-items: center;
7871
+ justify-content: center;
7872
+ }
7873
+ .wf-tour-btn--primary {
7874
+ background: var(--wf-color-primary);
7875
+ border-color: var(--wf-color-primary);
7876
+ color: var(--wf-color-on-brand);
7877
+ }
7878
+ .wf-tour-btn--ghost {
7879
+ background: transparent;
7880
+ border-color: transparent;
7881
+ color: var(--wf-color-text-secondary);
7882
+ }
7883
+ .wf-tour-btn:hover {
7884
+ filter: brightness(0.95);
7885
+ }
7886
+
7525
7887
  /* weifuwu/components — Transfer */
7526
7888
 
7527
7889
  .wf-transfer {
@@ -7803,6 +8165,71 @@ code {
7803
8165
  white-space: nowrap;
7804
8166
  }
7805
8167
 
8168
+ .wf-treeselect {
8169
+ position: relative;
8170
+ display: inline-block;
8171
+ min-width: var(--wf-treeselect-min-width);
8172
+ max-width: var(--wf-treeselect-max-width);
8173
+ }
8174
+
8175
+ .wf-treeselect-trigger {
8176
+ display: flex;
8177
+ align-items: center;
8178
+ justify-content: space-between;
8179
+ gap: 8px;
8180
+ padding: 7px 12px;
8181
+ border: 1px solid var(--wf-color-border);
8182
+ border-radius: var(--wf-radius-sm);
8183
+ background: var(--wf-color-bg);
8184
+ cursor: pointer;
8185
+ min-height: 36px;
8186
+ user-select: none;
8187
+ }
8188
+ .wf-treeselect-trigger:hover {
8189
+ border-color: var(--wf-color-primary);
8190
+ }
8191
+ .wf-treeselect-trigger--open {
8192
+ border-color: var(--wf-color-primary);
8193
+ box-shadow: 0 0 0 2px var(--wf-color-primary-bg, rgba(79, 110, 247, 0.15));
8194
+ }
8195
+
8196
+ .wf-treeselect-placeholder {
8197
+ color: var(--wf-color-text-tertiary);
8198
+ font-size: 13px;
8199
+ }
8200
+ .wf-treeselect-label {
8201
+ font-size: 13px;
8202
+ min-width: 0;
8203
+ overflow: hidden;
8204
+ text-overflow: ellipsis;
8205
+ white-space: nowrap;
8206
+ }
8207
+
8208
+ .wf-treeselect-arrow {
8209
+ width: 0;
8210
+ height: 0;
8211
+ border-left: 4px solid transparent;
8212
+ border-right: 4px solid transparent;
8213
+ border-top: 5px solid var(--wf-color-text-tertiary);
8214
+ transition: transform var(--wf-dur-fast) var(--wf-ease-out);
8215
+ flex-shrink: 0;
8216
+ }
8217
+ .wf-treeselect-arrow--open {
8218
+ transform: rotate(180deg);
8219
+ }
8220
+
8221
+ .wf-treeselect-dropdown {
8222
+ /* position: fixed + top/left/width 由 JS(usePopupPosition)提供 */
8223
+ z-index: var(--wf-z-popover);
8224
+ background: var(--wf-color-bg);
8225
+ border: 1px solid var(--wf-color-border);
8226
+ border-radius: var(--wf-radius-md);
8227
+ box-shadow: var(--wf-shadow-md, 0 4px 16px rgba(0, 0, 0, 0.1));
8228
+ padding: 4px;
8229
+ max-height: var(--wf-treeselect-dropdown-max-height);
8230
+ overflow: auto;
8231
+ }
8232
+
7806
8233
  /* weifuwu/components — Typography */
7807
8234
 
7808
8235
  .wf-title {
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) => {
@@ -4439,6 +4439,8 @@ function createSsrContext(serverCtx, dataStore) {
4439
4439
  execCommand: () => false,
4440
4440
  selectionText: () => null,
4441
4441
  getSelection: () => null,
4442
+ queryCommandState: () => false,
4443
+ queryCommandValue: () => "",
4442
4444
  viewportHeight: () => 0,
4443
4445
  scrollTop: () => 0,
4444
4446
  hash: () => "",
@@ -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;
@@ -155,3 +155,20 @@
155
155
  | **JSONViewer** | 新增 | 递归折叠 + 类型色 + 路径复制 + 懒展开(ToolCallCard 已接入) |
156
156
 
157
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` 第七批。
@@ -228,6 +228,9 @@ const MyComp: Component = (_init, ctx) => {
228
228
  ```
229
229
 
230
230
  **规则**:
231
+ - 拖拽统一 `ctx.ui.useDragDrop`(drop 侧 dropProps + drag 侧 dragProps:draggable/
232
+ onDragStart/onDragEnd)——**dragstart 期间禁止重渲染**(渲染替换源元素中断拖拽;
233
+ 身份/位置在渲染期闭包绑定,拖拽视觉高亮用 CSS :hover)
231
234
  - 复制统一 `browser.copyText`(clipboard + 降级——勿自建 textarea+execCommand)
232
235
  - 键盘导航用 `browser.activeElement()`(勿 document.activeElement)
233
236
  - 存储用 `browser.storageGet/Set`(勿 localStorage 裸调)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.66.0",
4
+ "version": "0.67.0",
5
5
  "description": "AI SaaS framework — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {