Why: The pane pinned .ui-fp to the column height, and the docx fit host then clipped overflow, so the right-hand preview could not scroll. The fullscreen DocViewer was a second shell around the same FilePreview. Evidence: npx vitest run (17 files, 82 tests) and npx tsc --noEmit passed. Headless Chromium laid out a 1400px docx host inside a 764px pane (body scrollHeight 1400) and a pdf iframe that filled that pane. Impact: .preview-pane-body is the scroll owner. Docx refit also watches page height. The overlay viewer is gone; expand/restore and text edit/save live on the pane. Refs: Agent-System-Dev#196, Agent-System-Frontend#44 Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
2.2 KiB
TypeScript
54 lines
2.2 KiB
TypeScript
// docx 分页纸面按预览栏宽度等比缩小。只缩不放:栏宽够放下整页时保持 100%。
|
||
// gutter 与 styles.css 里 .docx-wrapper 的左右 padding(12px + 12px)对齐。
|
||
|
||
export function computeFitScale(containerWidth: number, pageWidth: number, gutter: number): number {
|
||
if (!Number.isFinite(containerWidth) || !Number.isFinite(pageWidth) || pageWidth <= 0) return 1
|
||
if (!Number.isFinite(gutter)) return 1
|
||
const available = containerWidth - gutter
|
||
if (!(available > 0)) return 1
|
||
return Math.min(1, available / pageWidth)
|
||
}
|
||
|
||
const PAGE_GUTTER_PX = 24
|
||
|
||
/** host 是 docx-preview 的渲染根(内含 .docx-wrapper);el 是用来量栏宽的元素。
|
||
* 拖动分隔条时 el 变宽,ResizeObserver 重算。返回的函数卸下监听并清掉行内缩放。 */
|
||
export function fitPagesToWidth(host: HTMLElement, el: HTMLElement): () => void {
|
||
const apply = () => {
|
||
const wrapper = host.querySelector<HTMLElement>('.docx-wrapper')
|
||
const page = host.querySelector<HTMLElement>('section.docx')
|
||
if (!wrapper || !page) return
|
||
const scale = computeFitScale(el.clientWidth, page.offsetWidth, PAGE_GUTTER_PX)
|
||
wrapper.style.transformOrigin = 'top left'
|
||
wrapper.style.transform = scale < 1 ? `scale(${scale})` : ''
|
||
const nextHeight = `${Math.round(wrapper.offsetHeight * scale)}px`
|
||
if (host.style.height !== nextHeight) host.style.height = nextHeight
|
||
host.style.overflow = 'hidden'
|
||
host.style.minHeight = '0'
|
||
}
|
||
apply()
|
||
if (typeof ResizeObserver === 'undefined') {
|
||
return () => clearFit(host)
|
||
}
|
||
const observer = new ResizeObserver(() => apply())
|
||
observer.observe(el)
|
||
// 页内图片后加载只改变页纸高度,不改变栏宽。el 变宽和 wrapper 变高都要重算宿主高度。
|
||
const wrapper = host.querySelector<HTMLElement>('.docx-wrapper')
|
||
if (wrapper && wrapper !== el) observer.observe(wrapper)
|
||
return () => {
|
||
observer.disconnect()
|
||
clearFit(host)
|
||
}
|
||
}
|
||
|
||
function clearFit(host: HTMLElement) {
|
||
const wrapper = host.querySelector<HTMLElement>('.docx-wrapper')
|
||
if (wrapper) {
|
||
wrapper.style.transform = ''
|
||
wrapper.style.transformOrigin = ''
|
||
}
|
||
host.style.height = ''
|
||
host.style.overflow = ''
|
||
host.style.minHeight = ''
|
||
}
|