Files
dsh-context/tests/client/dockMeasure.spec.ts
T
Bowen Liang b11a1d2151 feat(client): dock the /context modal mask beside the shell sidebar
The fixed backdrop masked the whole viewport; inset it by the sidebar
track parsed off the app frame's inline grid template (the sole inline
gridTemplateColumns in the dsh client, identical on every supported
baseline), so the dialog centers over the main column and the sidebar
stays visible and interactive. An unresolved frame degrades to the
full-viewport mask.

The measure runs in a layout effect (no 0-inset first paint) and, while
open, a MutationObserver on the frame's style attribute follows sidebar
drags, collapse toggles and narrow-viewport re-solves. A per-baseline
compat probe pins the frame seam.
2026-09-01 22:48:26 +08:00

61 lines
2.5 KiB
TypeScript

// measureDock (src/client/dockMeasure.ts) — the /context modal's sidebar
// inset: the ancestor walk to the app frame's inline grid template, the
// leading-px parse, and every degrade-to-full-mask branch.
import assert from 'node:assert/strict'
import { describe, test } from 'vitest'
import { measureDock } from '../../src/client/dockMeasure'
const TEMPLATE = '280px minmax(0, 1fr) 360px'
/** A start element buried at the bottom of an ancestor chain (outermost first). */
function chainOf(...ancestors: HTMLElement[]): HTMLElement {
for (let i = 0; i < ancestors.length - 1; i++) ancestors[i].appendChild(ancestors[i + 1])
return ancestors[ancestors.length - 1]
}
function frameEl(template: string): HTMLDivElement {
const el = document.createElement('div')
el.style.gridTemplateColumns = template
return el
}
describe('measureDock', () => {
test('resolves to the full mask without a start element', () => {
assert.deepEqual(measureDock(null), { left: 0, frame: null })
})
test('resolves to the full mask when no ancestor carries an inline template', () => {
const start = chainOf(document.createElement('div'), document.createElement('div'))
assert.deepEqual(measureDock(start), { left: 0, frame: null })
})
test('parses the leading px track off the frame ancestor', () => {
const frame = frameEl(TEMPLATE)
const start = chainOf(frame, document.createElement('div'), document.createElement('div'))
assert.deepEqual(measureDock(start), { left: 280, frame })
})
test('parses a fractional track and a collapsed 0px rail', () => {
const frame = frameEl('264.5px minmax(0, 1fr) 0px')
const start = chainOf(frame, document.createElement('div'))
assert.deepEqual(measureDock(start), { left: 264.5, frame })
assert.deepEqual(measureDock(chainOf(frameEl('0px minmax(0, 1fr) 0px'), document.createElement('div'))).left, 0)
})
test('resolves to the full mask when the frame template is unparsable', () => {
for (const template of ['', 'minmax(0, 1fr)', 'auto 1fr']) {
const start = chainOf(frameEl(template), document.createElement('div'))
assert.deepEqual(measureDock(start), { left: 0, frame: null })
}
})
test('a hostile ancestor degrades to the full mask instead of throwing', () => {
const hostile = document.createElement('div')
Object.defineProperty(hostile, 'style', { get() { throw new Error('hostile') } })
const start = chainOf(hostile, document.createElement('div'))
assert.deepEqual(measureDock(start), { left: 0, frame: null })
})
})