Skip to content

DataGrid: Refactor ResizingController._synchronizeColumns - #34325

Merged
nightskylark merged 19 commits into
DevExpress:mainfrom
nightskylark:T1329677
Sep 23, 2026
Merged

nightskylark merged 19 commits into
DevExpress:mainfrom
nightskylark:T1329677

Conversation

@nightskylark

@nightskylark nightskylark commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

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.

gridCoreUtils.getSelectionRange / setSelectionRange — behavior change

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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.

File Description
packages/devextreme/js/__internal/ui/popover/popover.ts Tweaks overlay stack top-check typing in ESC key handler.
packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Refactors grid column synchronization/best-fit/maxWidth handling related to resizing.
packages/devextreme/js/__internal/grids/grid_core/m_utils.ts Adds SelectionRange type and makes selection-range APIs more explicit/typed.

Comment thread packages/devextreme/js/__internal/ui/popover/popover.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/m_utils.ts
@nightskylark nightskylark self-assigned this Jul 24, 2026
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
@nightskylark nightskylark changed the title T1329677 DataGrid - Column width changes are not applied immediately DataGrid: Refactor ResizingController._synchronizeColumns Aug 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The new index collection performs repeated array copies, creating an avoidable O(n²) cost during column synchronization.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity · 1 Low severity

Open (2)
Resolved since last review (2)

Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated
@nightskylark
nightskylark marked this pull request as ready for review September 22, 2026 11:57
Copilot AI review requested due to automatic review settings September 22, 2026 11:57
@nightskylark
nightskylark requested a review from a team as a code owner September 22, 2026 11:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The refactor is internally consistent and the changed behavior is correctly guarded.

Review effort: Lite
Findings: 1 Low severity

Open (1)
Resolved since last review (1)

Copilot AI review requested due to automatic review settings September 22, 2026 12:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new selection-range behavior lacks regression coverage for unsupported or partially readable ranges.

Review effort: Lite
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Add regression tests for negative selection sentinel and skipped restoration

packages/​devextreme/​js/​__internal/​grids/​grid_core/​m_utils.ts:530

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.

Comment thread packages/devextreme/js/__internal/grids/grid_core/views/m_grid_view.ts Outdated

public resizeCompleted!: Callback;

private _isMaxWidthSet = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: An underscore in the name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return dataType === 'date' || dataType === 'datetime';
}

export interface SelectionRange {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually keep types and interfaces in a separate types.ts file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copilot AI review requested due to automatic review settings September 23, 2026 16:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

One or more issues must be addressed before approval.

Review effort: Lite
Findings: None

Copilot AI review requested due to automatic review settings September 23, 2026 17:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Add focused tests for selection-range failure cases and negative-sentinel handling.

Review effort: Lite
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Medium severity Add tests for selection-range failure cases and negative sentinels

packages/​devextreme/​js/​__internal/​grids/​grid_core/​m_utils.ts:512

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.

Copilot AI review requested due to automatic review settings September 23, 2026 17:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Best-fit mode lifecycle ordering must be preserved before approval.

Review effort: Lite
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Low severity Add coverage for skipped selection restoration edge cases

packages/​devextreme/​js/​__internal/​grids/​grid_core/​m_utils.ts:525

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.

@nightskylark
nightskylark added this pull request to the merge queue Sep 23, 2026
Merged via the queue into DevExpress:main with commit d565b65 Sep 23, 2026
126 checks passed
@nightskylark
nightskylark deleted the T1329677 branch September 23, 2026 18:25
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.

3 participants