dsh-m 0.9.58 → 0.9.59

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/CHANGELOG.md CHANGED
@@ -8,6 +8,12 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
8
8
 
9
9
  ## 中文
10
10
 
11
+ ### 0.9.59 优化:分类行左缘内缩 8px + 全屏下空转 ⌃ 收起钮按行数派生隐藏
12
+
13
+ - **分类行内缩(`f42e5be`)**:分类 chips 行与搜索框/卡片左缘齐平,小颗粒胶囊贴着大元素左缘视觉憋仄;分类行整体右移 8px 留出呼吸空间。仅作用分类行(ZoneChips),上方分区 chips 行不随动。`offsetLeft` 与 absolute 定位同以 `.dshm-chips` 的 padding 盒为原点 → `+N` 跟随、右侧筛选钉位、`offsetTop` 裁剪几何均不受影响。
14
+ - **⌃ 空转修复(`7cbdf11`)**:全屏等宽容器下分类 chips 可能排进 ≤ maxRows(2)行,展开态 `⌃` 收起钮点击后布局零变化(`hiddenCount=0` 连 `+N` 都不会出现),成死按钮。新增展开态行数测量 `expRows`(复用 `chipRows` 纯函数,measure 展开态分支只写 `expRows` 不动 `geom`),`⌃` 仅当展开行数 > maxRows 时渲染;ResizeObserver 在展开态也挂载——全屏↔窗口切换的宽度变化正是重测触发源,全屏下 `⌃` 自动隐藏、退回窗口自动恢复,行数含 `⌃` 自身故显隐收敛不振荡。
15
+ - **验证**:1224 项测试全绿;真实 DSH Web 实测窗口/全屏两态 `⌃` 显隐与收起行为、分类行 8px 内缩生效。
16
+
11
17
  ### 0.9.58 优化:+N 动态紧跟末可见分类,并与其框高一致
12
18
 
13
19
  - **位置(`4ade54f`)**:在 0.9.57 的独立安全槽位中,根据末可见分类 chip 的实测右缘设置 `+N` 左缘 = 右缘 + 6px;槽位由 52px 扩为 60px,窄宽时仍不与分类或筛选重叠。精选区没有筛选时不额外预留筛选 gutter;展开态 `⌃` 仍位于列表尾部。
@@ -432,6 +438,12 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
432
438
 
433
439
  ## English
434
440
 
441
+ ### Improved in 0.9.59 — 8px category-row inset and a derived visibility for the no-op collapse toggle
442
+
443
+ - **Category-row inset (`f42e5be`)**: the category chip row sat flush with the search box and card grid, and small pills hugging large elements felt cramped; the row now starts 8px further right for breathing room. Only the category row (ZoneChips) moves — the zone chip row above stays put. `offsetLeft` and absolute positioning share the `.dshm-chips` padding-box origin, so `+N` tracking, the pinned Filter trigger and `offsetTop`-based clip geometry are all unaffected.
444
+ - **No-op `⌃` fix (`7cbdf11`)**: at fullscreen width all category chips can fit within maxRows (2) rows, where clicking the expanded-state `⌃` collapse toggle changed nothing visually (`hiddenCount=0`, not even a `+N` appears) — a dead button. Added an expanded-state row measurement `expRows` (reusing the pure `chipRows` helper; the expanded measure branch only writes `expRows`, never `geom`), and `⌃` renders only when expanded rows exceed maxRows. The ResizeObserver now also observes while expanded — the width change of fullscreen↔window switches is exactly the remeasure trigger — so `⌃` hides itself in fullscreen and returns back in the window; counting includes `⌃` itself, so visibility converges without oscillation.
445
+ - **Verification**: 1224 tests pass; verified against real DSH Web for `⌃` visibility and collapse behavior in both window and fullscreen, and for the 8px category-row inset.
446
+
435
447
  ### Improved in 0.9.58 — the +N toggle follows the last visible category at matching height
436
448
 
437
449
  - **Position (`4ade54f`)**: within the 0.9.57 reserved, overlap-free slot, position `+N` from the measured right edge of the last visible category chip plus 6px. The slot grows from 52px to 60px to preserve clearance at narrow widths. Curated rows without a Filter trigger still reserve no unnecessary Filter gutter; expanded `⌃` remains at list end.
package/lib/client.js CHANGED
@@ -1573,7 +1573,7 @@ var h = React.createElement;
1573
1573
  var { useState, useEffect, useLayoutEffect, useCallback, useMemo, useRef } = React;
1574
1574
  var PLUGIN_ID = "dsh-m";
1575
1575
  var API = "/dshm";
1576
- var { DEFAULT_PAGE_SIZE: DEFAULT_PAGE_SIZE2, MARKET_PAGE_SIZES: MARKET_PAGE_SIZES2, pageItems: pageItems2, createZoneState: createZoneState2, normalizeMarketQuery: normalizeMarketQuery2, resetPageOnFilterChange: resetPageOnFilterChange2, normalizeMarketResponse: normalizeMarketResponse2, registryNotice: registryNotice2, zoneChips: zoneChips2, marketNotice: marketNotice2, searchSourceOf: searchSourceOf2, mergeLatestFields: mergeLatestFields2, countBeyondRows: countBeyondRows2, clipTopOf: clipTopOf2, visibleRowTop: visibleRowTop2, autoExpandDecision: autoExpandDecision2 } = (init_market_state(), __toCommonJS(market_state_exports));
1576
+ var { DEFAULT_PAGE_SIZE: DEFAULT_PAGE_SIZE2, MARKET_PAGE_SIZES: MARKET_PAGE_SIZES2, pageItems: pageItems2, createZoneState: createZoneState2, normalizeMarketQuery: normalizeMarketQuery2, resetPageOnFilterChange: resetPageOnFilterChange2, normalizeMarketResponse: normalizeMarketResponse2, registryNotice: registryNotice2, zoneChips: zoneChips2, marketNotice: marketNotice2, searchSourceOf: searchSourceOf2, mergeLatestFields: mergeLatestFields2, chipRows: chipRows2, countBeyondRows: countBeyondRows2, clipTopOf: clipTopOf2, visibleRowTop: visibleRowTop2, autoExpandDecision: autoExpandDecision2 } = (init_market_state(), __toCommonJS(market_state_exports));
1577
1577
  var { readMarketSnapshot: readMarketSnapshot2, writeMarketSnapshot: writeMarketSnapshot2, isDefaultFirstPageQuery: isDefaultFirstPageQuery2 } = (init_market_snapshot(), __toCommonJS(market_snapshot_exports));
1578
1578
  var { backdropCloseHandlers: backdropCloseHandlers2 } = (init_backdrop(), __toCommonJS(backdrop_exports));
1579
1579
  var { createMarkdown: createMarkdown2 } = (init_markdown(), __toCommonJS(markdown_exports));
@@ -2230,6 +2230,10 @@ var CSS = `
2230
2230
  .dshm-chip:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}
2231
2231
  .dshm-chip.on{background:var(--dsw-specific-sidebar-nav-item-active,rgba(38,49,72,.08));border-color:transparent;color:var(--dsw-alias-label-primary,inherit);font-weight:500}
2232
2232
  .dsvm-chipswrap{position:sticky;top:-14px;z-index:5;background:var(--dsw-alias-bg-base,#fff);padding:8px 0;margin:-8px 0;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.14))}
2233
+ /* 0.9.59 \u5206\u7C7B\u884C\u5DE6\u7F18\u5185\u7F29 8px\uFF1A\u4E0E\u641C\u7D22\u6846/\u5361\u7247\u5DE6\u7F18\u9F50\u5E73\u65F6\u80F6\u56CA\u884C\u89C6\u89C9\u618B\u4EC4\uFF0C\u6574\u4F53\u53F3\u79FB\u7559\u51FA\u547C\u5438\u7A7A\u95F4\u3002
2234
+ \u4EC5\u4F5C\u7528\u5206\u7C7B\u884C\uFF08ZoneChips\uFF09\uFF0C\u4E0A\u65B9\u5206\u533A chips \u884C\u4E0D\u968F\u52A8\uFF1BoffsetLeft \u4E0E absolute \u5B9A\u4F4D\u540C\u4EE5
2235
+ .dshm-chips \u7684 padding \u76D2\u4E3A\u539F\u70B9 \u2192 +N \u8DDF\u968F\u3001\u53F3\u4FA7\u7B5B\u9009\u9489\u4F4D\u3001offsetTop \u88C1\u526A\u51E0\u4F55\u5747\u4E0D\u53D7\u5F71\u54CD\u3002 */
2236
+ .dsvm-chipswrap .dshm-chips{padding-left:8px}
2233
2237
  .dsvm-pagejump{display:inline-flex;align-items:center;gap:4px;margin-left:8px}
2234
2238
  .dsvm-pagejump-input{width:56px;height:24px;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.28));background:transparent;color:var(--dsw-alias-label-secondary,#4b5563);border-radius:999px;padding:0 10px;font:inherit;font-size:12px;outline:none;text-align:center;transition:border-color .15s,color .15s}
2235
2239
  .dsvm-pagejump-input:hover{color:var(--dsw-alias-label-primary,inherit)}
@@ -2732,6 +2736,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2732
2736
  const chipsSignature = JSON.stringify(chips.map((c) => [c.id, c.labelKey ? lookup(c.labelKey) : c.label, c.count]));
2733
2737
  const [expanded, setExpanded] = useState(false);
2734
2738
  const [stuck, setStuck] = useState(false);
2739
+ const [expRows, setExpRows] = useState(0);
2735
2740
  const [geom, setGeom] = useState(null);
2736
2741
  const [rowHeight, setRowHeight] = useState(0);
2737
2742
  const wrapRef = useRef(null);
@@ -2742,7 +2747,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2742
2747
  const maxH = maxRows * (rowHeight || 22) + (maxRows - 1) * 6;
2743
2748
  const measure = useCallback(() => {
2744
2749
  const el = wrapRef.current;
2745
- if (!el || expanded) return;
2750
+ if (!el) return;
2746
2751
  const tops = [];
2747
2752
  let rh = 0;
2748
2753
  for (const k of el.children) {
@@ -2751,6 +2756,11 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2751
2756
  if (!rh && k.offsetHeight) rh = k.offsetHeight;
2752
2757
  }
2753
2758
  if (!tops.length) return;
2759
+ if (expanded) {
2760
+ const rows = chipRows2(tops);
2761
+ setExpRows((prev) => prev === rows ? prev : rows);
2762
+ return;
2763
+ }
2754
2764
  setGeom((prev) => {
2755
2765
  const clipTopV = clipTopOf2(tops, maxRows);
2756
2766
  const hiddenCount2 = countBeyondRows2(tops, maxRows);
@@ -2784,7 +2794,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2784
2794
  if (d.expand) setExpanded(true);
2785
2795
  }, [active, activeIdx, expanded, geom]);
2786
2796
  useLayoutEffect(() => {
2787
- if (!expanded) measure();
2797
+ measure();
2788
2798
  }, [chipsSignature, active, expanded, zone, stuck, rowHeight, measure]);
2789
2799
  useEffect(() => {
2790
2800
  if (expanded || !geom || typeof requestAnimationFrame !== "function") return;
@@ -2793,7 +2803,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2793
2803
  }, [geom, expanded, measure]);
2794
2804
  useEffect(() => {
2795
2805
  const el = wrapRef.current;
2796
- if (!el || expanded || typeof ResizeObserver === "undefined") return;
2806
+ if (!el || typeof ResizeObserver === "undefined") return;
2797
2807
  let raf = 0;
2798
2808
  const ro = new ResizeObserver(() => {
2799
2809
  cancelAnimationFrame(raf);
@@ -2804,7 +2814,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2804
2814
  ro.disconnect();
2805
2815
  cancelAnimationFrame(raf);
2806
2816
  };
2807
- }, [expanded, measure]);
2817
+ }, [measure]);
2808
2818
  useEffect(() => {
2809
2819
  if (expanded || typeof document === "undefined" || !document.fonts?.ready) return;
2810
2820
  let cancelled = false;
@@ -2878,7 +2888,9 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2878
2888
  onClick: () => setExpanded(true)
2879
2889
  }, `+${hiddenCount}`) : null,
2880
2890
  expanded ? [
2881
- h("button", {
2891
+ // 0.9.59:仅当展开布局真实超过 maxRows 行才渲染 ⌃——否则收起是零变化空操作(死按钮)。
2892
+ // 行数含 ⌃ 自身:若它恰好独占一行,隐藏后行数回落仍 ≤ maxRows,显隐收敛不振荡。
2893
+ expRows > maxRows ? h("button", {
2882
2894
  key: "collapse",
2883
2895
  "data-chip": "1",
2884
2896
  className: "dshm-chip",
@@ -2888,7 +2900,7 @@ function ZoneChips({ zone, counts, labels, active, onPick, trailing, wrapTitle }
2888
2900
  if (active) autoRef.current = active;
2889
2901
  setExpanded(false);
2890
2902
  }
2891
- }, "\u2303"),
2903
+ }, "\u2303") : null,
2892
2904
  trailing || null
2893
2905
  ] : null
2894
2906
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-m",
3
- "version": "0.9.58",
3
+ "version": "0.9.59",
4
4
  "description": "可自定义收录清单的 DSH 插件市场:收录、安装、卸载、升级一站完成,附 agent 工具与 dshm CLI。",
5
5
  "license": "MIT",
6
6
  "type": "module",