Sitelet https://github.com/alaarab/ogrid/pull/39
Skip to content

fix: full-audit correctness sprint (formulas, XLSX, keyboard/a11y, windowed, virtual scroll, columns, clipboard, editors, packaging, MCP) - #39

Merged
alaarab merged 46 commits into
mainfrom
fix/scan-2026-10
Oct 2, 2026
Merged

alaarab merged 46 commits into
mainfrom
fix/scan-2026-10

Conversation

@alaarab

@alaarab alaarab commented Oct 2, 2026

Copy link
Copy Markdown
Owner

A full codebase audit (3 Claude + 5 DeepSeek reviewers, 530 raw findings → 226 verified issues) fixed across 17 workstreams, each reviewed and then integrated here with cross-branch conflicts resolved semantically.

Highlights

  • XLSX import: shared (filled-down) formulas and header-promoted references were wrong; sheet switching leaked formulas.
  • Keyboard: Backspace/Delete typed in a filter box deleted the selected cells; Tab trapped focus; Shift+Arrow lost its anchor.
  • Formulas: one coordinate model, so formulas follow their records through sort, filter, paging and column changes; all edits recalculate dependents and are undoable. Function DoS bounds come with configurable formulaLimits, and there are many Excel-compatibility fixes.
  • Windowed data sources and virtual scroll: stale or loading rows after sort/filter, a blank band on very large grids, and scrollToRow was a no-op.
  • Columns, clipboard/fill, controlled props, CSS/kit parity, filters, editors, packaging ("use client", React 17 ESM), MCP server.
  • Performance: rows are now actually memoized.

See the [Unreleased] CHANGELOG section for the full list, including Changed behavior.

Verification

  • npm run test:all: 3625 pass, 0 fail (main: 3115)
  • Forced turbo build (incl. docs), biome, typecheck, check:types, frozen lockfile
  • e2e smoke 13/13 and docs 1/1; Radix e2e 87/87. Fluent e2e passes on rerun but runs close to its 30 s timeout under load.

🤖 Generated with Claude Code

alaarab and others added 30 commits October 1, 2026 15:45
- Header options and context menus: role=menu/menuitem, roving focus,
  arrows/Home/End, Escape/Tab close, focus restore (useMenuKeyboardNav)
- Per-column trigger labels with aria-haspopup/aria-expanded
- Radix column chooser reachable by keyboard and labelled
- Rich select highlight resets on search; select editors expose
  combobox + aria-activedescendant
- aria-selected on range cells, focus ring on grid wrapper, editable
  cells no longer role=button, name box as <output>, quieter status bar
- SideBar/SheetTabs follow the WAI-ARIA tabs pattern
- prefers-reduced-motion for marching ants and spinner

Clusters: R12 R11 L16 R14 A03 A08 A09 A02 A06 A05 A07 L30 (A04 partial, A01 skipped)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e (scan T12)

- Header leaf row follows columnOrder and responsive hiding; split
  groups render one cell per adjacent run
- Uncontrolled column reorder works; hidden columns keep their place;
  no-op drops don't fire the callback
- calculateDropTarget returns the dragged column's final index (fixes
  rightward off-by-one) and measures header cells only
- Drag resize/autosize fire onColumnResized and reach getColumnState;
  applyColumnState/per-sheet widths apply after mount
- minWidth respected on resize; pins from late columns; pin+visibility
  updates in the same tick no longer clobber; header controls and
  filter popovers no longer start a drag

Clusters: L01-L10

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… T15)

- Single-row selection works with numeric row ids (S08)
- Worker sort follows controlled sort and reports loading (D01, D02)
- onUndo/onRedo/canUndo/canRedo drive Ctrl+Z/Y and the context menu
  without double-firing the internal stack (D03)
- Same-id data replacement re-filters/re-sorts unless it is the host
  applying a grid-emitted edit (D06); duplicate row refs and structural
  filter equality (S13, D18)
- Header select-all merges across pages; selectAll covers all filtered
  rows (S09); setSelectedRows fires onSelectionChange (D16 partial)
- Status bar counts setRowData rows, page clamped, getEditorProps inert
  when not editing (D15, D21, D29)
- cellEditorPopup:false no longer disables custom editors (U05)
- Docs: sort toggle semantics, selection scoping (D19, S09)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(scan T9)

- Fill drag, Ctrl+D and commitFill tile the source pattern (Excel
  semantics for down/right/up/left) instead of copying the top-left cell
- Pending cut is keyed by row/column id so sort/page changes can't clear
  the wrong cells; later copy cancels the cut; cut clears only when the
  pasted text is the cut's own (line-ending tolerant)
- Paste works under StrictMode; a rejected clipboard read aborts the
  paste and calls the new optional onClipboardError prop
- Drag selection ignores the sticky header and other grids
- clipboardFormatter '' respected; TSV quoting round-trips leading quotes
- Unchanged edits no longer emit onCellValueChanged or undo entries

Clusters: S01 S02 S03 S04 S06 S07 U14 U15 S12 (S11 partial, S05 skipped)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- columnMeta and table props are stable across unchanged renders, so
  rows only re-render when their inputs change (D12, D07)
- areGridRowPropsEqual compares every row input by identity, including
  formulaVersion, row-number width, virtualization spacers, renderer and
  handlers, with per-row selection/editing checks (K03, D13, D14)
- Inline columns no longer force re-filter/re-sort each render (D05)
- Aggregations only when the status bar is on (U04); cell cache fixed
  for >1024 columns and checkbox/row-number toggles (U20)
- Header filters keep stable props (D11); filter/worker paths cheaper
  and consistent for Date values (U06, U18); stable headless callbacks
  (D20); portaled menus and pointer listeners scoped (L26, D22)

Rows that are mutated in place no longer repaint on an unrelated render;
replace the row object (immutable update) instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(scan T13)

- Popovers, header menu, select dropdown and popover editors render above
  fullscreen (--ogrid-z-popover 10001; Z_INDEX.DROPDOWN/FILTER_POPOVER)
- Checkbox/row-number columns sticky with correct offsets; left-pinned
  columns start after them; column-letter spacer cells held to width
- Tinted pinned cells stay opaque; Fluent leaf headers align with groups
- Header menu clamps to viewport and closes only when its header moves
- Sort arrow in both kits; select dropdown carries theme tokens;
  Fluent column chooser portaled (no clipping) and themed
- --ogrid-selection honored with --ogrid-selection-color fallback
- Removed no-op content-visibility and dead compact-pagination CSS

Clusters: L17 L11 L12 L13 L14 L18 L31 L25 L27 L24 L22 (L15 L23 partial)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(scan T10)

- Re-request the last visible window on every context change (V02)
- Descriptor cache hits require the same row object and raw value (V03, U21)
- Swapped sources receive current sort/filters and window; unknown count
  keeps the previous count (V04)
- Keyboard navigation, copy, fill, editing and select-all work over loaded
  rows via WindowedDataState.loadedRows; pager hidden (V05)
- WindowedRowCache.invalidate refetches count, aborts pending requests,
  keeps the requested window resident (U17)
- Single hidden loading status region (V08); aria-rowcount uses the
  filtered total via totalCount (V09)

V06 partial: inline dataSource objects still refetch the visible window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…se Tab (scan T6, T8)

- Grid keydown ignores keys from header controls, portaled popovers,
  menus and text inputs; Backspace/Delete/Ctrl+X/Ctrl+V in a filter no
  longer touch cell data (R01)
- Inline editors own Home/End/PageUp/PageDown; Tab commits and moves
  (R05); boolean editors take focus (R13); rich select commits on Tab
  and cancels on blur (R15); Escape only exits fullscreen when unhandled
  (R09)
- Tab leaves the grid at the first/last cell and before a cell is
  active (R02); Shift+Space toggles the active row's selection (R08b)
- Active cell is the selection anchor for Shift+Arrow/PageUp/PageDown
  and Shift+click (R03, R04); headless useGridFocus extends correctly
  (R10); anchor highlight correct with checkbox/row-number columns (S14);
  shift-click row anchor tracked by row id (S10 partial)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ine (scan T1)

- Formulas, A1 refs, column letters, row numbers, name box, formula bar
  and reference overlay share sheet coordinates: flat leaf column index
  and the record's index in data (IFormulaRowMap), so hiding/reordering
  columns and sort/filter/paging keep formulas on their records (K01, K02)
- Edit, paste, fill, delete, cut, undo/redo and the formula bar all go
  through the useUndoRedo path: plain values clear overwritten formulas,
  formula changes are undoable, and the engine is notified after the
  consumer's data update renders (K04, K05, K07)
- Formula bar commits via the grid writer; Enter no longer deletes the
  formula; text refreshes on value/formula changes (K06)
- Cross-sheet recalc via onSheetChanged (F18); formulas toggle and engine
  settings changes keep sheets and formulas (K09)
- cellReferences name box is an <output> element (A06 follow-up)

In cellReferences/formulas mode, row numbers show each record's data row
(not 1..n after a sort) and hidden columns leave gaps in column letters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/testing/index.ts
# Conflicts:
#	packages/react/src/hooks/useOGrid.ts
#	packages/react/src/hooks/useOGridDataFetching.ts
#	packages/react/src/hooks/useOGridImperativeHandle.ts
… (scan T19)

- TimePicker gets an Apply button and Slider track clicks commit, through
  one commit scheduler (no double onCellValueChanged) (I08)
- minuteStep <= 0 no longer hangs; react-inputs reuses the guarded
  time utilities from ogrid-inputs (I01)
- DateTimePicker keeps unparseable values instead of replacing them with
  today, converts Z/offset values to local time, and has a focusable
  text input for keyboard entry (I02, I03)
- DatePicker emits clean YYYY-MM-DD while typing (I07); Escape cancels
  once (I17); Slider thumb keys don't reach the grid
- ogrid-inputs helpers: normalizeHex uppercases and keeps alpha,
  parseTags de-duplicates, parseDate is stricter, snapToStep rounds away
  float noise

17 of 19 T19 clusters fixed; I04 and I10 partial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…scan T17, T18)

- Dates follow one convention (UTC calendar days) across display,
  filters (sync and worker), toDateTimestamp and editor init
- Status bar Count/Min/Avg ignore blanks, whitespace, booleans and
  non-finite values (Excel COUNT semantics)
- Text filters also match the displayed text (valueFormatter/date
  format) in addition to the raw value (U09)
- Multi-select options include "(Blanks)" for blank cells (U07); text
  sort is locale-aware (U23); autosize uses CSS.escape (U19)
- Boolean strings "false", "0", "no" display unchecked (U08)
- CSV export guards every non-number value against formula injection
  and quotes after prefixing; BOM only on downloads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(scan T11)

- Scaled virtual scroll (very large row counts) has no blank band; first
  and last rows land exactly at the viewport edges; overscan rows that
  don't fit are dropped instead of shifting the block (V01)
- IOGridApi.scrollToRow works for plain, virtualized and scaled grids
  with start/center/end alignment (R07)
- Keyboard navigation scrolls unrendered rows into view and focuses them
  when they appear (R08); PageUp/PageDown size re-measured (R06)
- Virtual-scroll min-height no longer overflows short containers (L19);
  virtualScroll.rowHeight applied to rendered rows (L20)
- Container re-measured on resize (V07); empty window after data shrinks
  fixed (U16)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Multi-select filter choices survive grid re-renders; state resyncs
  only when the popover opens (D10)
- People search ignores stale responses and always clears its spinner
  (D09); filter option loads guard against stale results (D17 partial)
- SideBar text filters commit on a per-keystroke timer and can be
  cleared; people columns hidden from the panel (D27)
- Middle-click auto-scroll ignores links/controls correctly (D24)
- CellErrorBoundary resets on row, value or edit-mode change via the new
  optional resetKeys prop and reports each failure once (D26)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/hooks/__tests__/useRowSelection.test.ts
- ogrid://docs/{+path} resolves nested doc paths; all advertised doc
  URIs readable (M03); code-example imports kept in bundled docs (M01);
  POSIX doc paths on Windows (M02); clear error when docs are missing (M17)
- Bridge: heartbeat updates lastSeen (M05); percent-encoded grid ids
  (M04); sanitized state pushes and zod-validated commands (M06, M07);
  malformed URLs get 400 instead of crashing (M08); oversized bodies get
  413 (M14); timed-out commands dropped and results scoped to their grid
  (M09); closes when stdin ends (M13)
- Client: no overlapping polls, disconnect aborts in-flight requests
  (M12); set_filter/set_sort via IOGridApi, selected ids pushed (M16 partial)
- Bridge tools registered only when listening; port validated; server
  reports package version (M10 partial)

Localhost/Origin/Host guards unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/core/src/utils/dataGridViewModel.ts
#	packages/react/src/hooks/useDataGridState.ts
#	packages/react/src/hooks/useDataGridTableOrchestration.ts
…ndowed sources

The windowed branch feeds a sparse loadedRows array (holes for unloaded
rows) into useRowSelection and the row-click handler. Three lookups added
by other branches iterate holes and call getRowId(undefined):
- props-sync's page-scoped handleSelectAll (for...of)
- keyboard's shift-click anchor lookup (findIndex)
- props-sync's S08 single-row click lookup (find)

Use hole-skipping iteration / explicit undefined guards, with regression
tests for each (hook tests over a sparse array, plus a Radix windowed
single-selection test on a row loaded after unloaded ones).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/components/BaseInlineCellEditor.tsx
#	packages/react/src/components/BaseTableHeader.tsx
#	packages/react/src/hooks/__tests__/useColumnPinning.test.ts
#	packages/react/src/hooks/useDataGridLayout.ts
…g (scan T2, T3)

- Shared (filled-down) formulas expand per cell using the tokenizer-based
  reference shift; string literals, quoted sheet names and $-absolute
  refs are left intact (K11)
- Header-row promotion rebases formula refs with Excel's delete-row rule;
  ranges starting on the header shrink, lone header refs become #REF!
  and keep Excel's cached result (K10)
- XlsxWorkbookGrid remounts when the loaded sheet data changes, so
  formulas, sort and undo don't leak between sheets/workbooks (K08)
- Cached results read correctly (errors as text, no [object Object]),
  cross-sheet/_xlfn formulas keep cached values (K12, K13); export
  writes formulas without '=' and fixes headerRow:'none' offsets (K19,
  K27); duplicate/blank headers de-duplicated (K20)
- Pre-parse size checks (file bytes, ZIP entries incl. ZIP64, trailing
  bytes tolerated) with configurable limits; Infinity = no limit (K14,
  K15); real CSV parser with quotes, CRLF, BOM and delimiter detection
  (K16); NaN/Infinity not written to numeric cells (K17); column
  virtualization for wide sheets (K18); clear errors for empty
  workbooks, bad sheet names and mount() without a source (K21, K22)

XLSX/CSV loading now rejects files over 50 MiB by default; raise
limits.maxFileBytes for larger trusted files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/components/BaseInlineCellEditor.tsx
#	packages/react/src/hooks/__tests__/useRichSelectState.test.ts
#	packages/react/src/styles/_data-grid-table.scss
…name

a11y-menus (R12) renamed the header trigger's accessible name from
"Column options" to "<column> column options". Tests added on the
columns (L10) and css-parity (L17/L18) branches still looked it up by
the old label. Point them at "Name column options"; assertions unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Work bounds: generous configurable limits (5M range cells, 20M work
  units) via the new formulaLimits prop / FormulaEngine({ limits });
  fixed bounds for WORKDAY.INTL/WORKDAY/NETWORKDAYS, COMBIN/PERMUT,
  64x64 matrices (MDETERM via LU), nesting depth, formula/text length
  and the toNumber ReDoS (F01 F02 F03 F08 F09 F21 F23)
- Dates: functions return Dates at UTC midnight; arithmetic and
  comparisons use Excel serial days (F06, F07)
- Cycles: clearing a formula in a cycle recovers; only members get
  #CIRC! (F04, F05); INDIRECT/OFFSET ordering (F11)
- Excel semantics: criteria parser (blanks, <>, wildcards, booleans,
  dates), IF/AND/OR coercion, mixed-type comparisons, FP-safe rounding,
  CORREL alignment, MODE #N/A, NETWORKDAYS holidays, ROW()/COLUMN(),
  TEXT formats, RATE convergence, XLOOKUP text modes, *IFS dimension
  checks, non-finite results, named ranges ending in digits, and more
  (F10 F12-F17 F19 F20 F22 F24-F31)
- FormulaError is a single class across entry points (F10)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/core/src/utils/fillHelpers.ts
#	packages/core/src/utils/gridRowComparator.ts
#	packages/react/src/components/BaseTableHeader.tsx
#	packages/react/src/hooks/__tests__/useUndoRedo.test.ts
#	packages/react/src/hooks/useClipboard.ts
#	packages/react/src/hooks/useDataGridInteraction.ts
#	packages/react/src/hooks/useFillHandleInternal.ts
#	packages/react/src/hooks/useFormulaEngine.ts
#	packages/react/src/hooks/useOGrid.ts
#	packages/react/src/testing/index.ts
…et-row model

- useUndoRedo: props-sync's maxUndoDepth rebuild created an
  UndoRedoStack<ICellValueChangedEvent>, but formula-integration changed
  the history to UndoEntry (value or formula changes). Rebuild with the
  entry type (build failed with TS2322).
- rowMemoTestFactory K03: render-perf's test put initialFormulas row 4
  and read it back at screen row 4, i.e. the display-coordinate model
  formula-integration (K02) replaced. Under the default Name sort, data
  row 4 (Epsilon) shows on screen row 3. Locate the dependent cell by its
  record; the assertion (B5 repaints to 101 in another, memoized row) is
  unchanged and still fails when formulaVersion is dropped from row props.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ormula cut/paste

Regression tests for behaviour that only exists once fill-clipboard and
formula-integration are combined:
- core applyFillValues: a tiled formula fill shifts each destination by
  the sheet distance from its own tile source (fails with either branch's
  pre-merge logic).
- useFillHandleInternal + useUndoRedo: drag-filling a two-row formula
  block in a sorted view writes per-record references and undoes in one
  step (fails if the batch opens after the formula writes).
- useClipboard: pasting a cut formula back onto its own cell keeps it
  (cut-clear skips pasted formulas), and pasting it elsewhere still
  clears the cut source under the text-match rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- React 17 under strict ESM: builds bundle a minimal JSX runtime built on
  createElement/Fragment, so ogrid-react and ogrid-react-inputs load on
  React 17 without react/jsx-runtime; React 18/19 output unchanged (P02)
- 'use client' is the first statement in every React entry (post-build
  script, part of turbo build inputs)
- process.env access guarded (U12); validation wired through useOGrid
  (U11); status bar panels implemented (U10); optionsSource/yearsCount
  documented as no-ops and deprecated
- react-xlsx-browser peers trimmed (K24); README guidance for Vitest,
  Vite SSR and Jest CSS handling (P03 partial, P05)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alaarab and others added 16 commits October 1, 2026 17:33
…ead for paste

Full Playwright matrix on the integration branch failed two react-fluent
tests (react-radix didn't run because the matrix stops at the first failing kit):
- getContextMenuItem looked up role="button"; a11y-menus (R11) made the
  React context menu items role="menuitem".
- "Ctrl+V pastes copied value": fill-clipboard (S06) aborts a paste when
  navigator.clipboard.readText() rejects instead of pasting the stale
  in-page copy. Headless Chromium rejects readText without the
  clipboard-read permission, so the test only passed through that
  fallback. Grant clipboard-read/write for the Clipboard describe.

After: react-fluent 76 passed / 11 skipped, react-radix 87 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/core/src/types/columnTypes.ts
#	packages/core/src/utils/clientSideData.ts
#	packages/core/src/utils/workerSortFilter.ts
#	packages/docs/docs/api/column-def.mdx
…y with the editor

Premium editors (react-inputs) render as popover cell editors, several with
a text input. Before the keyboard branch, Home/End/PageUp/PageDown typed
there reached the grid keydown handler. Pin the merged behaviour in the
Radix kit with a custom popover editor holding a text input: the keys are
not prevented, nothing commits, and the active cell stays put. The keys are
kept from the grid in two ways: the event-target filter (portaled targets
are "outside") and the editing guards on Home/End/PageUp/PageDown. The test
fails only when both are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/hooks/useOGridImperativeHandle.ts
…board Shift paths

virtual-scroll and keyboard merged cleanly as text but not in behaviour:
keyboard's Shift+Arrow / Shift+PageUp/PageDown keep the active cell (the
anchor) in place, so virtual-scroll's index scroll in useActiveCell never
ran for the moving end. Keyboard's local scrollCellIntoView only worked on
rendered cells and added pixel deltas to a scaled scrollTop, and Shift+Page
skipped scrolling entirely on virtual grids.

- utils/scrollCellIntoView: one helper. Vertical scroll by index when a
  virtual scroller exists, DOM rect deltas otherwise; horizontal via DOM.
- useActiveCell: keeps its synchronous index scroll (focus retry depends on
  it) and uses the helper for the RAF phase.
- useKeyboardNavigation: scrollToIndexRef threaded from useDataGridState
  through useDataGridInteraction; Shift+Arrow and Shift+PageUp/PageDown use
  the helper; local copy deleted.
- setSelectedRows: one implementation (props-sync's all-filtered-rows pool)
  plus virtual-scroll's de-duplicated selectedRowIds.

Tests: Shift+PageDown and Shift+ArrowDown in a virtual grid scroll by index
(both fail on the merge commit); helper unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/react/src/hooks/useFormulaEngine.ts
#	packages/react/src/types/dataGridTypes.ts
…ications; formulaLimits rebuild test

formula-functions' defineNamedRange/removeNamedRange recalculate every
formula with the last accessor the engine saw, which only setFormula,
recalcAll and loadFormulas updated. formula-integration notifies the
engine through onCellChanged/onCellsChanged/onSheetChanged with an
accessor over the latest data, so a named-range change after an edit
recalculated against stale data. Those three now update it too.

The merge wired formulaLimits into engine creation and the rebuild check
(alongside formulaFunctions and namedRanges). Test that a changed limit
rebuilds and re-evaluates existing formulas while an equal inline object
does not.

Tests fail without each change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/core/src/utils/windowedRowCache.ts
#	packages/react/src/hooks/useOGrid.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der-independent

measureColumnContentWidth now filters [data-column-id] cells by value
instead of building a CSS.escape'd selector, which happy-dom rejected for
ids containing quotes/backslashes. The header-menu autosize test stubs the
offsetWidth the code actually measures, and the scrollToRow suite installs
its own ResizeObserver stub instead of inheriting a reset jest mock from
whichever test file ran first (CI file order differs from local).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing test

Reverts the columnAutosize selector change from the previous commit (core
tests pin the escaped-selector contract). The header-menu scoping test now
uses a plain column id, since happy-dom's selector parser rejects the
escaped quote form depending on test order; special-character ids stay
covered by core's mocked autosize regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Formula and filter dates now use one UTC calendar-day convention, so
WEEKDAY/NETWORKDAYS and worker timestamp fixtures built with local
constructors shifted a day under TZ=Pacific/Auckland in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alaarab
alaarab merged commit d85751e into main Oct 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant