simple-table-core 3.0.13 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/src/core/SimpleTableVanilla.d.ts +25 -0
- package/dist/cjs/src/core/rendering/RenderOrchestrator.d.ts +4 -0
- package/dist/cjs/src/core/rendering/SectionRenderer.d.ts +35 -0
- package/dist/cjs/src/core/rendering/TableRenderer.d.ts +4 -0
- package/dist/cjs/src/index.d.ts +2 -1
- package/dist/cjs/src/managers/AnimationCoordinator.d.ts +142 -0
- package/dist/cjs/src/types/AnimationsConfig.d.ts +14 -0
- package/dist/cjs/src/types/SimpleTableConfig.d.ts +2 -0
- package/dist/cjs/src/types/SimpleTableProps.d.ts +2 -0
- package/dist/cjs/src/types/TableRow.d.ts +9 -0
- package/dist/cjs/src/utils/bodyCell/types.d.ts +6 -0
- package/dist/cjs/src/utils/bodyCellRenderer.d.ts +2 -1
- package/dist/cjs/src/utils/headerCell/styling.d.ts +2 -0
- package/dist/cjs/src/utils/rowUtils.d.ts +25 -0
- package/dist/cjs/stories/examples/BasicExample.d.ts +1 -0
- package/dist/cjs/stories/examples/sales-example/SalesExample.d.ts +3 -0
- package/dist/cjs/stories/tests/32-ThemesTests.stories.d.ts +19 -0
- package/dist/cjs/stories/tests/41-CellAnimationsTests.stories.d.ts +237 -0
- package/dist/cjs/stories/tests/42-CellAnimationsVirtualizationTests.stories.d.ts +251 -0
- package/dist/cjs/styles.css +1 -1
- package/dist/index.es.js +1 -1
- package/dist/src/core/SimpleTableVanilla.d.ts +25 -0
- package/dist/src/core/rendering/RenderOrchestrator.d.ts +4 -0
- package/dist/src/core/rendering/SectionRenderer.d.ts +35 -0
- package/dist/src/core/rendering/TableRenderer.d.ts +4 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/managers/AnimationCoordinator.d.ts +142 -0
- package/dist/src/types/AnimationsConfig.d.ts +14 -0
- package/dist/src/types/SimpleTableConfig.d.ts +2 -0
- package/dist/src/types/SimpleTableProps.d.ts +2 -0
- package/dist/src/types/TableRow.d.ts +9 -0
- package/dist/src/utils/bodyCell/types.d.ts +6 -0
- package/dist/src/utils/bodyCellRenderer.d.ts +2 -1
- package/dist/src/utils/headerCell/styling.d.ts +2 -0
- package/dist/src/utils/rowUtils.d.ts +25 -0
- package/dist/stories/examples/BasicExample.d.ts +1 -0
- package/dist/stories/examples/sales-example/SalesExample.d.ts +3 -0
- package/dist/stories/tests/32-ThemesTests.stories.d.ts +19 -0
- package/dist/stories/tests/41-CellAnimationsTests.stories.d.ts +237 -0
- package/dist/stories/tests/42-CellAnimationsVirtualizationTests.stories.d.ts +251 -0
- package/dist/styles.css +1 -1
- package/package.json +27 -3
- package/src/styles/base.css +15 -0
- package/src/styles/themes/frost.css +3 -2
- package/src/styles/themes/modern-dark.css +3 -2
- package/src/styles/themes/modern-light.css +4 -3
- package/src/styles/themes/theme-custom.css +4 -3
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CELL ANIMATIONS TESTS
|
|
3
|
+
*
|
|
4
|
+
* Covers FLIP-style animations on:
|
|
5
|
+
* - Programmatic column reorder via the API (cells shift `left`).
|
|
6
|
+
* - Sort change (rows shift `top`) when `getRowId` is provided so cell
|
|
7
|
+
* identity is row-stable.
|
|
8
|
+
*
|
|
9
|
+
* Cells that newly enter the visible band slide in from their actual pre-
|
|
10
|
+
* change off-screen position; cells that leave the visible band slide out
|
|
11
|
+
* to their actual post-change off-screen position. The body container's
|
|
12
|
+
* overflow clip turns those long off-screen translates into "appears to
|
|
13
|
+
* slide in from the viewport edge" visually.
|
|
14
|
+
*
|
|
15
|
+
* Animations default to `true`. Live drag reorder is intentionally not
|
|
16
|
+
* animated (we don't want to fight the user's pointer mid-drag).
|
|
17
|
+
*/
|
|
18
|
+
import { SimpleTableVanilla } from "../../src/index";
|
|
19
|
+
import type { Meta } from "@storybook/html";
|
|
20
|
+
declare const meta: Meta;
|
|
21
|
+
export default meta;
|
|
22
|
+
export declare const ProgrammaticReorderAnimation: {
|
|
23
|
+
render: () => HTMLDivElement & {
|
|
24
|
+
_table?: SimpleTableVanilla | undefined;
|
|
25
|
+
};
|
|
26
|
+
play: ({ canvasElement }: {
|
|
27
|
+
canvasElement: HTMLElement;
|
|
28
|
+
}) => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Simplest possible reorder animation test: a 3 columns × 3 rows table.
|
|
32
|
+
*
|
|
33
|
+
* Step 1 is the straightforward case — move the center column (B) to the
|
|
34
|
+
* rightmost position by swapping B and C via
|
|
35
|
+
* `table.update({ defaultHeaders: [...] })`. After that animation settles,
|
|
36
|
+
* the play function chains four more reorders (5 total) so we exercise:
|
|
37
|
+
*
|
|
38
|
+
* - Pairwise neighbour swaps (B↔C, A↔B).
|
|
39
|
+
* - Long-distance swaps (first ↔ last column).
|
|
40
|
+
* - A "rotate back to original" reset.
|
|
41
|
+
*
|
|
42
|
+
* For every step we synchronously read the FLIP "First" frame and assert
|
|
43
|
+
* that each cell's inverse `transform-X` exactly matches `oldLeft − newLeft`
|
|
44
|
+
* (≤ 1.5px tolerance), then wait past `SLOW_DURATION` and assert no leftover
|
|
45
|
+
* transforms and no retained ghosts before moving on to the next step.
|
|
46
|
+
*
|
|
47
|
+
* Expected FLIP behaviour for each reorder:
|
|
48
|
+
* - Cells whose `left` increases slide RIGHT, so their inverse transform-X
|
|
49
|
+
* is NEGATIVE (`oldLeft − newLeft < 0`).
|
|
50
|
+
* - Cells whose `left` decreases slide LEFT, so their inverse transform-X
|
|
51
|
+
* is POSITIVE (`oldLeft − newLeft > 0`).
|
|
52
|
+
* - Cells whose column index is unchanged have no transform.
|
|
53
|
+
*/
|
|
54
|
+
export declare const SimpleThreeByThreeCenterToRightSwap: {
|
|
55
|
+
render: () => HTMLDivElement & {
|
|
56
|
+
_table?: SimpleTableVanilla | undefined;
|
|
57
|
+
};
|
|
58
|
+
play: ({ canvasElement }: {
|
|
59
|
+
canvasElement: HTMLElement;
|
|
60
|
+
}) => Promise<void>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Regression test: HEADER cells must FLIP-animate during a column reorder
|
|
64
|
+
* the same way body cells do. Header cells live in their own per-section
|
|
65
|
+
* tracking registry (separate WeakMap from body cells) and used to be
|
|
66
|
+
* invisible to the AnimationCoordinator, so on a reorder they would teleport
|
|
67
|
+
* while the body cells underneath them slid into place.
|
|
68
|
+
*
|
|
69
|
+
* For each of five chained programmatic reorders the test:
|
|
70
|
+
* 1. Snapshots every header cell's `style.left` BEFORE the update.
|
|
71
|
+
* 2. Calls `table.update({ defaultHeaders })` then synchronously reads
|
|
72
|
+
* the FLIP "First" frame transform on every header.
|
|
73
|
+
* 3. Asserts the inverse `transform-X` equals `oldLeft − newLeft` (±1.5px),
|
|
74
|
+
* that headers whose index didn't change have no transform, and that
|
|
75
|
+
* swapped headers carry opposite-sign transforms (one slid left, one
|
|
76
|
+
* slid right).
|
|
77
|
+
* 4. After SETTLE_PAUSE asserts no leftover transforms or transitions
|
|
78
|
+
* remain on any header cell.
|
|
79
|
+
*/
|
|
80
|
+
export declare const HeaderCellsAnimateOnColumnReorder: {
|
|
81
|
+
render: () => HTMLDivElement & {
|
|
82
|
+
_table?: SimpleTableVanilla | undefined;
|
|
83
|
+
};
|
|
84
|
+
play: ({ canvasElement }: {
|
|
85
|
+
canvasElement: HTMLElement;
|
|
86
|
+
}) => Promise<void>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Drag-and-drop variant of {@link HeaderCellsAnimateOnColumnReorder}. The
|
|
90
|
+
* regression we're guarding against is a setup where body cells animate on
|
|
91
|
+
* every dragover but header cells teleport because the AnimationCoordinator
|
|
92
|
+
* has never been told about the header containers.
|
|
93
|
+
*/
|
|
94
|
+
export declare const HeaderCellsAnimateDuringDragReorder: {
|
|
95
|
+
render: () => HTMLDivElement & {
|
|
96
|
+
_table?: SimpleTableVanilla | undefined;
|
|
97
|
+
};
|
|
98
|
+
play: ({ canvasElement }: {
|
|
99
|
+
canvasElement: HTMLElement;
|
|
100
|
+
}) => Promise<void>;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Regression test: while a drag-reorder swap is animating, dragover events
|
|
104
|
+
* targeting the still-animating cells must NOT keep firing additional
|
|
105
|
+
* swaps. Previously, the moving header would slide back under the user's
|
|
106
|
+
* cursor, the browser would re-fire dragover on it, and the column order
|
|
107
|
+
* would oscillate visibly (a fast back-and-forth flicker).
|
|
108
|
+
*
|
|
109
|
+
* The fix: in-flight cells get `pointer-events: none` so the browser's
|
|
110
|
+
* hit-testing skips them. dispatchEvent bypasses hit-testing, so this test
|
|
111
|
+
* resolves the cursor's target via `document.elementFromPoint` (which DOES
|
|
112
|
+
* honor pointer-events: none) — i.e. simulates what the browser would do.
|
|
113
|
+
*
|
|
114
|
+
* Asserts:
|
|
115
|
+
* 1. Headers that move have `pointer-events: none` while in flight.
|
|
116
|
+
* 2. The unchanged header keeps default pointer-events.
|
|
117
|
+
* 3. After many dragover events sustained at the same screen point during
|
|
118
|
+
* the animation, the column order does NOT oscillate (at most one swap
|
|
119
|
+
* from the starting state, never the original-→-swapped-→-original
|
|
120
|
+
* ping-pong the regression produced).
|
|
121
|
+
* 4. After the animation settles, pointer-events on the previously-moving
|
|
122
|
+
* headers is restored to default.
|
|
123
|
+
*/
|
|
124
|
+
export declare const HeaderDragDoesNotFlickerDuringAnimation: {
|
|
125
|
+
render: () => HTMLDivElement & {
|
|
126
|
+
_table?: SimpleTableVanilla | undefined;
|
|
127
|
+
};
|
|
128
|
+
play: ({ canvasElement }: {
|
|
129
|
+
canvasElement: HTMLElement;
|
|
130
|
+
}) => Promise<void>;
|
|
131
|
+
};
|
|
132
|
+
export declare const ReorderWithoutAnimations: {
|
|
133
|
+
render: () => HTMLDivElement & {
|
|
134
|
+
_table?: SimpleTableVanilla | undefined;
|
|
135
|
+
};
|
|
136
|
+
play: ({ canvasElement }: {
|
|
137
|
+
canvasElement: HTMLElement;
|
|
138
|
+
}) => Promise<void>;
|
|
139
|
+
};
|
|
140
|
+
export declare const SortAnimationDemo: {
|
|
141
|
+
render: () => HTMLDivElement & {
|
|
142
|
+
_table?: SimpleTableVanilla | undefined;
|
|
143
|
+
};
|
|
144
|
+
play: ({ canvasElement }: {
|
|
145
|
+
canvasElement: HTMLElement;
|
|
146
|
+
}) => Promise<void>;
|
|
147
|
+
};
|
|
148
|
+
export declare const AnimationsPropWiring: {
|
|
149
|
+
render: () => HTMLDivElement & {
|
|
150
|
+
_table?: SimpleTableVanilla | undefined;
|
|
151
|
+
};
|
|
152
|
+
play: ({ canvasElement }: {
|
|
153
|
+
canvasElement: HTMLElement;
|
|
154
|
+
}) => Promise<void>;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Cells should animate from THEIR PREVIOUS position, not all from the same
|
|
158
|
+
* direction. This story snapshots every cell's pre-reorder geometry and then
|
|
159
|
+
* verifies, mid-flight, that:
|
|
160
|
+
*
|
|
161
|
+
* 1. Cells that move RIGHT (new left > old left) start with a NEGATIVE
|
|
162
|
+
* transform-X (so they appear at their previous-left and slide rightward).
|
|
163
|
+
* 2. Cells that move LEFT (new left < old left) start with a POSITIVE
|
|
164
|
+
* transform-X (so they appear at their previous-right and slide leftward).
|
|
165
|
+
* 3. Both directions appear in the same animation tick — no "everyone slides
|
|
166
|
+
* from the same edge" regression.
|
|
167
|
+
* 4. The translate-X delta for each cell exactly equals (oldLeft - newLeft),
|
|
168
|
+
* so the FLIP "First" frame really lands at the previous on-screen pixel
|
|
169
|
+
* position rather than at some shared anchor.
|
|
170
|
+
*/
|
|
171
|
+
export declare const ReorderAnimatesFromPreviousPositionPerCell: {
|
|
172
|
+
render: () => HTMLDivElement & {
|
|
173
|
+
_table?: SimpleTableVanilla | undefined;
|
|
174
|
+
};
|
|
175
|
+
play: ({ canvasElement }: {
|
|
176
|
+
canvasElement: HTMLElement;
|
|
177
|
+
}) => Promise<void>;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Off-screen rows still slide. When the viewport only renders a slice of
|
|
181
|
+
* all rows, sorting causes some cells to enter the visible band (rows that
|
|
182
|
+
* were below the fold pre-sort) and others to leave it (rows that were on
|
|
183
|
+
* screen pre-sort). The coordinator captures positions for ALL rows in the
|
|
184
|
+
* dataset, so:
|
|
185
|
+
*
|
|
186
|
+
* - Incoming cells get created at their new (visible) position and FLIP
|
|
187
|
+
* in from their actual pre-change off-screen `top`. Visually the cell
|
|
188
|
+
* appears to slide in from the viewport edge.
|
|
189
|
+
* - Outgoing cells get retained at their pre-change visible position and
|
|
190
|
+
* slide to their actual post-change off-screen `top`, then are removed.
|
|
191
|
+
* Visually the cell appears to slide out past the viewport edge.
|
|
192
|
+
*
|
|
193
|
+
* Both kinds of slides use `transform: translate3d` (no opacity).
|
|
194
|
+
*/
|
|
195
|
+
export declare const SortSlidesRowsCrossingTheViewportBoundary: {
|
|
196
|
+
render: () => HTMLDivElement & {
|
|
197
|
+
_table?: SimpleTableVanilla | undefined;
|
|
198
|
+
};
|
|
199
|
+
play: ({ canvasElement }: {
|
|
200
|
+
canvasElement: HTMLElement;
|
|
201
|
+
}) => Promise<void>;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Drag-and-drop column reorder must FLIP-animate the displaced body cells
|
|
205
|
+
* (and header cells) on EVERY `dragover` swap — not just on the final
|
|
206
|
+
* `dragend`. Visually: while the user drags column B sideways, column C
|
|
207
|
+
* should glide left to make room as soon as B's center crosses C's center,
|
|
208
|
+
* the same way a programmatic `table.update({ defaultHeaders })` swap
|
|
209
|
+
* animates.
|
|
210
|
+
*
|
|
211
|
+
* How the host pulls this off:
|
|
212
|
+
* - The drag handler (`headerCell/dragging.ts`) calls
|
|
213
|
+
* `context.onTableHeaderDragEnd(newHeaders)` from inside `dragover` once
|
|
214
|
+
* the cursor has moved enough to trigger a swap. That callback resolves
|
|
215
|
+
* to `setHeaders(newHeaders)` + `onRender()`.
|
|
216
|
+
* - `setHeaders` first calls `captureAnimationSnapshot()` (no live-drag
|
|
217
|
+
* skip), then mutates the headers. The next render commits cells to
|
|
218
|
+
* their new absolute positions.
|
|
219
|
+
* - `render()`'s final `play()` consumes the snapshot, computes the
|
|
220
|
+
* pre→post deltas, and FLIPs every cell that moved — including the one
|
|
221
|
+
* in the column the user is dragging.
|
|
222
|
+
*
|
|
223
|
+
* This test renders a 3 cols × 3 rows table and dispatches the drag
|
|
224
|
+
* sequence inline so it can poll the cells between `dragover` events and
|
|
225
|
+
* assert that a FLIP transform or `transition: transform` was observed
|
|
226
|
+
* BEFORE `dragend` ever fires. Asserting only "saw FLIP within N ms
|
|
227
|
+
* after dragend" wouldn't distinguish the desired behaviour from a
|
|
228
|
+
* single settle animation that runs only on drop.
|
|
229
|
+
*/
|
|
230
|
+
export declare const DragAndDropColumnReorderShouldAnimate: {
|
|
231
|
+
render: () => HTMLDivElement & {
|
|
232
|
+
_table?: SimpleTableVanilla | undefined;
|
|
233
|
+
};
|
|
234
|
+
play: ({ canvasElement }: {
|
|
235
|
+
canvasElement: HTMLElement;
|
|
236
|
+
}) => Promise<void>;
|
|
237
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CELL ANIMATIONS — VIRTUALIZATION & SCALE TESTS (slow & visible)
|
|
3
|
+
*
|
|
4
|
+
* Stress-tests the FLIP animation coordinator at scale (500 rows × 30 cols
|
|
5
|
+
* in a constrained viewport) with `animations.duration` cranked up so the
|
|
6
|
+
* play function is *visible* when watched in Storybook. Each play function
|
|
7
|
+
* runs many sequential interactions with explicit pauses between them so
|
|
8
|
+
* you can see each animation phase fire.
|
|
9
|
+
*
|
|
10
|
+
* Slides apply both within and across the visible band:
|
|
11
|
+
* - Persistent cells (visible before AND after) slide from old → new.
|
|
12
|
+
* - Incoming cells (off-screen before, in DOM after) FLIP in from their
|
|
13
|
+
* true pre-change off-screen position, clipped by the body's overflow.
|
|
14
|
+
* - Outgoing cells (in DOM before, off-screen after) are retained as
|
|
15
|
+
* `data-animating-out` ghosts and slide to their true post-change
|
|
16
|
+
* off-screen position before being removed — visually they appear to
|
|
17
|
+
* slide out past the viewport edge.
|
|
18
|
+
*
|
|
19
|
+
* Animate-out into virtualized space is regression-tested in four flavours:
|
|
20
|
+
* 1. Vertical / downward (sort col_0 desc at scrollTop=0): top-band rows
|
|
21
|
+
* sort to the bottom of the table → ghosts slide DOWN past bottom edge.
|
|
22
|
+
* → {@link SortRetainsCellsThatExitVirtualizedBand}
|
|
23
|
+
* 2. Vertical / upward (sort col_0 desc while scrolled to bottom): visible
|
|
24
|
+
* bottom-band rows sort to the top of the table → ghosts slide UP past
|
|
25
|
+
* top edge.
|
|
26
|
+
* → {@link SortRetainsCellsThatExitUpwardWhenScrolled}
|
|
27
|
+
* 3. Vertical / re-aim mid-flight (rapid double sort): cells already
|
|
28
|
+
* animating out from a first sort must be re-aimed by a second sort
|
|
29
|
+
* that fires before the first finishes, with all ghosts torn down once
|
|
30
|
+
* everything settles.
|
|
31
|
+
* → {@link OverlappingSortsRetainAndReaimGhosts}
|
|
32
|
+
* 4. Horizontal / leftward (column reverse at right-most scrollLeft):
|
|
33
|
+
* visible right-side cells reorder to the left side of the table → if
|
|
34
|
+
* the new `left` is outside `getVisibleBodyCells`'s post-reorder band,
|
|
35
|
+
* the cells are retained as ghosts that slide LEFT past the viewport
|
|
36
|
+
* edge.
|
|
37
|
+
* → {@link ReorderAfterHorizontalScrollRetainsExitingCellsAsGhosts}
|
|
38
|
+
*
|
|
39
|
+
* Why horizontal animate-out only manifests under horizontal scroll: at
|
|
40
|
+
* scrollLeft=0, `getVisibleBodyCells` keeps every non-pinned cell in the
|
|
41
|
+
* DOM (the visible band's right edge equals scrollLeft + mainWidth, which
|
|
42
|
+
* is the full content width), so column reorder never *removes* a cell —
|
|
43
|
+
* the same DOM node persists and slides to its new `left` via FLIP, with
|
|
44
|
+
* the body's overflow clipping the off-screen portion. Once scrollLeft > 0
|
|
45
|
+
* the band shifts and reorders can push cells outside it; that's when the
|
|
46
|
+
* outgoing ghost path kicks in horizontally as well.
|
|
47
|
+
*/
|
|
48
|
+
import type { Meta } from "@storybook/html";
|
|
49
|
+
declare const meta: Meta;
|
|
50
|
+
export default meta;
|
|
51
|
+
/**
|
|
52
|
+
* Large-scale reorder round-trip: reverse → reset on a 30-col × 500-row
|
|
53
|
+
* table, asserting that >50 cells are mid-flight after each step and that
|
|
54
|
+
* everything settles cleanly with no leftover ghosts.
|
|
55
|
+
*
|
|
56
|
+
* Strict per-cell FLIP transform-X correctness on a contained neighbour
|
|
57
|
+
* swap is covered by `ContainedNeighborSwapAnimation` (immediately below)
|
|
58
|
+
* on the same constrained table, so we don't repeat it here.
|
|
59
|
+
*/
|
|
60
|
+
export declare const SlowColumnReorderMarathon: {
|
|
61
|
+
render: () => HTMLElement;
|
|
62
|
+
play: ({ canvasElement }: {
|
|
63
|
+
canvasElement: HTMLElement;
|
|
64
|
+
}) => Promise<void>;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Visually obvious "two cells trading places" demo. Uses neighbour columns
|
|
68
|
+
* that are both fully inside the viewport (so the FLIP motion is contained
|
|
69
|
+
* on-screen, no off-screen sweeps). The play function:
|
|
70
|
+
*
|
|
71
|
+
* 1. Captures both cells' pre-swap left positions.
|
|
72
|
+
* 2. Calls `table.update({ defaultHeaders: swapped })`.
|
|
73
|
+
* 3. Synchronously asserts each cell's FLIP transform-X equals
|
|
74
|
+
* (oldLeft - newLeft) — i.e. cell A starts where B was, cell B starts
|
|
75
|
+
* where A was, and they slide toward each other in opposite directions.
|
|
76
|
+
*
|
|
77
|
+
* If a future change causes cells to animate from a single shared anchor
|
|
78
|
+
* (e.g. the right edge), this story fails immediately.
|
|
79
|
+
*/
|
|
80
|
+
export declare const ContainedNeighborSwapAnimation: {
|
|
81
|
+
render: () => HTMLElement;
|
|
82
|
+
play: ({ canvasElement }: {
|
|
83
|
+
canvasElement: HTMLElement;
|
|
84
|
+
}) => Promise<void>;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Vertical scroll → reorder → vertical scroll → reorder, demonstrating that
|
|
88
|
+
* the snapshot reflects the *currently visible* row band each time.
|
|
89
|
+
*/
|
|
90
|
+
export declare const ReorderAtMultipleScrollPositions: {
|
|
91
|
+
render: () => HTMLElement;
|
|
92
|
+
play: ({ canvasElement }: {
|
|
93
|
+
canvasElement: HTMLElement;
|
|
94
|
+
}) => Promise<void>;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Per-cell FLIP correctness check at scale.
|
|
98
|
+
*
|
|
99
|
+
* When reversing 30 columns:
|
|
100
|
+
* - Cells whose pre-reverse position is currently on-screen (or whose true
|
|
101
|
+
* journey fits within ~one viewport) must FLIP exactly to that position
|
|
102
|
+
* (`txX === oldLeft - newLeft` to within sub-pixel rounding).
|
|
103
|
+
* - Cells whose pre-reverse position is far off-screen are scaled by
|
|
104
|
+
* `AnimationCoordinator.scaleFlipDistance` so the visible slide stays
|
|
105
|
+
* bounded. For those, we relax the strict equality to: same sign as the
|
|
106
|
+
* true journey, magnitude < the true journey, and magnitude inside the
|
|
107
|
+
* `[viewport, ~2 × viewport]` band the scaler produces.
|
|
108
|
+
*
|
|
109
|
+
* Catches regressions where the snapshot is captured against the post-
|
|
110
|
+
* mutation layout, where preLayouts overwrites live DOM positions, where
|
|
111
|
+
* some cells get skipped from the FLIP pass, or where horizontal scaling
|
|
112
|
+
* collapses the journey too aggressively (e.g. dropping it to 0).
|
|
113
|
+
*/
|
|
114
|
+
export declare const ReorderAtScaleAnimatesFromPreviousPositionPerCell: {
|
|
115
|
+
render: () => HTMLElement;
|
|
116
|
+
play: ({ canvasElement }: {
|
|
117
|
+
canvasElement: HTMLElement;
|
|
118
|
+
}) => Promise<void>;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Sort cleanup at scale. Verifies that after a sort animation settles on a
|
|
122
|
+
* 500-row × 30-col table, every retained ghost is torn down and no cell is
|
|
123
|
+
* left with a stuck transform or transition.
|
|
124
|
+
*
|
|
125
|
+
* Per-sort FLIP correctness, ghost retention, mid-flight re-aim, and the
|
|
126
|
+
* upward / horizontal exit cases each have their own focused regression
|
|
127
|
+
* tests below — this one only proves cleanup holds at scale across a
|
|
128
|
+
* round-trip (sort → clear).
|
|
129
|
+
*/
|
|
130
|
+
export declare const SortMarathon: {
|
|
131
|
+
render: () => HTMLElement;
|
|
132
|
+
play: ({ canvasElement }: {
|
|
133
|
+
canvasElement: HTMLElement;
|
|
134
|
+
}) => Promise<void>;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* REGRESSION TEST FOR ANIMATE-OUT INTO VIRTUALIZED SPACE.
|
|
138
|
+
*
|
|
139
|
+
* When a sort moves a *currently visible* row to a position that's outside
|
|
140
|
+
* the visible band (e.g. row at position 0 sorts to position 499 in a 500
|
|
141
|
+
* row table), the cell for that row should NOT be removed from the DOM
|
|
142
|
+
* immediately. Instead the renderer should hand it to the animation
|
|
143
|
+
* coordinator as a retained "ghost" that:
|
|
144
|
+
*
|
|
145
|
+
* 1. Stays in the DOM with `data-animating-out="true"`.
|
|
146
|
+
* 2. Has its `style.top` updated to its new (off-screen) position.
|
|
147
|
+
* 3. Plays a FLIP slide from its old (on-screen) position to that new
|
|
148
|
+
* off-screen position. The body's `overflow: hidden` clips the part
|
|
149
|
+
* that crosses the viewport edge, so it visually appears to slide
|
|
150
|
+
* out past the bottom edge.
|
|
151
|
+
* 4. Is removed from the DOM only after the slide completes.
|
|
152
|
+
*
|
|
153
|
+
* If the cell is dropped immediately, the user sees it pop out of existence
|
|
154
|
+
* in place — a visible jank during sort.
|
|
155
|
+
*
|
|
156
|
+
* The test grabs any cell in the top-most visible row, records its on-screen
|
|
157
|
+
* rect, triggers a sort that pushes it far off-screen, and then samples
|
|
158
|
+
* shortly after — well before the long animation could finish. With a
|
|
159
|
+
* working slide-out, the cell is still in the DOM and visually only a small
|
|
160
|
+
* fraction of the way to its new position. With a broken slide-out, the
|
|
161
|
+
* cell is either missing from the DOM (removed instantly) or already at its
|
|
162
|
+
* far-off-screen target (snapped). After the animation settles we also
|
|
163
|
+
* confirm the ghost was cleaned up.
|
|
164
|
+
*/
|
|
165
|
+
export declare const SortRetainsCellsThatExitVirtualizedBand: {
|
|
166
|
+
tags: string[];
|
|
167
|
+
render: () => HTMLElement;
|
|
168
|
+
play: ({ canvasElement }: {
|
|
169
|
+
canvasElement: HTMLElement;
|
|
170
|
+
}) => Promise<void>;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* REGRESSION TEST FOR ANIMATE-OUT WHEN SCROLLED — UP DIRECTION.
|
|
174
|
+
*
|
|
175
|
+
* Companion to {@link SortRetainsCellsThatExitVirtualizedBand} that exercises
|
|
176
|
+
* cells exiting via the *top* of the viewport rather than the bottom.
|
|
177
|
+
*
|
|
178
|
+
* If you scroll mid-way through the table and then sort, rows that are
|
|
179
|
+
* currently visible can be sorted to a position ABOVE the visible band (i.e.
|
|
180
|
+
* a small `top` value while the scroller is at a large `scrollTop`). The
|
|
181
|
+
* cells representing those rows must still be retained as ghosts and slide
|
|
182
|
+
* UPWARD past the top edge — not pop out in place.
|
|
183
|
+
*
|
|
184
|
+
* Concretely: scroll to the bottom of the table (rows ~485–499 visible),
|
|
185
|
+
* then sort `col_0 desc` (descending by col_0 value, where row-0 has the
|
|
186
|
+
* lowest value). The currently-visible rows have HIGH col_0 values, so on
|
|
187
|
+
* desc they sort to the TOP of the table (small `top`). Their old visual
|
|
188
|
+
* position was below the viewport edge of the scroller; their new visual
|
|
189
|
+
* position is above it. They must be retained and slide upward, with an
|
|
190
|
+
* inverse FLIP `transform` whose Y component is positive (= old.top -
|
|
191
|
+
* new.top, where old > new ⇒ tx_y > 0).
|
|
192
|
+
*/
|
|
193
|
+
export declare const SortRetainsCellsThatExitUpwardWhenScrolled: {
|
|
194
|
+
tags: string[];
|
|
195
|
+
render: () => HTMLElement;
|
|
196
|
+
play: ({ canvasElement }: {
|
|
197
|
+
canvasElement: HTMLElement;
|
|
198
|
+
}) => Promise<void>;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* REGRESSION TEST FOR ANIMATE-OUT WHEN SORTS OVERLAP.
|
|
202
|
+
*
|
|
203
|
+
* If the user clicks a sort header twice in rapid succession (toggling the
|
|
204
|
+
* direction before the previous animation finishes), the second sort's
|
|
205
|
+
* snapshot fires while the first sort's retained ghosts are still mid-flight.
|
|
206
|
+
* Those mid-flight ghosts are themselves "currently visible" cells (as far
|
|
207
|
+
* as the user is concerned) and should also be retained / re-aimed for the
|
|
208
|
+
* second sort — not orphaned in place at the wrong position.
|
|
209
|
+
*
|
|
210
|
+
* The test:
|
|
211
|
+
* 1. Sorts col_0 desc — capturing the wave of bottom-bound ghosts.
|
|
212
|
+
* 2. Half-way through the slide, sorts col_0 asc — which should send
|
|
213
|
+
* everything back the other way.
|
|
214
|
+
* 3. Verifies the active cells (now sorting back ascending) still get a
|
|
215
|
+
* FLIP transform (i.e. they slide rather than snap), and that all
|
|
216
|
+
* ghosts are torn down once both animations settle.
|
|
217
|
+
*/
|
|
218
|
+
export declare const OverlappingSortsRetainAndReaimGhosts: {
|
|
219
|
+
tags: string[];
|
|
220
|
+
render: () => HTMLElement;
|
|
221
|
+
play: ({ canvasElement }: {
|
|
222
|
+
canvasElement: HTMLElement;
|
|
223
|
+
}) => Promise<void>;
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* REGRESSION TEST FOR HORIZONTAL ANIMATE-OUT WHEN HORIZONTALLY SCROLLED.
|
|
227
|
+
*
|
|
228
|
+
* When the user has scrolled the body horizontally so that left-side
|
|
229
|
+
* columns are outside the rendered cell band, then performs a column
|
|
230
|
+
* reorder that pushes the *currently visible* right-side columns to the
|
|
231
|
+
* left side, those right-side cells exit the band horizontally and need
|
|
232
|
+
* to be retained as ghosts that slide LEFT past the viewport edge — not
|
|
233
|
+
* popped out of existence in place.
|
|
234
|
+
*
|
|
235
|
+
* Concretely:
|
|
236
|
+
* 1. Scroll the body container all the way to the right (rightmost
|
|
237
|
+
* columns visible, leftmost columns out of band).
|
|
238
|
+
* 2. Reverse all 31 columns. The cells that were on-screen on the right
|
|
239
|
+
* now belong on the left side of the table — outside the band that
|
|
240
|
+
* `getVisibleBodyCells` keeps in the DOM at the new scroll position.
|
|
241
|
+
* 3. Verify those cells are retained as `data-animating-out` ghosts at
|
|
242
|
+
* their new (off-screen-left) `style.left`, with an inverse FLIP X
|
|
243
|
+
* transform so they visually start at their old on-screen `left`.
|
|
244
|
+
*/
|
|
245
|
+
export declare const ReorderAfterHorizontalScrollRetainsExitingCellsAsGhosts: {
|
|
246
|
+
tags: string[];
|
|
247
|
+
render: () => HTMLElement;
|
|
248
|
+
play: ({ canvasElement }: {
|
|
249
|
+
canvasElement: HTMLElement;
|
|
250
|
+
}) => Promise<void>;
|
|
251
|
+
};
|