/** * CELL ANIMATIONS TESTS * * Covers FLIP-style animations on: * - Programmatic column reorder via the API (cells shift `left`). * - Sort change (rows shift `top`) when `getRowId` is provided so cell * identity is row-stable. * * Cells that newly enter the visible band slide in from their actual pre- * change off-screen position; cells that leave the visible band slide out * to their actual post-change off-screen position. The body container's * overflow clip turns those long off-screen translates into "appears to * slide in from the viewport edge" visually. * * Animations default to `true`. Live drag reorder is intentionally not * animated (we don't want to fight the user's pointer mid-drag). */ import { SimpleTableVanilla } from "../../src/index"; import type { Meta } from "@storybook/html"; declare const meta: Meta; export default meta; export declare const ProgrammaticReorderAnimation: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Simplest possible reorder animation test: a 3 columns × 3 rows table. * * Step 1 is the straightforward case — move the center column (B) to the * rightmost position by swapping B and C via * `table.update({ defaultHeaders: [...] })`. After that animation settles, * the play function chains four more reorders (5 total) so we exercise: * * - Pairwise neighbour swaps (B↔C, A↔B). * - Long-distance swaps (first ↔ last column). * - A "rotate back to original" reset. * * For every step we synchronously read the FLIP "First" frame and assert * that each cell's inverse `transform-X` exactly matches `oldLeft − newLeft` * (≤ 1.5px tolerance), then wait past `SLOW_DURATION` and assert no leftover * transforms and no retained ghosts before moving on to the next step. * * Expected FLIP behaviour for each reorder: * - Cells whose `left` increases slide RIGHT, so their inverse transform-X * is NEGATIVE (`oldLeft − newLeft < 0`). * - Cells whose `left` decreases slide LEFT, so their inverse transform-X * is POSITIVE (`oldLeft − newLeft > 0`). * - Cells whose column index is unchanged have no transform. */ export declare const SimpleThreeByThreeCenterToRightSwap: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Regression test: HEADER cells must FLIP-animate during a column reorder * the same way body cells do. Header cells live in their own per-section * tracking registry (separate WeakMap from body cells) and used to be * invisible to the AnimationCoordinator, so on a reorder they would teleport * while the body cells underneath them slid into place. * * For each of five chained programmatic reorders the test: * 1. Snapshots every header cell's `style.left` BEFORE the update. * 2. Calls `table.update({ defaultHeaders })` then synchronously reads * the FLIP "First" frame transform on every header. * 3. Asserts the inverse `transform-X` equals `oldLeft − newLeft` (±1.5px), * that headers whose index didn't change have no transform, and that * swapped headers carry opposite-sign transforms (one slid left, one * slid right). * 4. After SETTLE_PAUSE asserts no leftover transforms or transitions * remain on any header cell. */ export declare const HeaderCellsAnimateOnColumnReorder: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Drag-and-drop variant of {@link HeaderCellsAnimateOnColumnReorder}. The * regression we're guarding against is a setup where body cells animate on * every dragover but header cells teleport because the AnimationCoordinator * has never been told about the header containers. */ export declare const HeaderCellsAnimateDuringDragReorder: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Regression test: while a drag-reorder swap is animating, dragover events * targeting the still-animating cells must NOT keep firing additional * swaps. Previously, the moving header would slide back under the user's * cursor, the browser would re-fire dragover on it, and the column order * would oscillate visibly (a fast back-and-forth flicker). * * The fix: in-flight cells get `pointer-events: none` so the browser's * hit-testing skips them. dispatchEvent bypasses hit-testing, so this test * resolves the cursor's target via `document.elementFromPoint` (which DOES * honor pointer-events: none) — i.e. simulates what the browser would do. * * Asserts: * 1. Headers that move have `pointer-events: none` while in flight. * 2. The unchanged header keeps default pointer-events. * 3. After many dragover events sustained at the same screen point during * the animation, the column order does NOT oscillate (at most one swap * from the starting state, never the original-→-swapped-→-original * ping-pong the regression produced). * 4. After the animation settles, pointer-events on the previously-moving * headers is restored to default. */ export declare const HeaderDragDoesNotFlickerDuringAnimation: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; export declare const ReorderWithoutAnimations: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; export declare const SortAnimationDemo: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; export declare const AnimationsPropWiring: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Cells should animate from THEIR PREVIOUS position, not all from the same * direction. This story snapshots every cell's pre-reorder geometry and then * verifies, mid-flight, that: * * 1. Cells that move RIGHT (new left > old left) start with a NEGATIVE * transform-X (so they appear at their previous-left and slide rightward). * 2. Cells that move LEFT (new left < old left) start with a POSITIVE * transform-X (so they appear at their previous-right and slide leftward). * 3. Both directions appear in the same animation tick — no "everyone slides * from the same edge" regression. * 4. The translate-X delta for each cell exactly equals (oldLeft - newLeft), * so the FLIP "First" frame really lands at the previous on-screen pixel * position rather than at some shared anchor. */ export declare const ReorderAnimatesFromPreviousPositionPerCell: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Off-screen rows still slide. When the viewport only renders a slice of * all rows, sorting causes some cells to enter the visible band (rows that * were below the fold pre-sort) and others to leave it (rows that were on * screen pre-sort). The coordinator captures positions for ALL rows in the * dataset, so: * * - Incoming cells get created at their new (visible) position and FLIP * in from their actual pre-change off-screen `top`. Visually the cell * appears to slide in from the viewport edge. * - Outgoing cells get retained at their pre-change visible position and * slide to their actual post-change off-screen `top`, then are removed. * Visually the cell appears to slide out past the viewport edge. * * Both kinds of slides use `transform: translate3d` (no opacity). */ export declare const SortSlidesRowsCrossingTheViewportBoundary: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; }; /** * Drag-and-drop column reorder must FLIP-animate the displaced body cells * (and header cells) on EVERY `dragover` swap — not just on the final * `dragend`. Visually: while the user drags column B sideways, column C * should glide left to make room as soon as B's center crosses C's center, * the same way a programmatic `table.update({ defaultHeaders })` swap * animates. * * How the host pulls this off: * - The drag handler (`headerCell/dragging.ts`) calls * `context.onTableHeaderDragEnd(newHeaders)` from inside `dragover` once * the cursor has moved enough to trigger a swap. That callback resolves * to `setHeaders(newHeaders)` + `onRender()`. * - `setHeaders` first calls `captureAnimationSnapshot()` (no live-drag * skip), then mutates the headers. The next render commits cells to * their new absolute positions. * - `render()`'s final `play()` consumes the snapshot, computes the * pre→post deltas, and FLIPs every cell that moved — including the one * in the column the user is dragging. * * This test renders a 3 cols × 3 rows table and dispatches the drag * sequence inline so it can poll the cells between `dragover` events and * assert that a FLIP transform or `transition: transform` was observed * BEFORE `dragend` ever fires. Asserting only "saw FLIP within N ms * after dragend" wouldn't distinguish the desired behaviour from a * single settle animation that runs only on drop. */ export declare const DragAndDropColumnReorderShouldAnimate: { render: () => HTMLDivElement & { _table?: SimpleTableVanilla | undefined; }; play: ({ canvasElement }: { canvasElement: HTMLElement; }) => Promise; };