fix(table): прокрутка не сбрасывается наверх при перетаскивании ширины колонки (H-1)
MRT при isResizingColumn подменяет MRT_TableBody на Memo_MRT_TableBody, тело монтируется заново, виртуализатор строк стартует с initialOffset=0 и сбрасывает scrollTop. rowVirtualizerOptions теперь функция от table, initialOffset читает текущий scrollTop контейнера. Воспроизведено на чистом MRT и на test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
6255f4a250
commit
54f5af6148
@ -451,3 +451,7 @@ const pinnedLayoutKey = useMemo(
|
||||
- Ширина измеряется одним `boundingBox` на шаге 50 (пик хода), до хода — один вызов; цена — один дополнительный вызов внутри пробы из 100 шагов.
|
||||
- Цена ошибки: замеры нового сценария несравнимы со снятыми по старой раскладке; сравнение с базой делается тем же сценарием на обеих ветках.
|
||||
22. **2026-10-28 (контроллер, R-6, M-3, O-3) — диапазон `['','']` не нормализуется в ключе; код не меняется.** В TanStack такой диапазон не снимает фильтр колонки, ключ отличается от «без фильтров»; это безвредный лишний сброс. Наблюдение O-3 (вне скоупа, follow-up): `Cell/Cell/Cell.jsx` ~112 `createHighlightedContent` вызывает `q.replace` на значении фильтра-массива (поведение базы). Цена ошибки: одна лишняя перерисовка на редком действии.
|
||||
23. **2026-11-08 (H-1, замечание PotapovaA в PR #240) — `rowVirtualizerOptions` стал функцией от table с `initialOffset`, читающим `scrollTop` контейнера.**
|
||||
- Причина: `MRT_Table.tsx` (MRT 3.2.1) при `columnSizingInfo.isResizingColumn` меняет `MRT_TableBody` на `Memo_MRT_TableBody`. Это другой тип элемента, тело монтируется заново на начале и на конце перетаскивания. Виртуализатор строк живёт в теле (`useMRT_RowVirtualizer`), новый стартует с `initialOffset = 0` и в `_willUpdate` вызывает `_scrollToOffset(0)`, прокрутка сбрасывается наверх. Воспроизведено на чистом MRT без нашего кода, с управляемым и неуправляемым `columnSizingInfo`, то есть и на `test`; с `initialOffset` прокрутка сохраняется.
|
||||
- Не берём: подмену `isResizingColumn` для MRT (ломает заморозку тела, D3/D4).
|
||||
- Цена ошибки: при нулевом `scrollTop` или отсутствии контейнера `initialOffset` равен 0, поведение как раньше.
|
||||
|
||||
@ -15,7 +15,7 @@ import { toast } from 'react-toastify';
|
||||
import { SheetModals } from './Modals/SheetModals';
|
||||
import { additionExpenseRowTable, additionVspRowTable } from './constants/addingRowConfig';
|
||||
import { BASE_TABLE_CONFIG, TABLE_ROW_HEIGHT, TABLE_CONTAINER_SX, getTablePaperStyles, getTableRowHeightPx } from './constants/tableConfig';
|
||||
import { createFixedRowVirtualizerOptions } from './utils/virtualizerOptions';
|
||||
import { createRowVirtualizerOptionsForTable } from './utils/virtualizerOptions';
|
||||
import { getActiveCellSx } from './utils/activeCellCss';
|
||||
import { useLockedCellsStore, useRealtimeActions, useVspOptions } from './contexts/RealtimeContext';
|
||||
import { useBudgetYear } from './hooks/useBudgetYear';
|
||||
@ -39,11 +39,13 @@ import { FormsNoCanAddRow } from './constants/formConfig';
|
||||
|
||||
const CONFIG_CACHE = new Map();
|
||||
|
||||
const ROW_VIRTUALIZER_OPTIONS = createFixedRowVirtualizerOptions({
|
||||
const ROW_VIRTUALIZER_PARAMS = {
|
||||
rowHeight: getTableRowHeightPx,
|
||||
overscan: 2,
|
||||
extra: { scrollPaddingStart: 0, scrollPaddingEnd: 0 },
|
||||
});
|
||||
};
|
||||
// H-1: функция от table, чтобы initialOffset видел scrollTop контейнера (см. virtualizerOptions.js)
|
||||
const getRowVirtualizerOptions = ({ table }) => createRowVirtualizerOptionsForTable(table, ROW_VIRTUALIZER_PARAMS);
|
||||
|
||||
const hasVspDropdown = (columns) =>
|
||||
columns.some((column) => column.editType === 'vsp_dropdown' || (column.columns?.length && hasVspDropdown(column.columns)));
|
||||
@ -451,7 +453,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
enableColumnVirtualization: true,
|
||||
rowVirtualizerInstanceRef: rowVirtualizerRef,
|
||||
columnVirtualizerInstanceRef: columnVirtualizerRef,
|
||||
rowVirtualizerOptions: ROW_VIRTUALIZER_OPTIONS,
|
||||
rowVirtualizerOptions: getRowVirtualizerOptions,
|
||||
onEditingCellChange: (cell) => {
|
||||
// AURORA-1891: защита на случай, если что-то кроме нашего собственного
|
||||
// onClick/onKeyDown откроет редактор для нередактируемой ячейки —
|
||||
|
||||
@ -17,6 +17,15 @@ export const createFixedRowVirtualizerOptions = ({ rowHeight, overscan, extra =
|
||||
};
|
||||
};
|
||||
|
||||
// Опции для rowVirtualizerOptions в форме функции от table. MRT при начале и конце перетаскивания
|
||||
// ширины подменяет MRT_TableBody на Memo_MRT_TableBody (MRT_Table.tsx), тело монтируется заново,
|
||||
// новый виртуализатор стартует с initialOffset = 0 и в _willUpdate сбрасывает scrollTop контейнера.
|
||||
// initialOffset читает текущий scrollTop, и позиция прокрутки переживает перемонтирование (AURORA-1839, H-1).
|
||||
export const createRowVirtualizerOptionsForTable = (table, params) => ({
|
||||
...createFixedRowVirtualizerOptions(params),
|
||||
initialOffset: () => table?.refs?.tableContainerRef?.current?.scrollTop ?? 0,
|
||||
});
|
||||
|
||||
// Размер 1rem в px по правилу App.css: .83vw при ширине окна <= 1920px, иначе 16px.
|
||||
// Считается по window.innerWidth, чтобы не читать layout и не вызывать пересчёт стилей.
|
||||
const REM_BASE_PX = 16;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { createFixedRowVirtualizerOptions, getRootFontSizePx } from './virtualizerOptions.js';
|
||||
import { createFixedRowVirtualizerOptions, createRowVirtualizerOptionsForTable, getRootFontSizePx } from './virtualizerOptions.js';
|
||||
|
||||
const throwingElement = new Proxy(
|
||||
{},
|
||||
@ -49,3 +49,19 @@ test('getRootFontSizePx повторяет правило App.css', () => {
|
||||
assert.ok(Math.abs(getRootFontSizePx(1600) * 3 - 39.84) < 0.01);
|
||||
assert.equal(getRootFontSizePx(undefined), 16);
|
||||
});
|
||||
|
||||
// AURORA-1839 (H-1): MRT при начале/конце перетаскивания ширины подменяет компонент тела таблицы
|
||||
// (MRT_TableBody <-> Memo_MRT_TableBody), тело монтируется заново, виртуализатор строк создаётся
|
||||
// с initialOffset = 0 и сбрасывает scrollTop контейнера. initialOffset должен читать текущий scrollTop.
|
||||
test('createRowVirtualizerOptionsForTable: initialOffset читает scrollTop контейнера таблицы', () => {
|
||||
const table = { refs: { tableContainerRef: { current: { scrollTop: 30000 } } } };
|
||||
const options = createRowVirtualizerOptionsForTable(table, { rowHeight: 37, overscan: 2 });
|
||||
assert.equal(options.initialOffset(), 30000);
|
||||
table.refs.tableContainerRef.current.scrollTop = 120;
|
||||
assert.equal(options.initialOffset(), 120);
|
||||
assert.equal(options.estimateSize(), 37);
|
||||
});
|
||||
|
||||
test('createRowVirtualizerOptionsForTable: без контейнера initialOffset = 0', () => {
|
||||
assert.equal(createRowVirtualizerOptionsForTable({ refs: { tableContainerRef: { current: null } } }, { rowHeight: 37 }).initialOffset(), 0);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user