# Changelog ## 0.8.2(2026-09-20) - **修主题色误用**:此前把宿主遮罩 token `--dsw-alias-bg-mask-3` 当淡色 hover/底纹用;DSH 0.1.6-alpha.2 里它实测亮/暗主题都是 `rgba(0,0,0,.48)`,导致周视图「今天」整列、月视图格子 hover、加载骨架屏、详情 tag 全部发深灰(浏览器视觉验收抓到,视觉上像一块无字灰板)。现改为 `color-mix`(label-primary 5%~7% / business-primary 7%),mask-3 只保留在 `.dshc-overlay` / `.dshc-modalwrap` 两处真正的遮罩上。 - **修 Esc 关错层**:详情抽屉/新建表单打开时按 Esc 会连整个日历浮层面板一起关掉。现在 Esc 只关最上面一层,第二次才关面板;焦点在上层宿主 `PRIM.Modal` 里时让行给宿主;输入法组合状态(`isComposing`)不误关;设置页与对话页两个面板并存时一次也只关一层,并按实际打开顺序关。 - **测试**:render 测试 7 → 15 条(新增抽屉/宿主 Modal 真假路径/宿主高层浮层让行/普通宿主元素兜底/层序/IME 等用例),全量 154 pass。该版经两位独立评审:首轮抓到「宿主 Portal 抢 Esc」「双面板一次连关两层」「IME 误关」,二轮抓到「宿主高层 Modal 盖上来时关错下面那层」,均已修。 ## 0.8.1(2026-09-19) - **新增真 DOM 行为测试层**(`test/render.test.mjs`,devDependencies 里加 `react` / `react-dom` / `jsdom`,不进发布包):用 jsdom + 真 React 渲染周视图,然后真派发 `pointerdown/move/up`、`click`、`keydown`。7 条覆盖:渲染不抛、点事件不会顺手弹「新建」、拖动只提交一次且按视口坐标换算、拖动中 Esc 零请求、卸载后不留监听器且之后的 pointerup 不提交、拖到边缘 rAF 持续滚动、重复日程被面板挡住。 - **它的第一批产出就是三个真问题**: ① **同一批次内拖动不提交**:提交前的「有没有落点」判断读的是 React state(`ghost`),而 `pointermove` 与 `pointerup` 落在同一批次时 state 还没刷新 → 明明拖了却不落盘。改为在 `dragRef` 上记同步标记。 ② `requestAnimationFrame` / `cancelAnimationFrame` 按全局调用:浏览器里有,但模块作用域下应当显式走 `window.*`。 ③ 三处 React key 警告(日期头、事件块、幽灵块、日列的子节点用了数组却没给 key)——dev 模式控制台一直在吵。 ## 0.8.0(2026-09-19) - **新增:周视图拖拽改期**。拖动事件块上下改时间、左右换天(15 分钟吸附);拖块底部 6px 改时长;拖动中显示幽灵落点,与已有日程重叠时描成黄色(允许重叠,只是提醒);拖到容器上下边缘自动滚动,长会议不用先滚再拖。 - **新增:键盘改期**。Tab 聚焦后 ↑/↓ 挪 15 分钟、Shift+↑/↓ 挪 1 小时、←/→ 挪一天、Enter 打开详情、拖动中 Esc 取消 —— 没有鼠标也能完成一次改期。 - **新增:乐观更新 + 失败回滚 + 5 秒撤销**。本地先动画面再落盘,失败自动回滚并把服务器原话弹出来;成功后提示「已改期 · 撤销」。 - **重复日程与超过 24 小时的日程暂不支持拖动改期**(提示去详情里编辑):CalDAV 里整个系列是一个对象,而 update 只能改 master 的 DTSTART —— 独立评审实测「把某次实例的目标时间发过去」等于**重锚系列起点**(早于它的实例全丢、COUNT/UNTIL 语义被改、撤销也回不到原系列)。宁可不做,也不做半个数据事故。 - 几何算法全部抽成纯函数(`snapMinutes` / `slotFromEvent` / `moveSlot` / `slotFromDrag` / `resizeSlot` / `rangeOfSlot` / `conflictsForSlot` / `isRecurring`),新增 12 条单测**直接测发布文件里的实现**(跨天、跨月、越午夜、吸附、钳制、冲突判定、拖拽接线契约)。 - 交互细节(两轮独立评审后补的洞):5px 阈值区分点击与拖动;**点事件不再冒泡去触发「新建日程」**(slot 是日列的子节点,此前点一下会同时弹详情与新建表单,拖完松手也会弹);只认发起拖动的 `pointerId`;window 监听器**只在挂载时注册一次**并通过 ref 调最新实现(此前按渲染闭包挂/摘,卸载后残留的 `pointerup` 会替用户提交一次改期);`buttons === 0` / 窗口失焦 / `Esc`(捕获阶段,不顺手关掉浮层面板)都回到原位;边缘自动滚动改用 **rAF 持续滚**并在滚动后重算落点。 - 落盘:改期请求**按 uid 串行 + 合并**(连按方向键只落最后一次)、跳过无效位移、带 15 秒超时;失败回滚后还会 reload 对账(超时可能已经写进去了)。 - 位移改成**日历日 + 墙钟分钟**运算:此前按毫秒加,DST 切换日会偏一小时(评审用 `TZ=America/New_York` 复现,中国时区看不见);日末钳制也吸附到 15 分钟网格。 - **修一个渲染即崩的 P0**:焦点恢复的 `useEffect` 依赖数组引用了声明在后面的 `data`,TDZ 直接抛错、整个面板打不开(纯函数测试测不到,评审渲染才发现)。 - 明确取舍:拖动越过午夜**滚到次日**(与 Google 日历一致,也让幽灵块按 `slot.dayKey` 的日列渲染自洽),而不是硬钳在当天最后一刻。 ## 0.7.0(2026-09-19) - **新增**:面板**记住上次用的视图**(月/周/议程,存 localStorage;隐私模式写不进去就退回「月」),下次打开不再固定跳回月视图。 - **新增**:周视图**默认落在 07:00**(半夜那几格基本没人看,但需要时还能往上滚,不裁剪任何事件)。 - **适配窄容器**:面板在设置页里比对话页浮层窄得多,现在用容器查询自适应 —— 窄的时候隐藏芯片里的时间前缀(让日程标题露出来)、隐藏重复的面板标题、收紧工具栏间距。 - **修复**:月视图的格子由 `