The helper-only spec passes even if the observer goes back to calling updateSettings() - which is the regression the helper exists to prevent. Move the observer into refreshGridAfterContainerResize.ts so a spec can drive a real container resize through it, and assert that the resize reaches refreshDimensions() without any settings call. Verified by re-injecting the old wiring: the spec fails with 'Expected spy updateSettings not to have been called', and passes once it is removed. Also corrects the helper's claim about what refreshDimensions() measures: it compares rootElement.getBoundingClientRect() with the last measured size, and both grids take their height from a viewport-derived calc(), so a resize that matters is a width or viewport change.
54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
import Handsontable from 'handsontable'
|
|
|
|
/**
|
|
* Re-measures a grid after its container changed size (sidebar toggle, modal
|
|
* open/close, window resize).
|
|
*
|
|
* Deliberately does NOT call `updateSettings()`. Any settings call while a
|
|
* multi-column sort is active corrupts formula cell references into `#REF!` -
|
|
* that is the bug `updateSettingsSortSafe()` exists for - and the workaround
|
|
* (clear the sort, apply, re-apply the sort) re-sorts the data underneath an
|
|
* open cell editor, so typing can land on a different row than the one being
|
|
* edited. A container resize has no business changing settings at all:
|
|
* `refreshDimensions()` measures `rootElement.getBoundingClientRect()` and
|
|
* compares it with the last measured size, re-running `adjustElementsSize()`
|
|
* and a render only when the box actually moved. Both grids take their height
|
|
* from a viewport-derived `calc()` setting (editor.component.ts:203), so a
|
|
* container resize that matters to the grid is a width change or a viewport
|
|
* change - both of which move that box. It also fires
|
|
* `beforeRefreshDimensions` / `afterRefreshDimensions` for anything that needs
|
|
* to react.
|
|
*/
|
|
export function refreshGridAfterContainerResize(
|
|
hot: Handsontable | null | undefined
|
|
): void {
|
|
if (!hot || hot.isDestroyed) return
|
|
hot.refreshDimensions()
|
|
}
|
|
|
|
/**
|
|
* Watches a grid's container and re-measures the grid whenever its box changes
|
|
* (sidebar toggle, modal open/close, window resize).
|
|
*
|
|
* The observer lives here rather than in the component so the wiring is
|
|
* covered by a spec: what matters is not that `refreshDimensions()` is called
|
|
* but that a resize never reaches `updateSettings()`.
|
|
*
|
|
* Returns the observer so the caller can disconnect it on destroy.
|
|
*/
|
|
export function observeGridContainerResize(
|
|
hot: Handsontable | null | undefined,
|
|
container: HTMLElement | null | undefined
|
|
): ResizeObserver | undefined {
|
|
if (!hot || !container || typeof ResizeObserver === 'undefined') {
|
|
return undefined
|
|
}
|
|
|
|
const observer = new ResizeObserver(() => {
|
|
requestAnimationFrame(() => refreshGridAfterContainerResize(hot))
|
|
})
|
|
observer.observe(container)
|
|
|
|
return observer
|
|
}
|