fix(desktop): 补齐 mermaid 放大视图的拖拽区退出 + 把 #772 的守卫换成真实级联探针
#773 修掉了面板宿主层继承宿主 `body > :not(#root) { no-drag }` 导致的 macOS 拖拽 失效,但只覆盖了 `.mermaidModal` 之外的层——而放大视图是插件**第二个铺满视口的 body 直挂层**(`position:fixed; inset:0`,portal 到 body),打开期间会同样清空整窗 拖拽与 macOS 双击标题栏缩放。 - src/client/sidebar.module.css:`.mermaidModal` 加 `-webkit-app-region: initial !important`(与面板宿主同一条契约),并在面板宿主那段注释里写明「哪些交互层 绝对不能加 initial」(`.selectionPopup` 是 `<button>`、FloatingWindow / AnchoredPopover 自带指针拖拽,宿主 `:is(button, …)` 已给它们 no-drag;反过来 声明 `initial !important` 会让按下变成拖窗,重演 #103/#111)。 - tests/panel-host-css.spec.ts:新用例把形状钉在 Linux 的 `pnpm test` 里(宿主层 与面板层必须是 `initial !important`、`> *` 必须是 `no-drag`、`.mermaidModal` 同样退出、`.selectionPopup` 不得出现 `initial`)——没有 macOS runner,丢掉 `!important` 只能靠这里才不会静默复发。 - tests/e2e/mount.e2e.ts:把 #773 的**文本正则**断言换成**真实级联探针**——逐字 注入宿主两条 darwin 规则、翻转 `data-platform=darwin`,读取计算值并断言 `[data-window-drag]` 仍 `drag`、宿主层与面板层为 `none`、`[data-dsh-panel-host] > *` 为 `no-drag`,随后还原。探针把 `[data-window-drag]` 放在 `#root` 内:直挂 body 的元素会被宿主那条 id 级规则本身命中(这正是问题机制)。 - docs/external-plugin-guide.md §12.1:按仓库规则同步这条皮肤契约(含交互弹层 的反例判据与守卫位置)。 实测(scratch profile + 真实 dsh web + Chromium): - npm dsh-better-sidebar@0.22.0:探针红,`host` 计算值 `no-drag`(正是线上症状) - 本分支打包版:探针绿(`strip=drag` / `host=none` / `layer=none` / `child=no-drag`) - 本地挂载 lane:7 passed(mount + perf,含新探针) 验证:typecheck / lint 通过;panel-host-css + theme 用例通过;新产物 `app-region:initial!important` 2 处(面板宿主 + mermaid 模态)、`app-region:no-drag` 2 处。
This commit is contained in:
+45
-7
@@ -617,14 +617,52 @@ test('conservative auto: URL stamps alone never modify the layout; plugin chrome
|
||||
expect(hasNoDragRule, 'the bundle must ship the drag-region opt-out rule').toBe(true)
|
||||
// The viewport-sized panel host must NOT inherit the shell's blanket
|
||||
// `body > :not(#root) { no-drag }` — it would cancel every window-drag
|
||||
// strip beneath it on macOS (issue #772).
|
||||
const hasHostReset = await page.evaluate(() => {
|
||||
for (const tag of document.querySelectorAll('style')) {
|
||||
if (tag.textContent !== null && /\[data-dsh-panel-host\]\{-webkit-app-region:\s*initial\s*!important/.test(tag.textContent)) return true
|
||||
}
|
||||
return false
|
||||
// strip beneath it on macOS (issue #772). A text match only proves the
|
||||
// declaration shipped, so this probe reproduces the SHELL's two darwin
|
||||
// rules verbatim, flips the platform attribute the shell stamps, and reads
|
||||
// the COMPUTED property: app-region is inherited and ignores
|
||||
// pointer-events, so the loss shows on the host/layer — never on the strip
|
||||
// itself (it computes `drag` in every configuration, which is why a fix
|
||||
// validated only against the strip proves nothing).
|
||||
const regions = await page.evaluate(() => {
|
||||
const style = document.createElement('style')
|
||||
style.textContent = [
|
||||
'html[data-platform=darwin] [data-window-drag]{-webkit-app-region:drag}',
|
||||
'html[data-platform=darwin] body>:not(#root){-webkit-app-region:no-drag}',
|
||||
].join('\n')
|
||||
const strip = document.createElement('div')
|
||||
strip.setAttribute('data-window-drag', '')
|
||||
strip.style.cssText = 'position:fixed;top:0;left:0;right:0;height:8px'
|
||||
const probe = document.createElement('div')
|
||||
document.head.appendChild(style)
|
||||
// INSIDE #root: the shell's real drag strip is a frame child, not a body
|
||||
// child — a body child would be caught by the blanket rule itself (it is
|
||||
// id-bearing, so it outranks the `[data-window-drag]` rule).
|
||||
const root = document.querySelector('#root')
|
||||
;(root ?? document.body).appendChild(strip)
|
||||
const host = document.querySelector('[data-dsh-better-sidebar]')
|
||||
const layer = document.querySelector('[data-dsh-panel-host]')
|
||||
// This stamp-only page has no session, so the panel host has no child of
|
||||
// its own; `probe` stands in for the workbench panel the same `> *`
|
||||
// selector targets in a real session.
|
||||
layer?.appendChild(probe)
|
||||
const previous = document.documentElement.dataset.platform
|
||||
document.documentElement.dataset.platform = 'darwin'
|
||||
const read = (element: Element | null): string => element === null
|
||||
? 'missing'
|
||||
: getComputedStyle(element).getPropertyValue('-webkit-app-region').trim()
|
||||
const result = { strip: read(strip), host: read(host), layer: read(layer), layerChild: read(probe) }
|
||||
probe.remove()
|
||||
strip.remove()
|
||||
style.remove()
|
||||
if (previous === undefined) delete document.documentElement.dataset.platform
|
||||
else document.documentElement.dataset.platform = previous
|
||||
return result
|
||||
})
|
||||
expect(hasHostReset, 'the panel host must opt out of app-region computation').toBe(true)
|
||||
expect(regions.strip, 'the drag strip itself must keep computing `drag`').toBe('drag')
|
||||
expect(regions.host, 'the plugin host must not inherit the shell no-drag').toBe('none')
|
||||
expect(regions.layer, 'the panel host must not inherit the shell no-drag').toBe('none')
|
||||
expect(regions.layerChild, 'panels stay no-drag so their controls keep receiving clicks').toBe('no-drag')
|
||||
})
|
||||
|
||||
test('standard WCO geometry drives the strip reactively (issue #257)', async ({ page }) => {
|
||||
|
||||
@@ -44,4 +44,30 @@ describe('panel host layer css', () => {
|
||||
expect(degraded, 'the degraded-mode rule must exist').toBeDefined()
|
||||
expect(degraded).not.toMatch(/overflow\s*:/)
|
||||
})
|
||||
|
||||
it('keeps the app-region opt-out that un-breaks macOS window drag (issue #772)', () => {
|
||||
// The shell's `html[data-platform=darwin] body > :not(#root) { no-drag }`
|
||||
// carries an id in its specificity, so only `initial !important` wins;
|
||||
// `initial` computes to the NEUTRAL `none` (does not subtract from the
|
||||
// drag region) while `no-drag` is the subtracting value — hence the
|
||||
// split: decorative viewport-sized layers opt out, their panels stay
|
||||
// no-drag so controls keep receiving clicks. Dropping the `!important`
|
||||
// silently re-breaks window drag / double-click-title zoom on macOS
|
||||
// (there is no macOS runner to catch it), so pin the shape here where
|
||||
// Linux `pnpm test` fails instead.
|
||||
const text = stripComments(css)
|
||||
expect(text, 'the panel host must opt out of app-region computation').toMatch(
|
||||
/:global\(\[data-dsh-panel-host\]\)\s*\{[^}]*-webkit-app-region:\s*initial\s*!important/,
|
||||
)
|
||||
expect(text, 'panels must stay no-drag').toMatch(
|
||||
/:global\(\[data-dsh-panel-host\]\)\s*>\s*\*\s*\{[^}]*-webkit-app-region:\s*no-drag/,
|
||||
)
|
||||
expect(text, 'the mermaid zoom modal is the other viewport-sized body child').toMatch(
|
||||
/\.mermaidModal\s*\{[^}]*-webkit-app-region:\s*initial\s*!important/,
|
||||
)
|
||||
// The interactive popups must NOT get `initial`: they are buttons/handles
|
||||
// the shell already keeps no-drag, and outranking that rule makes a press
|
||||
// start a window drag (the #103/#111 click-swallow class).
|
||||
expect(text).not.toMatch(/\.selectionPopup\s*\{[^}]*-webkit-app-region:\s*initial/)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user