dsh-quick-actions 0.2.0-rc.1 → 0.2.0-rc.2

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.en.md CHANGED
@@ -9,7 +9,7 @@ Preset Quick Actions ship with the package and are read-only — you can hide or
9
9
  ## What it does
10
10
 
11
11
  - **Send Actions**: load a piece of static text into the draft and submit it through the official path. There is exactly one loading path, `setDraft(text)` → `submit()`.
12
- - **Three layouts**: a ribbon above the input, a bar inside it, or a single launcher opening a searchable panel. Switch at any time.
12
+ - **Three layouts**: a ribbon above the input, a bar under it, or a single launcher opening a searchable panel. Switch at any time.
13
13
  - **Per-action send confirmation**, on by default and yours to change.
14
14
  - **Text starting with `/` is a valid Command Send Action**, adjudicated by DSH itself.
15
15
  - Presets and customs are capped at **50 combined**. At the cap, adding and cloning stop; if an upgrade or a config change pushes existing state past it, **no data is lost** — adding and cloning are simply refused until you are back under it.
@@ -54,7 +54,7 @@ Then restart the web profile. One package is the whole thing: it carries `dsh.bu
54
54
  ```sh
55
55
  mkdir -p /tmp/quick-actions
56
56
  pnpm --filter dsh-quick-actions pack --pack-destination /tmp/quick-actions
57
- dsh plugin --profile web add /tmp/quick-actions/dsh-quick-actions-0.2.0-rc.1.tgz
57
+ dsh plugin --profile web add /tmp/quick-actions/dsh-quick-actions-0.2.0-rc.2.tgz
58
58
  ```
59
59
 
60
60
  The `--filter` form works from anywhere in the repository; from the package directory itself, `pnpm pack --pack-destination /tmp/quick-actions` is the same thing.
@@ -123,6 +123,7 @@ Field rules:
123
123
  - `label` and `text` are required; `icon` and `confirm` are optional, and `confirm` defaults to `true`.
124
124
  - An invalid preset (a missing field, a duplicate `id`, a catalog over 50 entries) makes **plugin loading fail loudly** and lists every problem at once, rather than truncating silently.
125
125
  - `presets` sits under the same row's `config` as your action data (see "Settings paths" below), and this plugin never writes it. It is a DSH volatile field: editing it while the profile runs reaches the Quick Actions immediately; an invalid catalog written that way shows a catalog error in the Quick Actions area, and the next profile restart fails plugin loading with the list of problems.
126
+ - **Declare them in the active profile's own `cordis.patch.yml` only.** Do not put this plugin's `config` in the home patch (`<DSH_HOME>/cordis.patch.yml`) or a `dsh --patch` overlay: DSH replaces a patch row's `config` whole, so that layer hides the action data stored on this row (the UI falls back to defaults; the data on disk is still there), and DSH refuses every save from then on — the UI reports the save as refused, and retrying never succeeds. Remove this plugin's row from that layer and restart the profile to recover.
126
127
 
127
128
  Users can hide or clone a preset but never edit or delete it; a clone becomes an ordinary Custom Quick Action.
128
129
 
@@ -133,7 +134,7 @@ Layout is a global persisted setting, switched in the management panel:
133
134
  | Value | Name | Where |
134
135
  |---|---|---|
135
136
  | `ribbon` (default) | Action ribbon | One row above the input, matching its width |
136
- | `bar` | Action bar | One row inside the input; whatever does not fit folds into "more" |
137
+ | `bar` | Action bar | One row under the input, beside DSH's own usage info, as wide as its content and at most as wide as the input card; whatever does not fit folds into "more" |
137
138
  | `launcher` | Single launcher | One entry button opening a searchable panel |
138
139
 
139
140
  `bar` and `launcher` share the same searchable panel, and the search matches labels and texts only. The management panel is where you reorder, hide, restore and clone presets, create, edit, enable and delete custom actions, and switch layout.
@@ -193,7 +194,7 @@ Cross-version data compatibility is the Host's job: new presets are appended to
193
194
  dsh plugin --profile web remove dsh-quick-actions
194
195
  ```
195
196
 
196
- Both the dependency and the layer in `dsh.profile.bundles` go away. After a profile restart the actions are gone. The `id: composer-quick-actions` row in `cordis.patch.yml` stays as it is — your actions live in its `config`, and a reinstall picks the row back up by id, so they come back. If you uninstall without reinstalling, the profile logs a `patch: entry "composer-quick-actions" not found` warning for that row on every start; it does not block startup, and step 1 below removes it.
197
+ Both the dependency and the layer in `dsh.profile.bundles` go away. After a profile restart the actions are gone. The `id: composer-quick-actions` row in `cordis.patch.yml` stays as it is — your actions live in its `config`, and a reinstall picks the row back up by id, so they come back. If you uninstall without reinstalling, that row is left addressing nothing: it does not block startup, `dsh --profile web --dump-config` reports it as `patch: entry "composer-quick-actions" not found`, and step 1 below removes it.
197
198
 
198
199
  **Full manual cleanup** (uninstalling does none of this, because a reinstall should restore your actions):
199
200
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  ## 能做什么
10
10
 
11
11
  - **发送动作**:把一段静态文本装载进草稿并按官方路径提交,装载路径只有一条 `setDraft(text)` → `submit()`。
12
- - **三种布局**:输入框上方的动作带、输入框内的操作栏、单入口的可搜索面板,随时切换。
12
+ - **三种布局**:输入框上方的动作带、输入框下方的操作栏、单入口的可搜索面板,随时切换。
13
13
  - **每个动作可单独设置发送确认**,默认开启,之后由你决定。
14
14
  - **`/` 开头的文本是合法的命令发送动作**,交给 DSH 官方裁决。
15
15
  - 预置与自定义**合计上限 50 个**。达到上限后不能再新增或克隆;若升级或配置变化把既有状态推过上限,**已有数据一个都不会丢**,只是在回到上限以内之前禁止新增和克隆。
@@ -54,7 +54,7 @@ dsh plugin --profile web add dsh-quick-actions@next
54
54
  ```sh
55
55
  mkdir -p /tmp/quick-actions
56
56
  pnpm --filter dsh-quick-actions pack --pack-destination /tmp/quick-actions
57
- dsh plugin --profile web add /tmp/quick-actions/dsh-quick-actions-0.2.0-rc.1.tgz
57
+ dsh plugin --profile web add /tmp/quick-actions/dsh-quick-actions-0.2.0-rc.2.tgz
58
58
  ```
59
59
 
60
60
  上面的 `--filter` 形式在仓库任意位置都能用;如果你已经在包目录里,`pnpm pack --pack-destination /tmp/quick-actions` 即可。
@@ -123,6 +123,7 @@ pnpm 有一条供应链策略:拒绝发布时间在冷却窗口内(默认 24
123
123
  - `label`、`text` 必填;`icon`、`confirm` 可选,`confirm` 默认 `true`。
124
124
  - 预置无效(缺字段、`id` 重复、目录超过 50 条)会让**插件加载响亮失败**并一次列出所有问题,而不是静默截断。
125
125
  - `presets` 与你的动作数据同在这一行 `config` 下(见下文「Settings 路径」),本插件从不写它。它是 DSH 的 volatile 字段:profile 运行期间改动会即时反映到快捷动作上;此时若改出无效目录,快捷动作区域显示目录错误,重启 profile 时插件加载失败并列出问题。
126
+ - **只写在 active profile 自己的这份 `cordis.patch.yml` 里。** 不要把本插件的 `config` 写进 home patch(`<DSH_HOME>/cordis.patch.yml`)或 `dsh --patch` 的 overlay:DSH 的 patch 行 `config` 是整份替换,那一层会盖住这一行里存的你的动作数据(界面回到默认,磁盘上的数据还在),而且 DSH 会拒绝此后的每一次保存,界面报「保存被拒绝」,重试也不会成功。删掉那一层里本插件的行并重启 profile 即可恢复。
126
127
 
127
128
  用户对预置只能隐藏或克隆,不能编辑或删除;克隆出来的是一条普通的自定义动作。
128
129
 
@@ -133,7 +134,7 @@ pnpm 有一条供应链策略:拒绝发布时间在冷却窗口内(默认 24
133
134
  | 值 | 名称 | 位置 |
134
135
  |---|---|---|
135
136
  | `ribbon`(默认) | 上方动作带 | 输入框上方一行,与输入框等宽 |
136
- | `bar` | 下方操作栏 | 输入框内部下方一行,装不下的折进「更多」 |
137
+ | `bar` | 下方操作栏 | 输入框下方一行,与 DSH 自己的用量信息并排,宽度随内容、最多与输入卡片同宽,装不下的折进「更多」 |
137
138
  | `launcher` | 单入口面板 | 一个入口按钮,点开可搜索的动作面板 |
138
139
 
139
140
  `bar` 与 `launcher` 共用同一个可搜索面板,搜索只匹配标签和文本。管理面板里可以给预置排序、隐藏、恢复、克隆,增删改自定义动作并启停它们,以及切换布局。
@@ -193,7 +194,7 @@ dsh plugin --profile web add dsh-quick-actions@<version>
193
194
  dsh plugin --profile web remove dsh-quick-actions
194
195
  ```
195
196
 
196
- 依赖与 `dsh.profile.bundles` 里的那一层会同时去掉,重启 profile 后动作不再出现。`cordis.patch.yml` 里 `id: composer-quick-actions` 那一行原样保留——你的动作都在它的 `config` 里,重装后按 id 接回,所以动作会回来。只卸不装时,profile 每次启动会为这行打一条 `patch: entry "composer-quick-actions" not found` 警告,不影响启动;按下面第 1 步删掉即可。
197
+ 依赖与 `dsh.profile.bundles` 里的那一层会同时去掉,重启 profile 后动作不再出现。`cordis.patch.yml` 里 `id: composer-quick-actions` 那一行原样保留——你的动作都在它的 `config` 里,重装后按 id 接回,所以动作会回来。只卸不装时,这一行就成了找不到目标的孤儿行:不影响启动,`dsh --profile web --dump-config` 会为它报 `patch: entry "composer-quick-actions" not found`;按下面第 1 步删掉即可。
197
198
 
198
199
  **手工彻底清理**(卸载不做这些,因为重装应当恢复你的动作):
199
200
 
package/lib/client.js CHANGED
@@ -1685,6 +1685,11 @@ window.__ModuleLoader__.load({
1685
1685
  * no layout — every width reads as zero. That answers "all of them": showing the
1686
1686
  * full row and letting the browser's own overflow handle it for one frame is
1687
1687
  * better than flashing a "more" button that the next frame withdraws.
1688
+ *
1689
+ * A control fits when it overruns the row by less than `FIT_TOLERANCE`. Whenever
1690
+ * the bar is content-sized (spec 22.9) the row it measures is exactly as wide as
1691
+ * the controls it shows, and fractional layout can report that a hair short;
1692
+ * folding a face over the difference would narrow the row and start a cascade.
1688
1693
  */
1689
1694
  function fitActionCount(input) {
1690
1695
  const { available, widths, reserved, gap } = input;
@@ -1694,7 +1699,7 @@ window.__ModuleLoader__.load({
1694
1699
  let shown = 0;
1695
1700
  for (const width of widths) {
1696
1701
  const next = used + width + (shown === 0 && reserved === 0 ? 0 : gap);
1697
- if (next > available) break;
1702
+ if (next > available + .5) break;
1698
1703
  used = next;
1699
1704
  shown += 1;
1700
1705
  }
@@ -2087,10 +2092,13 @@ window.__ModuleLoader__.load({
2087
2092
  });
2088
2093
  }
2089
2094
  /**
2090
- * Measure one element's inner width, republishing on every resize. Used twice:
2091
- * on the whole row for the density rule, and on the action region alone for the
2092
- * bar's overflow split — the region is `flex: 1 1 auto`, so its width is already
2093
- * what is left after the controls that must stay visible.
2095
+ * Measure one element's width, republishing on every resize. Used twice: on the
2096
+ * whole row for the density rule, and on the action region alone for the bar's
2097
+ * overflow split — the region is `flex: 1 1 auto`, so its width is already what
2098
+ * is left after the controls that must stay visible.
2099
+ *
2100
+ * Fractional, like the control widths it is compared with: `clientWidth` rounds,
2101
+ * and a region reported a pixel short of the faces it holds folds one of them.
2094
2102
  */
2095
2103
  function useElementWidth() {
2096
2104
  const ref = (0, react.useRef)(null);
@@ -2099,10 +2107,10 @@ window.__ModuleLoader__.load({
2099
2107
  const element = ref.current;
2100
2108
  if (element === null || typeof ResizeObserver === "undefined") return;
2101
2109
  const observer = new ResizeObserver(() => {
2102
- setWidth(element.clientWidth);
2110
+ setWidth(element.getBoundingClientRect().width);
2103
2111
  });
2104
2112
  observer.observe(element);
2105
- setWidth(element.clientWidth);
2113
+ setWidth(element.getBoundingClientRect().width);
2106
2114
  return () => {
2107
2115
  observer.disconnect();
2108
2116
  };
@@ -2123,7 +2131,7 @@ window.__ModuleLoader__.load({
2123
2131
  let changed = false;
2124
2132
  for (const node of Array.from(fitRef.current?.querySelectorAll("[data-quick-action]") ?? [])) {
2125
2133
  const key = node.dataset["quickAction"];
2126
- const value = node.offsetWidth;
2134
+ const value = node.getBoundingClientRect().width;
2127
2135
  if (key === void 0 || value <= 0 || widths.current.get(key) === value) continue;
2128
2136
  widths.current.set(key, value);
2129
2137
  changed = true;
@@ -2194,6 +2202,7 @@ window.__ModuleLoader__.load({
2194
2202
  className: layout === "bar" ? "dsh-cqa-bar" : layout === "launcher" ? "dsh-cqa-launcher" : "dsh-cqa-ribbon",
2195
2203
  "data-quick-actions-layout": layout,
2196
2204
  "data-quick-actions-density": density,
2205
+ "data-quick-actions-overflow": layout === "bar" && overflow.length > 0 ? "" : void 0,
2197
2206
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2198
2207
  className: "dsh-cqa-row",
2199
2208
  ref: rowRef,
@@ -3463,20 +3472,24 @@ window.__ModuleLoader__.load({
3463
3472
  * Colours are DSH alias theme tokens only — nothing here defines a palette, and
3464
3473
  * nothing overrides a global theme (spec 8.4).
3465
3474
  *
3466
- * ## The width rule (spec 8.2)
3467
- *
3468
- * The two layouts sit in different boxes, so they reach the same outer edges by
3469
- * different arithmetic:
3470
- *
3471
- * - `.dsh-cqa-ribbon` renders in the composer stack, outside the InputBar, which
3472
- * is the element that owns `--dsh-composer-side-clearance` as padding. It
3473
- * therefore subtracts that clearance from both sides itself.
3474
- * - `.dsh-cqa-bar` renders as the InputBar's last child, inside that padding, so
3475
- * it is simply `100%` wide.
3476
- *
3477
- * Both are then capped at `--dsh-composer-card-max-width` — the same cap the
3478
- * composer card uses — and centred, so their left and right edges coincide with
3479
- * the input box exactly rather than approximately.
3475
+ * ## The width rule (spec 8.2, 22.9)
3476
+ *
3477
+ * `.dsh-cqa-ribbon` (and the launcher, in the same box) renders in the composer
3478
+ * stack, outside the InputBar, which is the element that owns
3479
+ * `--dsh-composer-side-clearance` as padding. It therefore subtracts that
3480
+ * clearance from both sides itself, is capped at `--dsh-composer-card-max-width`
3481
+ * — the same cap the composer card uses — and is centred, so its left and right
3482
+ * edges coincide with the input box exactly rather than approximately.
3483
+ *
3484
+ * `.dsh-cqa-bar` makes no such claim. Since DSH 0.1.6-alpha.2 the composer dock is
3485
+ * a row under the card that DSH centres and sizes to its content, shared with
3486
+ * DSH's own stats pills and context meter, so the bar is a content-sized member of
3487
+ * that row (spec 22.9). It only has to stay inside it: `min-width: 0` lets it
3488
+ * shrink when the row reaches the composer's width, which is what hands the
3489
+ * overflow split a smaller region to fold into "more". Once it folds it claims
3490
+ * the card's width (`[data-quick-actions-overflow]`), capped by the row's own
3491
+ * `max-width: 100%`: content-sized, the region the split measures would only be
3492
+ * as wide as what it already shows, and a wider window could never unfold it.
3480
3493
  */
3481
3494
  const TAG_ID = "dsh-quick-actions/surfaces.css";
3482
3495
  const QUICK_ACTIONS_CSS = `
@@ -3489,9 +3502,12 @@ window.__ModuleLoader__.load({
3489
3502
  }
3490
3503
  .dsh-cqa-bar {
3491
3504
  box-sizing: border-box;
3492
- width: 100%;
3505
+ min-width: 0;
3493
3506
  max-width: var(--dsh-composer-card-max-width);
3494
- margin: 0 auto;
3507
+ }
3508
+ /* Folding: claim the card's width, for the dock row's own max-width to cap. */
3509
+ .dsh-cqa-bar[data-quick-actions-overflow] {
3510
+ width: var(--dsh-composer-card-max-width);
3495
3511
  }
3496
3512
 
3497
3513
  .dsh-cqa-row {