fix(grid): v3 review fixes — split-null crash, monitor race, drag-safe gutters
Adversarial review (4 lenses → per-finding verify) of v3 confirmed 6 issues:
- HIGH: splitForLayout({"grid-4":null}) threw a TypeError — null passed the
`!== undefined` guard, then null.cols threw. Since splitForLayout runs on every
grid render, one corrupt localStorage entry would brick the tab UI. Now guards
`!== null && typeof === 'object'`.
- MED: a monitor toggled before the session finished attaching (id still null)
showed the button active while the pane stayed live and sent a resize, and did
not self-correct. onSessionId now reconciles a pending monitor once the id lands.
- MED: renderGutters destroyed + recreated handles on every applyLayout, dropping
the drag listeners if a re-render fired mid-drag. A draggingGutter flag now skips
the rebuild while dragging.
- LOW: grid-presets hardcoded the 1024px breakpoint → now uses GRID_MIN_WIDTH.
Regression tests added (null-split no-throw, attach reconcile, drag survives a
concurrent re-render). typecheck + build:web clean, 1615 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,6 +165,11 @@ describe('grid-layout: resizable splitters (v3)', () => {
|
||||
expect(splitForLayout({}, 'split-2')).toEqual(defaultSplit('split-2'))
|
||||
})
|
||||
|
||||
it('splitForLayout falls back to default for a null stored entry (no throw)', () => {
|
||||
// {"grid-4":null} is valid JSON a corrupt/tampered store could hold.
|
||||
expect(splitForLayout({ 'grid-4': null } as never, 'grid-4')).toEqual(defaultSplit('grid-4'))
|
||||
})
|
||||
|
||||
it('saveGridSplits + loadGridSplits round-trip', () => {
|
||||
saveGridSplits({ 'grid-4': { cols: [1.5, 0.5], rows: [1, 1] } })
|
||||
expect(loadGridSplits()).toEqual({ 'grid-4': { cols: [1.5, 0.5], rows: [1, 1] } })
|
||||
|
||||
Reference in New Issue
Block a user