проблема при нажатии кнопки
This commit is contained in:
@@ -40,7 +40,7 @@ export const ApprovalMatrix: React.FC<IApprovalMatrixProps> = ({
|
||||
// подсвечивается пол-таблицы и непонятно, что именно переехало. Запоминаем
|
||||
// ключи блока ДО перестановки: после неё индексы уже другие.
|
||||
const [activeKeys, setActiveKeys] = React.useState<string[]>([]);
|
||||
const registerRow = useFlipRows(activeKeys);
|
||||
const registerRow = useFlipRows(activeKeys, rowKeys);
|
||||
|
||||
// Строка → шаг, которому она принадлежит. Нужно, чтобы отрисовать ячейку
|
||||
// «Шаг» один раз на весь шаг (rowSpan) и понять, можно ли двигать его выше/ниже.
|
||||
|
||||
@@ -72,14 +72,22 @@ function drop(row: HTMLTableRowElement): void {
|
||||
* @param activeKeys ключи строк того шага, который двигает пользователь —
|
||||
* только он подсвечивается и поднимается над остальными (см. ApprovalMatrix).
|
||||
* Для прочих изменений состава (добавление/удаление) — пустой массив.
|
||||
* @param rowKeys ключи строк в ТЕКУЩЕМ порядке — единственный сигнал, по
|
||||
* которому решаем, действительно ли что-то переставили (см. ниже, почему
|
||||
* геометрии для этого недостаточно).
|
||||
*/
|
||||
// eslint-disable-next-line @rushstack/no-new-null -- null здесь диктует React: ref-колбэк получает именно null при отвязке узла
|
||||
export function useFlipRows(activeKeys: string[]): (key: string) => (el: HTMLTableRowElement | null) => void {
|
||||
export function useFlipRows(
|
||||
activeKeys: string[],
|
||||
rowKeys: string[]
|
||||
// eslint-disable-next-line @rushstack/no-new-null -- null здесь диктует React: ref-колбэк получает именно null при отвязке узла
|
||||
): (key: string) => (el: HTMLTableRowElement | null) => void {
|
||||
const nodes = React.useRef(new Map<string, HTMLTableRowElement>());
|
||||
// Колбэк на один и тот же ключ должен быть стабильным, иначе React дёргал бы
|
||||
// ref(null)/ref(el) на каждый рендер и карта узлов пересобиралась бы впустую.
|
||||
const refCache = React.useRef(new Map<string, (el: HTMLTableRowElement | null) => void>());
|
||||
const prevTops = React.useRef(new Map<string, number>());
|
||||
// Порядок строк на прошлый коммит — см. проверку orderChanged ниже.
|
||||
const prevRowKeys = React.useRef<string[]>([]);
|
||||
// Свои анимации держим сами, чтобы отменять ИМЕННО их: el.getAnimations()
|
||||
// вернул бы заодно чужие (CSS-переходы и т.п.).
|
||||
const running = React.useRef<Animation[]>([]);
|
||||
@@ -101,6 +109,29 @@ export function useFlipRows(activeKeys: string[]): (key: string) => (el: HTMLTab
|
||||
// useEffect: инвертировать положение нужно до того, как браузер покажет кадр,
|
||||
// иначе будет заметен скачок.
|
||||
React.useLayoutEffect(() => {
|
||||
// ВАЖНО: «строка сдвинулась по пикселям» — недостаточный повод анимировать.
|
||||
// Пример живого бага: заявку отправили на согласование → таблица стала
|
||||
// read-only → у строк пропали колонки со стрелками/кнопками → ширина
|
||||
// текстовых колонок изменилась → где-то текст перенёсся по-другому →
|
||||
// строки СМЕСТИЛИСЬ ПО ВЫСОТЕ, хотя их состав и порядок не менялись вовсе.
|
||||
// Раньше это трактовалось как «переезд» и запускало translateY на
|
||||
// случайную величину — на кадре это выглядело как строки, которые на
|
||||
// мгновение пропадают (уезжают за пределы видимой области) и выскакивает
|
||||
// скролл. Настоящая перестановка меняет НАБОР/ПОРЯДОК ключей — вот это и
|
||||
// проверяем, а не сам факт смещения.
|
||||
const orderChanged =
|
||||
rowKeys.length !== prevRowKeys.current.length || rowKeys.some((k, i) => k !== prevRowKeys.current[i]);
|
||||
prevRowKeys.current = rowKeys;
|
||||
|
||||
if (!orderChanged) {
|
||||
// Порядок тот же — просто обновляем базовую геометрию для следующего
|
||||
// ДЕЙСТВИТЕЛЬНОГО сравнения, без единой анимации на этом проходе.
|
||||
const current = new Map<string, number>();
|
||||
nodes.current.forEach((el, key) => current.set(key, el.getBoundingClientRect().top));
|
||||
prevTops.current = current;
|
||||
return;
|
||||
}
|
||||
|
||||
// Сначала запоминаем, где строка ВИДНА сейчас: при быстрых повторных кликах
|
||||
// она в этот момент ещё летит, и новая анимация обязана стартовать от её
|
||||
// текущего положения на экране, иначе будет рывок.
|
||||
|
||||
Reference in New Issue
Block a user