dsh-wisp 1.31.0 → 1.33.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.
package/README.md CHANGED
@@ -448,6 +448,75 @@ node tools/audit-log.mjs --confirm <manifest> # 生成后:并入代理登
448
448
 
449
449
  ## 变更
450
450
 
451
+ ### 1.33.0
452
+
453
+ **子菜单改成在**旁边**弹出。** 上一版做成了"在行下面内联展开" —— 那是网页的手风琴,
454
+ 不是菜单栏。真正的 GUI 级联菜单(cascading menu / flyout)形状不一样:
455
+
456
+ ```
457
+ ┌──────────────────┐ ┌────────────────┐
458
+ │ 外观 深海女仆 ▸│──▶│ ✓ 深海女仆 │ ← 面板浮在行的**右侧**,
459
+ │ 行为 4/5 开 ▸│ │ 原版女仆 │ 与父行顶部对齐,
460
+ │ 位置 右下角 ▸│ │ 素绘女仆 │ 不把下面的内容推下去
461
+ └──────────────────┘ └────────────────┘
462
+ ```
463
+
464
+ 做对它的关键点,少一条都不算:
465
+
466
+ | 细节 | 为什么 |
467
+ |---|---|
468
+ | **面板是菜单的兄弟节点**(同一个 layer) | 才能探出菜单外面;内联展开永远做不到这一点。 |
469
+ | **右边放不下就翻到左侧**(▸ 变 ◂) | 否则子菜单被屏幕边缘切掉。 |
470
+ | **指针在「行」与「面板」之间算同一区域** | 两边都挂 enter/leave:任一边进入取消关闭,两边都离开才开始计宽限。 |
471
+ | **悬停是预览,点击是决定** | 悬停打开的随鼠标移开关闭;**点开的被钉住**,再点一次才收。 |
472
+ | **键盘 → / ←** | → 进子面板(焦点送进去),← 关面板并把焦点还给父行。 |
473
+ | **Esc 一次退一层** | 先关子面板,再关菜单。 |
474
+
475
+ **过程中修掉两个真 bug**(都是测试逼出来的):
476
+
477
+ 1. **子面板泄漏**:`closeMenu` 里那句收面板写成了 `if (menuEl) closeFlyout()` ——
478
+ 而那时 `menuEl` **已经被置空**,于是关菜单时子面板被**丢在屏幕上**。
479
+ 2. **Esc 永远退不到子面板**:`onKey` 的**第一句**就是"Escape → 关菜单",
480
+ 我那条"先关子面板"的分支排在后面,**永远轮不到**。诊断信息
481
+ `面板=还开着 菜单=被关了` 一眼看穿了它。
482
+
483
+ 另外把四个行构造器(动作行 / 开关行 / 滑块 / 罗盘)从 `openMenu` 内部提到了模块级 ——
484
+ 子面板要用同一批构造器,藏在 `openMenu` 里面就是一个 `ReferenceError`。
485
+
486
+ 预检 524 → **529 项**:面板是菜单的兄弟、有定位、不与菜单重叠、悬停延迟、宽限、
487
+ 指针移进面板算同一区域、路过不弹、触屏不弹、点击钉住、再点收起、手风琴、
488
+ → 进面板并聚焦、← 关闭并还焦点、Esc 逐层退出。
489
+
490
+ ### 1.32.0
491
+
492
+ ### 1.32.0
493
+
494
+ **分组改成悬停展开、移开收起**(点一下仍然是"钉住")。
495
+
496
+ 这一条本来就是标准交互,上一版只做了"点开/点关",属于设计盲区。补上之后,
497
+ 真正要小心的地方不在于"加个 mouseenter",而在于下面这几条 —— 少一条都比不做更糟:
498
+
499
+ | 细节 | 为什么必须 |
500
+ |---|---|
501
+ | **展开有延迟**(140 ms) | 鼠标只是**路过**那一行就展开 = 抖动。这就是 hover intent。 |
502
+ | **移开有宽限**(260 ms) | 斜着往子项移动时,中途不能收。 |
503
+ | **子项与标题在同一个悬停区**(`div.wisp-menu-group`) | 从标题移到子项**不该算移开**。这是这类交互最常见的翻车点。 |
504
+ | **点击 = 钉住** | 悬停是预览、点击是决定。点开的那一组鼠标移开也不关,再点一次才收起。 |
505
+ | **触屏不触发悬停** | 判 `pointerType`。不判的话手指一碰就会莫名其妙展开。 |
506
+ | **焦点在那一组里时不关** | 否则键盘用户正操作着,鼠标一动组就没了。 |
507
+ | **手风琴** | 悬停到另一组会解除上一组的钉住 —— 同时开两组看不清。 |
508
+
509
+ **顺手抓到一个真 bug**:焦点保护第一版写的是"焦点还在菜单里就不许关" ——
510
+ 而菜单**一打开就会把焦点放到第一项**,所以那条件**永远为真**,
511
+ 悬停收起等于**永远不会触发**。改成只看"焦点在不在**这一组**里"。
512
+ 第一版还用了一个"组名 → 元素"的映射,实测和重画后的 DOM 对不上(组照样关);
513
+ 现在改成从焦点**向上走**、遇到带 `data-group-block` 的祖先就算命中 —— 不依赖任何外部映射。
514
+
515
+ 预检 502 → **524 项**:延迟、宽限、路过不展开、子项在同一悬停区、
516
+ 触屏不悬停但点击可用、点击钉住、再点收起、手风琴、焦点保护、焦点离开后规则恢复。
517
+
518
+ ### 1.31.0
519
+
451
520
  ### 1.31.0
452
521
 
453
522
  **菜单重做。** 上一版只是"把 19 个条目收进三个分组" —— 那是分类,不是交互设计。