@prettier-ai/dsh-client-ui-schedule 0.1.2-alpha.2 → 0.1.2-alpha.4

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-schedule/README.md
5
- README.md: 2d75746876daf453b01ff2e84b6e62ed018c205c
6
- README.zh.md: 32925e73aed252189764c4eafc0f5ecc58bb2a08
5
+ README.md: 37ffbc0ef0b4a55af3238efa700dfdd0b942dd35
6
+ README.zh.md: 6094050437dbd062134c972918682403f675e660
package/README.md CHANGED
@@ -35,7 +35,7 @@ The shipped Web graph already resolves `@deepseek-ai/dsh-client-ui-schedule` thr
35
35
 
36
36
  ### Read and dismiss the catalog
37
37
 
38
- Each row shows the complete wrapping prompt, a separate Scheduled or Overdue status, localized Once or the largest exact whole unit for a repeating interval, browser-local target time, and browser-clock-relative time. Intervals are never rounded, and the three metadata fields wrap across lines instead of clipping valid large values. The 336px popover scrolls vertically when needed and exposes no Schedule id, raw UTC value, details, or action controls.
38
+ Each row shows the complete wrapping prompt, a separate Scheduled or Overdue status, localized Once or the largest exact whole unit for a repeating interval, browser-local target time, and browser-clock-relative time. Intervals are never rounded, and the three metadata fields wrap across lines instead of clipping valid large values. The body-portaled popover targets 336px, shares the trigger's left edge when space permits, and shifts left to retain a 16px viewport margin when the trigger is near the right edge; its maximum width is the viewport width minus 32px. It scrolls vertically when needed and exposes no Schedule id, raw UTC value, details, or action controls.
39
39
 
40
40
  Only the native trigger button enters the tab order. Enter and Space use normal button activation; while focus remains on the trigger or catalog, Escape closes the popover and restores trigger focus; an outside pointer press dismisses it. If a live update removes the final record, the component closes and unmounts without moving focus to another header action. A failed Session open hides the trigger even when a tentative cached projection exists.
41
41
 
@@ -47,7 +47,7 @@ Only the native trigger button enters the tab order. Enter and Space use normal
47
47
  <details>
48
48
  <summary>Implementation internals — click to expand</summary>
49
49
 
50
- The browser plugin contributes `schedule-catalog` to `conversation.session.header.actions` at order 10, after static Agent and Subagent context and before background Jobs. It reads `openState` through the standard Session hook and the complete value through `useProjection('schedule')`; popover visibility is its only local interaction state. Browser formatting uses the viewing locale, time zone, and clock, while durable Schedule records remain unchanged.
50
+ The browser plugin contributes `schedule-catalog` to `conversation.session.header.actions` at order 10, after static Agent and Subagent context and before background Jobs. It reads `openState` through the standard Session hook and the complete value through `useProjection('schedule')`; popover visibility is its only local interaction state. The component portals the catalog to `document.body` and gives its trigger and panel refs to `useAnchoredPosition`, which publishes fixed coordinates after measuring the rendered panel, keeps a 5px gap below the trigger, clamps to a 16px viewport margin, and remeasures on resize, captured scroll, and panel resize. The catalog ref also makes pointer presses inside the portal part of the existing dismissal boundary. Browser formatting uses the viewing locale, time zone, and clock, while durable Schedule records remain unchanged.
51
51
 
52
52
  ### Source map
53
53
 
@@ -57,7 +57,7 @@ The browser plugin contributes `schedule-catalog` to `conversation.session.heade
57
57
  | [`src/client/ScheduleCatalogAction.tsx`](src/client/ScheduleCatalogAction.tsx) | Visibility, ordering, formatting, popover, and keyboard behavior |
58
58
  | [`src/client/locales.ts`](src/client/locales.ts) | English and Chinese catalog copy |
59
59
  | [`src/index.ts`](src/index.ts) | Empty Host apply that keeps the optional browser feature addressable by Loader |
60
- | [`src/invariant.ts`](src/invariant.ts) | Invariant companion; the package owns no mutable cross-plugin state |
60
+ | | No runtime invariant companion is published because this read-only client catalog owns no mutable cross-plugin state. |
61
61
 
62
62
  The [durable Web Schedule Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns the active projection and opt-in presentation boundary; this package owns the catalog's timing and accessibility behavior.
63
63
 
package/README.zh.md CHANGED
@@ -35,7 +35,7 @@ dsh web --patch apps/cli/config/examples/schedule/cordis.yml
35
35
 
36
36
  ### 阅读和关闭目录
37
37
 
38
- 每一行显示可完整换行的 prompt、独立的「等待中」或「已逾期」状态、本地化的「单次」或重复间隔可整除的最大完整单位、浏览器本地目标时间,以及按浏览器时钟派生的相对时间。间隔绝不舍入,三项元数据会按行换行,不会裁剪合法的大数值。336px 宽的弹层在需要时纵向滚动,不显示 Schedule id、原始 UTC 值、详情或操作控件。
38
+ 每一行显示可完整换行的 prompt、独立的「等待中」或「已逾期」状态、本地化的「单次」或重复间隔可整除的最大完整单位、浏览器本地目标时间,以及按浏览器时钟派生的相对时间。间隔绝不舍入,三项元数据会按行换行,不会裁剪合法的大数值。通过 portal 挂到 body 的弹层目标宽度为 336px;空间足够时与触发按钮左边缘对齐,触发器靠近视口右侧时向左避让并保留 16px 视口边距,最大宽度为视口宽度减 32px。弹层会在需要时纵向滚动,且不显示 Schedule id、原始 UTC 值、详情或操作控件。
39
39
 
40
40
  只有原生触发按钮进入 Tab 顺序。Enter 与 Space 使用按钮的正常激活行为;焦点仍在触发器或目录内时,Escape 会关闭弹层并把焦点交还触发器;在外部按下指针也会关闭。若 live 更新移除最后一条记录,组件会关闭并卸载,但不会把焦点移到另一个会话头部动作。Session 打开失败时,即使存在暂定的缓存 projection,也会隐藏触发器。
41
41
 
@@ -47,7 +47,7 @@ dsh web --patch apps/cli/config/examples/schedule/cordis.yml
47
47
  <details>
48
48
  <summary>实现细节——点击展开</summary>
49
49
 
50
- 浏览器插件以顺序 10 向 `conversation.session.header.actions` 贡献 `schedule-catalog`,位于静态 Agent 与 Subagent 上下文之后、后台 Jobs 之前。它通过标准 Session hook 读取 `openState`,通过 `useProjection('schedule')` 读取完整值;弹层开合是它唯一的本地交互状态。浏览器格式化使用查看方的 locale、时区与时钟,持久 Schedule 记录保持不变。
50
+ 浏览器插件以顺序 10 向 `conversation.session.header.actions` 贡献 `schedule-catalog`,位于静态 Agent 与 Subagent 上下文之后、后台 Jobs 之前。它通过标准 Session hook 读取 `openState`,通过 `useProjection('schedule')` 读取完整值;弹层开合是它唯一的本地交互状态。组件把目录 portal 到 `document.body`,并将触发器与面板 ref 交给 `useAnchoredPosition`;该 hook 在测量已渲染面板后发布 fixed 坐标,使面板位于触发器下方 5px、钳制在 16px 视口边距内,并在 resize、捕获阶段 scroll 与面板 resize 时重新测量。目录 ref 也让 portal 内的指针按下继续属于既有 dismissal 边界之内。浏览器格式化使用查看方的 locale、时区与时钟,持久 Schedule 记录保持不变。
51
51
 
52
52
  ### 源码地图
53
53
 
@@ -57,7 +57,7 @@ dsh web --patch apps/cli/config/examples/schedule/cordis.yml
57
57
  | [`src/client/ScheduleCatalogAction.tsx`](src/client/ScheduleCatalogAction.tsx) | 可见性、排序、格式化、弹层与键盘行为 |
58
58
  | [`src/client/locales.ts`](src/client/locales.ts) | 中英文目录文案 |
59
59
  | [`src/index.ts`](src/index.ts) | 空的 Host apply,使 Loader 可以寻址该可选浏览器功能 |
60
- | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件;本包不拥有可变跨插件状态 |
60
+ | | 不发布运行时不变量伴生入口;这个只读客户端目录不拥有可变的跨插件状态。 |
61
61
 
62
62
  [持久 Web Schedule Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md)拥有活动 projection 与 opt-in 呈现边界;本包拥有目录的时间与无障碍行为。
63
63
 
package/lib/client.js CHANGED
@@ -6,9 +6,10 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let react = require("react");
9
+ let react_dom = require("react-dom");
9
10
  let _prettier_ai_dsh_client_ui_primitives = require("@prettier-ai/dsh-client-ui-primitives");
10
11
  //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-schedule/src/client/ScheduleCatalogAction.module.css.mjs
11
- const css = ".sRbB7a_root{position:relative}.sRbB7a_trigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;align-items:center;gap:4px;padding:3px 2px;font-size:12px;line-height:18px;display:inline-flex}.sRbB7a_trigger:hover,.sRbB7a_trigger:focus-visible{color:var(--dsw-alias-label-secondary)}.sRbB7a_trigger svg{flex:none}.sRbB7a_trigger>svg:last-child{transition:transform .12s}.sRbB7a_triggerOpen{transform:rotate(180deg)}.sRbB7a_count{margin-left:2px}.sRbB7a_menu{z-index:100;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);width:336px;max-width:min(336px,100vw - 32px);max-height:min(420px,100vh - 140px);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:2px;margin:0;padding:4px;list-style:none;display:flex;position:absolute;top:calc(100% + 5px);right:0;overflow:auto}.sRbB7a_row{box-sizing:border-box;width:100%;min-height:54px;color:var(--dsw-alias-label-primary);border-radius:8px;flex-direction:column;flex-shrink:0;gap:3px;padding:8px 10px;display:flex}.sRbB7a_rowOverdue{background:var(--dsw-alias-state-warn-tertiary)}.sRbB7a_status{color:var(--dsw-alias-label-tertiary);align-items:center;gap:5px;font-size:11px;line-height:16px;display:inline-flex}.sRbB7a_statusDot{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:8px;height:8px}.sRbB7a_rowOverdue .sRbB7a_status{color:var(--dsw-alias-state-warn-label)}.sRbB7a_rowOverdue .sRbB7a_statusDot{background:var(--dsw-alias-state-warn-primary)}.sRbB7a_prompt{overflow-wrap:anywhere;white-space:normal;font-size:13px;line-height:18px}.sRbB7a_metadata{min-width:0;color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:5px;font-size:11px;line-height:16px;display:flex}.sRbB7a_relativeOverdue{color:var(--dsw-alias-state-warn-label)}";
12
+ const css = ".sRbB7a_root{position:relative}.sRbB7a_trigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;align-items:center;gap:4px;padding:3px 2px;font-size:12px;line-height:18px;display:inline-flex}.sRbB7a_trigger:hover,.sRbB7a_trigger:focus-visible{color:var(--dsw-alias-label-secondary)}.sRbB7a_trigger svg{flex:none}.sRbB7a_trigger>svg:last-child{transition:transform .12s}.sRbB7a_triggerOpen{transform:rotate(180deg)}.sRbB7a_count{margin-left:2px}.sRbB7a_menu{z-index:100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:336px;max-width:min(336px,100vw - 32px);max-height:min(420px,100vh - 140px);box-shadow:var(--dsw-elevation-prominent);border:0;border-radius:20px;flex-direction:column;gap:2px;margin:0;padding:4px;list-style:none;display:flex;position:fixed;overflow:auto}.sRbB7a_row{box-sizing:border-box;width:100%;min-height:54px;color:var(--dsw-alias-label-primary);border-radius:8px;flex-direction:column;flex-shrink:0;gap:3px;padding:8px 10px;display:flex}.sRbB7a_rowOverdue{background:var(--dsw-alias-state-warn-tertiary)}.sRbB7a_status{color:var(--dsw-alias-label-tertiary);align-items:center;gap:5px;font-size:11px;line-height:16px;display:inline-flex}.sRbB7a_statusDot{corner-shape:round;background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:8px;height:8px}.sRbB7a_rowOverdue .sRbB7a_status{color:var(--dsw-alias-state-warn-label)}.sRbB7a_rowOverdue .sRbB7a_statusDot{background:var(--dsw-alias-state-warn-primary)}.sRbB7a_prompt{overflow-wrap:anywhere;white-space:normal;font-size:13px;line-height:18px}.sRbB7a_metadata{min-width:0;color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:5px;font-size:11px;line-height:16px;display:flex}.sRbB7a_relativeOverdue{color:var(--dsw-alias-state-warn-label)}";
12
13
  const tagId = "@prettier-ai/dsh-client-ui-schedule/ScheduleCatalogAction.module.css";
13
14
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
15
  const tag = document.createElement("style");
@@ -39,6 +40,11 @@ window.__ModuleLoader__.load({
39
40
  unit: "second",
40
41
  seconds: 1
41
42
  };
43
+ const MEASURE_STYLE = {
44
+ visibility: "hidden",
45
+ left: 0,
46
+ top: 0
47
+ };
42
48
  const UNIT_SECONDS = [
43
49
  {
44
50
  unit: "day",
@@ -122,7 +128,16 @@ window.__ModuleLoader__.load({
122
128
  const [now, setNow] = (0, react.useState)(() => Date.now());
123
129
  const rootRef = (0, react.useRef)(null);
124
130
  const triggerRef = (0, react.useRef)(null);
125
- (0, _prettier_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, open, setOpen);
131
+ const catalogRef = (0, react.useRef)(null);
132
+ const catalogPosition = (0, _prettier_ai_dsh_client_ui_primitives.useAnchoredPosition)({
133
+ open,
134
+ anchorRef: triggerRef,
135
+ panelRef: catalogRef,
136
+ side: "bottom",
137
+ gap: 5,
138
+ margin: 16
139
+ });
140
+ (0, _prettier_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, open, setOpen, catalogRef);
126
141
  (0, react.useEffect)(() => {
127
142
  if (!open) return;
128
143
  setNow(Date.now());
@@ -166,8 +181,10 @@ window.__ModuleLoader__.load({
166
181
  (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: open ? ScheduleCatalogAction_module_css_default.triggerOpen : void 0 })
167
182
  ]
168
183
  });
169
- const catalog = open ? (0, react_jsx_runtime.jsx)("ul", {
184
+ const catalog = open ? (0, react_dom.createPortal)((0, react_jsx_runtime.jsx)("ul", {
185
+ ref: catalogRef,
170
186
  className: ScheduleCatalogAction_module_css_default.menu,
187
+ style: catalogPosition ?? MEASURE_STYLE,
171
188
  "aria-label": t("list.aria"),
172
189
  children: rows.map((record) => {
173
190
  const overdue = Date.parse(record.scheduledAt) <= now;
@@ -207,7 +224,7 @@ window.__ModuleLoader__.load({
207
224
  ]
208
225
  }, record.id);
209
226
  })
210
- }) : null;
227
+ }), document.body) : null;
211
228
  return (0, react_jsx_runtime.jsxs)("div", {
212
229
  ref: rootRef,
213
230
  className: ScheduleCatalogAction_module_css_default.root,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prettier-ai/dsh-client-ui-schedule",
3
3
  "description": "Read-only active Schedule catalog in the Web Session header",
4
- "version": "0.1.2-alpha.2",
4
+ "version": "0.1.2-alpha.4",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -10,10 +10,6 @@
10
10
  "types": "./lib/types/index.d.ts",
11
11
  "default": "./lib/index.js"
12
12
  },
13
- "./invariant": {
14
- "types": "./lib/types/invariant.d.ts",
15
- "default": "./lib/invariant.js"
16
- },
17
13
  "./client": {
18
14
  "types": "./lib/types/client/index.d.ts",
19
15
  "default": "./lib/client.js"
@@ -46,24 +42,23 @@
46
42
  "devDependencies": {
47
43
  "@testing-library/react": "^16.1.0",
48
44
  "@types/react": "~18.3.1",
45
+ "@types/react-dom": "~18.3.0",
49
46
  "react": "^18.2.0",
50
47
  "react-dom": "^18.2.0",
51
- "@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.2",
52
- "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.2",
53
- "@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.2",
54
- "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.2",
55
- "@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.2",
56
- "@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.2",
57
- "@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.2",
58
- "@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.2",
59
- "@prettier-ai/dsh-schedule": "^0.1.2-alpha.2",
60
- "@prettier-ai/dsh-invariants": "^0.1.2-alpha.2",
61
- "@prettier-ai/dsh-session": "^0.1.2-alpha.2",
48
+ "@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.4",
49
+ "@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.4",
50
+ "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.4",
51
+ "@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.4",
52
+ "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.4",
53
+ "@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.4",
54
+ "@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.4",
55
+ "@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.4",
56
+ "@prettier-ai/dsh-schedule": "^0.1.2-alpha.4",
57
+ "@prettier-ai/dsh-session": "^0.1.2-alpha.4",
62
58
  "@prettier-ai/cordis": "^4.0.2"
63
59
  },
64
60
  "files": [
65
61
  "lib/index.js",
66
- "lib/invariant.js",
67
62
  "lib/client.js",
68
63
  "lib/types/**/*.d.ts"
69
64
  ],
package/lib/invariant.js DELETED
@@ -1,13 +0,0 @@
1
- //#region lib/types/invariant.js
2
- /** Package-owned invariant companion for the read-only Schedule catalog. */
3
- const PACKAGE_NAME = "@prettier-ai/dsh-client-ui-schedule";
4
- /** Cordis companion plugin name. */
5
- const name = "client-ui-schedule-invariant";
6
- /** Service required before the companion can reserve package ownership. */
7
- const inject = ["invariants"];
8
- /** No runtime invariant: the package owns no mutable cross-plugin state. */
9
- const install = () => {};
10
- /** Register this package's invariant companion. */
11
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
12
- //#endregion
13
- export { apply, inject, name };
@@ -1,9 +0,0 @@
1
- /** Package-owned invariant companion for the read-only Schedule catalog. */
2
- import type { Context } from '@prettier-ai/cordis';
3
- /** Cordis companion plugin name. */
4
- export declare const name = "client-ui-schedule-invariant";
5
- /** Service required before the companion can reserve package ownership. */
6
- export declare const inject: string[];
7
- /** Register this package's invariant companion. */
8
- export declare const apply: (ctx: Context) => Promise<() => void>;
9
- //# sourceMappingURL=invariant.d.ts.map