You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ResizingController._synchronizeColumns andm_utils.tswere refactored for readability and type-safety ahead of the fix, without changing behavior:
ResizingController:
Replaced the untyped_maxWidth: anyfield with a small_maxWidth: MaxWidthControllerhelper object (isModified,set(),clear()) that encapsulates reading/writing the element'smaxWidthCSS, instead of manually checking truthiness and mutating the DOM inline in_synchronizeColumns.
Extracted the "temporarily switch to best-fit mode, measure, restore focus" logic out of_synchronizeColumnsinto a new_enableTemporaryBestFitMode()method that returns a cleanup closure, replacing the previousresetBestFitModeboolean flag plus an inline restore-focus block.
Extracted the localnormalizeWidthsByExpandColumnsclosure into a proper private method_normalizeWidthsByExpandColumns(resultWidths, visibleColumns), simplified withfindIndexinstead of two separateeachloops.
SimplifiedneedBestFit/hasMinWidthcomputation from imperative loops with early-exit flags into single.some()expressions, and narrowedresultWidthsto(number | string | undefined)[], scoped inside thedeferUpdatecallback instead of the outer closure.
This refactor made_synchronizeColumnseasier to reason about and was a prerequisite for isolating and fixing thevisibleWidth/widthstaleness bug (T1329677) in the same best-fit measurement code path.
These two were also given an explicit contract (SelectionRange), and this part is not behavior-preserving — calling it out explicitly:
getSelectionRange now returns { selectionStart: -1, selectionEnd: -1 } instead of {}
when the range can't be read (no focused element, or an element whose selectionStart
throws, e.g. input[type=number] in Chrome). Non-numeric values are normalized to -1 too.
setSelectionRange now skips the call when either bound is negative.
Previously, setSelectionRange(el, {}) called el.setSelectionRange(undefined, undefined),
which the browser coerces to (0, 0) — the caret jumped to the start of the input whenever
the range could not be captured. It now leaves the caret alone.
-1 was chosen as the sentinel because m_editing.ts:2191 already guards on selectionRange.selectionStart >= 0; that call site is unaffected (undefined >= 0 and -1 >= 0 are both false). The only place where behavior changes is restoreFocus in m_grid_view.ts.
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR addresses a DataGrid sizing/resizing issue where column width updates may not be applied immediately by refactoring parts of the grid’s column synchronization flow (best-fit toggling, max-width handling) and tightening selection-range handling used during temporary layout measurement. It also includes a small TypeScript-typing workaround in the Popover escape-key handler.
Changes:
Refactors ResizingController._synchronizeColumns to use a temporary best-fit enable/restore helper, normalize group expand column widths, and centralize max-width set/clear logic.
Introduces a typed SelectionRange contract and updates selection-range getters/setters to use explicit sentinel values.
Adjusts Popover overlay-stack comparison typing to avoid a TypeScript “no overlap” error.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
nightskylark
changed the title
T1329677 DataGrid - Column width changes are not applied immediately
DataGrid: Refactor ResizingController._synchronizeColumns
Aug 18, 2026
This changes caret restoration for unsupported controls (for example, input[type=number]) and partially readable ranges, but no regression test covers the new negative-sentinel/skip contract. The existing grid focus coverage only asserts a valid { selectionStart: 1, selectionEnd: 1 } range; please add cases that verify getSelectionRange returns the sentinel and that setSelectionRange is not called when either bound is negative.
The new selection-range contract is not covered for the failure cases it changes: there is no test for an unfocused element or an input whose selectionStart throws, nor for verifying that negative sentinels prevent setSelectionRange from being called. Add focused tests for these cases so the caret-preservation fix is guarded against regression.
This introduces the new -1 sentinel and the guard that skips restoring a selection, but the tests only cover the existing valid { selectionStart: 1, selectionEnd: 1 } path. Please add unit coverage for no focused element and an element whose selectionStart throws (and assert setSelectionRange is not called), so the explicitly changed focus behavior is protected from regression.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ResizingController._synchronizeColumnsandm_utils.tswere refactored for readability and type-safety ahead of the fix, without changing behavior:ResizingController:_maxWidth: anyfield with a small_maxWidth: MaxWidthControllerhelper object (isModified,set(),clear()) that encapsulates reading/writing the element'smaxWidthCSS, instead of manually checking truthiness and mutating the DOM inline in_synchronizeColumns._synchronizeColumnsinto a new_enableTemporaryBestFitMode()method that returns a cleanup closure, replacing the previousresetBestFitModeboolean flag plus an inline restore-focus block.normalizeWidthsByExpandColumnsclosure into a proper private method_normalizeWidthsByExpandColumns(resultWidths, visibleColumns), simplified withfindIndexinstead of two separateeachloops.needBestFit/hasMinWidthcomputation from imperative loops with early-exit flags into single.some()expressions, and narrowedresultWidthsto(number | string | undefined)[], scoped inside thedeferUpdatecallback instead of the outer closure.This refactor made
_synchronizeColumnseasier to reason about and was a prerequisite for isolating and fixing thevisibleWidth/widthstaleness bug (T1329677) in the same best-fit measurement code path.gridCoreUtils.getSelectionRange/setSelectionRange— behavior changeThese two were also given an explicit contract (
SelectionRange), and this part isnot behavior-preserving — calling it out explicitly:
getSelectionRangenow returns{ selectionStart: -1, selectionEnd: -1 }instead of{}when the range can't be read (no focused element, or an element whose
selectionStartthrows, e.g.
input[type=number]in Chrome). Non-numeric values are normalized to-1too.setSelectionRangenow skips the call when either bound is negative.Previously,
setSelectionRange(el, {})calledel.setSelectionRange(undefined, undefined),which the browser coerces to
(0, 0)— the caret jumped to the start of the input wheneverthe range could not be captured. It now leaves the caret alone.
-1was chosen as the sentinel becausem_editing.ts:2191already guards onselectionRange.selectionStart >= 0; that call site is unaffected (undefined >= 0and-1 >= 0are bothfalse). The only place where behavior changes isrestoreFocusinm_grid_view.ts.