simple-table-core 3.4.1 → 3.5.2

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.
Files changed (44) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/src/core/SimpleTableVanilla.d.ts +55 -0
  3. package/dist/cjs/src/core/rendering/RenderOrchestrator.d.ts +9 -0
  4. package/dist/cjs/src/core/rendering/TableRenderer.d.ts +4 -1
  5. package/dist/cjs/src/managers/AnimationCoordinator.d.ts +64 -0
  6. package/dist/cjs/src/types/TableRow.d.ts +6 -5
  7. package/dist/cjs/src/utils/accordionAnimation.d.ts +25 -0
  8. package/dist/cjs/src/utils/bodyCell/styling.d.ts +7 -0
  9. package/dist/cjs/src/utils/bodyCell/types.d.ts +11 -0
  10. package/dist/cjs/src/utils/headerCell/types.d.ts +18 -0
  11. package/dist/cjs/src/utils/rowUtils.d.ts +21 -2
  12. package/dist/cjs/src/utils/stickyParentsRenderer.d.ts +14 -0
  13. package/dist/cjs/stories/examples/BasicRowGrouping.d.ts +4 -0
  14. package/dist/cjs/stories/examples/CollapsibleColumnsExample.d.ts +4 -0
  15. package/dist/cjs/stories/examples/DynamicNestedTableExample.d.ts +2 -0
  16. package/dist/cjs/stories/examples/pinned-columns/PinnedColumns.d.ts +2 -0
  17. package/dist/cjs/stories/tests/17-NestedTablesTests.stories.d.ts +64 -6
  18. package/dist/cjs/stories/tests/43-CollapseExpandAnimationsTests.stories.d.ts +63 -0
  19. package/dist/cjs/stories/tests/testUtils.d.ts +5 -0
  20. package/dist/cjs/styles.css +1 -1
  21. package/dist/index.es.js +1 -1
  22. package/dist/src/core/SimpleTableVanilla.d.ts +55 -0
  23. package/dist/src/core/rendering/RenderOrchestrator.d.ts +9 -0
  24. package/dist/src/core/rendering/TableRenderer.d.ts +4 -1
  25. package/dist/src/managers/AnimationCoordinator.d.ts +64 -0
  26. package/dist/src/types/TableRow.d.ts +6 -5
  27. package/dist/src/utils/accordionAnimation.d.ts +25 -0
  28. package/dist/src/utils/bodyCell/styling.d.ts +7 -0
  29. package/dist/src/utils/bodyCell/types.d.ts +11 -0
  30. package/dist/src/utils/headerCell/types.d.ts +18 -0
  31. package/dist/src/utils/rowUtils.d.ts +21 -2
  32. package/dist/src/utils/stickyParentsRenderer.d.ts +14 -0
  33. package/dist/stories/examples/BasicRowGrouping.d.ts +4 -0
  34. package/dist/stories/examples/CollapsibleColumnsExample.d.ts +4 -0
  35. package/dist/stories/examples/DynamicNestedTableExample.d.ts +2 -0
  36. package/dist/stories/examples/pinned-columns/PinnedColumns.d.ts +2 -0
  37. package/dist/stories/tests/17-NestedTablesTests.stories.d.ts +64 -6
  38. package/dist/stories/tests/43-CollapseExpandAnimationsTests.stories.d.ts +63 -0
  39. package/dist/stories/tests/testUtils.d.ts +5 -0
  40. package/dist/styles.css +1 -1
  41. package/package.json +1 -1
  42. package/src/styles/base.css +99 -48
  43. package/src/styles/themes/modern-light.css +12 -12
  44. package/src/styles/themes/theme-custom.css +2 -2
@@ -54,6 +54,26 @@ export declare class SimpleTableVanilla {
54
54
  private scrollEndTimeoutId;
55
55
  private lastScrollTop;
56
56
  private isUpdating;
57
+ /**
58
+ * Active accordion axis for the next render. Set by row/column collapse-
59
+ * expand mutators (see {@link beginAccordionAnimation}) and consumed by the
60
+ * cell renderers via the render context. Cleared in {@link render} after
61
+ * each render so subsequent non-accordion renders (sort, scroll, etc.)
62
+ * don't re-trigger the size transitions.
63
+ */
64
+ private pendingAccordionAxis;
65
+ /** Pending timeout id used to remove the accordion CSS class. */
66
+ private accordionCleanupTimerId;
67
+ /**
68
+ * Visible-leaf-headers key as of the last render that committed to the DOM.
69
+ * Used by `setHeaders` to detect hide/show/pin/unpin and trigger the
70
+ * accordion-horizontal animation. Comparing against `this.headers` directly
71
+ * doesn't work because the column editor mutates header objects in place
72
+ * (e.g. `header.hide = true`) BEFORE invoking setHeaders, so by the time
73
+ * setHeaders runs, the prev and next trees already point to the same
74
+ * mutated header instances.
75
+ */
76
+ private lastRenderedVisibilityKey;
57
77
  constructor(container: HTMLElement, config: SimpleTableConfig);
58
78
  private applyAnimationsConfig;
59
79
  private rebuildRowIndexMap;
@@ -79,7 +99,42 @@ export declare class SimpleTableVanilla {
79
99
  * displaced columns slide smoothly out of the dragged column's way rather
80
100
  * than snapping into place.
81
101
  */
102
+ /**
103
+ * Build a key summarizing the leaf columns that will paint (accessor +
104
+ * pinned section). Hidden leaves and excluded subtrees drop out; nested
105
+ * children are flattened so a parent collapse/expand counts as a
106
+ * visibility change at the leaf level too.
107
+ */
108
+ private buildVisibilityKey;
109
+ /**
110
+ * True when the visible-leaf-set (or its pinned-section assignment) for
111
+ * `nextHeaders` differs from the last render that committed to the DOM.
112
+ *
113
+ * We deliberately compare against {@link lastRenderedVisibilityKey} rather
114
+ * than `this.headers`: the column editor mutates header objects in place
115
+ * before invoking setHeaders (e.g. `header.hide = true`, then
116
+ * `setHeaders(deepClone(headers))`), and `this.headers` shares those
117
+ * mutated references — so a prev-vs-next compare always reads the same
118
+ * state and reports no change. Comparing to the last-rendered key sees
119
+ * the user's actually-painted state and correctly detects hide/show and
120
+ * pin/unpin changes.
121
+ */
122
+ private didColumnVisibilityChange;
82
123
  private captureAnimationSnapshot;
124
+ /**
125
+ * Open the accordion animation window for the next render: capture a FLIP
126
+ * snapshot, mark the active axis so cell renderers initialize incoming
127
+ * cells at zero size, and add the CSS class that enables the size
128
+ * transitions on `.st-cell` / `.st-header-cell`.
129
+ *
130
+ * The CSS class is removed after `duration + ACCORDION_CLEANUP_BUFFER_MS`
131
+ * so non-accordion renders don't keep transitioning size on subsequent
132
+ * inline-style writes.
133
+ *
134
+ * No-op when animations are disabled (which already includes the
135
+ * prefers-reduced-motion check via {@link AnimationCoordinator.isEnabled}).
136
+ */
137
+ private beginAccordionAnimation;
83
138
  private initializeManagers;
84
139
  mount(): void;
85
140
  private setupManagers;
@@ -11,10 +11,19 @@ import { FilterManager } from "../../managers/FilterManager";
11
11
  import { SelectionManager } from "../../managers/SelectionManager";
12
12
  import { RowSelectionManager } from "../../managers/RowSelectionManager";
13
13
  import type { AnimationCoordinator, CellPosition } from "../../managers/AnimationCoordinator";
14
+ import type { AccordionAxis } from "../../utils/accordionAnimation";
14
15
  import { FlattenRowsResult } from "../../utils/rowFlattening";
15
16
  import { ProcessRowsResult } from "../../utils/rowProcessing";
16
17
  import { MergedColumnEditorConfig, ResolvedIcons } from "../initialization/TableInitializer";
17
18
  export interface RenderContext {
19
+ /**
20
+ * Active accordion animation axis for this render. Set on row-grouping or
21
+ * nested-column collapse/expand toggles (see
22
+ * {@link SimpleTableVanilla.beginAccordionAnimation}). Cell renderers use it
23
+ * to initialize incoming cells at zero size in the named axis so the CSS
24
+ * size transition can grow them while sibling cells FLIP into place.
25
+ */
26
+ accordionAxis?: AccordionAxis;
18
27
  animationCoordinator?: AnimationCoordinator;
19
28
  cellRegistry: Map<string, any>;
20
29
  collapsedHeaders: Set<Accessor>;
@@ -8,7 +8,10 @@ import { FilterManager } from "../../managers/FilterManager";
8
8
  import { SelectionManager } from "../../managers/SelectionManager";
9
9
  import { RowSelectionManager } from "../../managers/RowSelectionManager";
10
10
  import type { AnimationCoordinator, CellPosition } from "../../managers/AnimationCoordinator";
11
+ import type { AccordionAxis } from "../../utils/accordionAnimation";
11
12
  export interface TableRendererDeps {
13
+ /** Accordion animation axis for the in-flight collapse/expand. See {@link RenderContext.accordionAxis}. */
14
+ accordionAxis?: AccordionAxis;
12
15
  animationCoordinator?: AnimationCoordinator;
13
16
  cellRegistry: Map<string, any>;
14
17
  collapsedHeaders: Set<Accessor>;
@@ -56,7 +59,7 @@ export interface TableRendererDeps {
56
59
  pinnedRightRef: {
57
60
  current: HTMLDivElement | null;
58
61
  };
59
- positionOnlyBody?: boolean; /** When true, body sections use position-only updates for existing cells (scroll performance). */
62
+ positionOnlyBody?: boolean; /** When true, scroll path updates cell geometry only (no full content/selection refresh); row separators still sync. */
60
63
  resolvedIcons: any;
61
64
  rowSelectionManager: RowSelectionManager | null;
62
65
  rowStateMap: Map<string | number, any>;
@@ -33,6 +33,14 @@ export declare class AnimationCoordinator {
33
33
  private easing;
34
34
  /** Pre-change positions for any cell we want to consider for animation. */
35
35
  private snapshot;
36
+ /**
37
+ * One-shot synthetic origins for incoming cells that have no entry in the
38
+ * captured snapshot (e.g. rows/columns that did not exist in the pre-render
39
+ * state because they were inside a collapsed group). Used by accordion
40
+ * animations so a newly-visible cell unfolds from its parent's position
41
+ * rather than appearing in place. Cleared at the end of {@link play}.
42
+ */
43
+ private incomingOrigins;
36
44
  private inFlight;
37
45
  /** Outgoing cells the renderer handed off; keyed per container so play() finds them. */
38
46
  private retainedCells;
@@ -55,6 +63,19 @@ export declare class AnimationCoordinator {
55
63
  setEasing(easing: string): void;
56
64
  isEnabled(): boolean;
57
65
  isInFlight(cellId: string): boolean;
66
+ getDuration(): number;
67
+ getEasing(): string;
68
+ /**
69
+ * Register synthetic pre-change origins for incoming cells that did not
70
+ * exist in the captured snapshot. {@link play} consults this map before
71
+ * giving up on a cell that has no `before` snapshot entry; matching cells
72
+ * FLIP from the override origin to their final position.
73
+ *
74
+ * The map is consumed by the next `play()` call and cleared, so callers
75
+ * must set it after `captureSnapshot` and before the render that creates
76
+ * the corresponding cells.
77
+ */
78
+ setIncomingOrigins(origins: Map<string, CellPosition> | null): void;
58
79
  /**
59
80
  * Read scroller layout metrics for `container`, caching the result for the
60
81
  * remainder of the current render cycle. Subsequent calls in the same
@@ -82,6 +103,27 @@ export declare class AnimationCoordinator {
82
103
  * keep it for an out-animation.
83
104
  */
84
105
  shouldRetain(cellId: string): boolean;
106
+ /**
107
+ * Whether the captured snapshot has an entry for the given cellId. The
108
+ * accordion expand path uses this to detect "newly visible" cells (no
109
+ * pre-change layout) so it can initialize them at zero size and let the
110
+ * CSS transition grow them to full size.
111
+ */
112
+ hasSnapshotEntry(cellId: string): boolean;
113
+ /**
114
+ * True when the snapshot has an entry for `cellId` AND the cell was
115
+ * rendered in `currentContainer` at snapshot time. Returns false when the
116
+ * cell came from a different container (cross-section pin/unpin) — its
117
+ * snapshot position is in another container's coordinate frame, so a
118
+ * FLIP applied locally would slide from a wrong visual origin and the
119
+ * destination renderer should treat the cell as fresh (accordion grow
120
+ * from 0 instead).
121
+ *
122
+ * Snapshot entries with `sourceContainer === null` (preLayouts /
123
+ * conceptual positions) are treated as same-container so the existing
124
+ * sort/reorder FLIP-from-off-screen behavior is preserved.
125
+ */
126
+ hasSnapshotEntryInContainer(cellId: string, currentContainer: HTMLElement): boolean;
85
127
  /**
86
128
  * Hand a cell that the renderer would otherwise remove to the coordinator.
87
129
  * The coordinator updates its absolute positioning to the post-change layout
@@ -112,6 +154,28 @@ export declare class AnimationCoordinator {
112
154
  * doesn't pop into existence at a clipped FLIP entry point.
113
155
  */
114
156
  claimRetainedForReuse(cellId: string, container: HTMLElement): HTMLElement | null;
157
+ /**
158
+ * Hand off a cell that the renderer would otherwise remove for an accordion
159
+ * shrink-out (column hide / pin-out from this section): the cell stays in
160
+ * place and its size in the named axis is animated to zero by the
161
+ * `.st-accordion-animating` CSS transition (width/height). Removed from the
162
+ * DOM after the transition completes.
163
+ *
164
+ * Used when there is no destination position for the cell in the current
165
+ * section's post-render layout — either because the column was hidden or
166
+ * because it moved to a different pinned section. In the moved-section
167
+ * case, the destination section creates a fresh cell that grows from zero
168
+ * width via the existing accordion incoming-cell path, so the visual
169
+ * effect is a synchronized shrink-here / grow-there pair rather than a
170
+ * cross-container slide (which would require translating coordinates
171
+ * between two different container coordinate frames).
172
+ */
173
+ shrinkOutCell(args: {
174
+ cellId: string;
175
+ element: HTMLElement;
176
+ container: HTMLElement;
177
+ axis: "horizontal" | "vertical";
178
+ }): void;
115
179
  /**
116
180
  * Discard any retained cell with this id in the given container. Called by
117
181
  * the renderer when it's about to create a fresh cell with the same id, so
@@ -11,11 +11,12 @@ type TableRow = {
11
11
  rowId: (string | number)[];
12
12
  /**
13
13
  * Position-independent identity for the row, used as the basis for the
14
- * cell DOM `id` and the animation coordinator's snapshot key. When
15
- * `getRowId` is provided, this is `String(customId)` (optionally prefixed
16
- * by grouping keys for nested rows). Lets the same DOM cell survive a
17
- * sort, so FLIP can animate the row to its new position. Falls back to
18
- * the positional rowId string when `getRowId` is absent.
14
+ * cell DOM `id`, the animation coordinator's snapshot key, and **expand /
15
+ * collapse / row-loading state maps** ({@link expandStateKey}).
16
+ *
17
+ * Sort/filter reorder leaves this unchanged while positional `rowId` changes,
18
+ * so nested rows stay expanded after sort when this is supplied (via `getRowId`
19
+ * or WeakMap-backed fallback identities).
19
20
  */
20
21
  stableRowKey?: string;
21
22
  rowPath?: (string | number)[];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Active axis for the in-flight accordion animation. Set on the render
3
+ * context for one render after a collapse/expand toggle so cell renderers
4
+ * know which dimension to fold/unfold.
5
+ *
6
+ * - `"vertical"` — row group expand/collapse: incoming cells start at
7
+ * `height: 0` and CSS-transition to `rowHeight`.
8
+ * - `"horizontal"` — nested column expand/collapse: incoming cells start at
9
+ * `width: 0` and CSS-transition to their final width.
10
+ * - `null` — no accordion animation in progress (sort, reorder,
11
+ * scroll, etc.).
12
+ */
13
+ export type AccordionAxis = "vertical" | "horizontal" | null;
14
+ /** CSS class applied to the table root during the animation window. */
15
+ export declare const ACCORDION_ANIMATION_CLASS = "st-accordion-animating";
16
+ /** Custom property names consumed by the accordion CSS transitions. */
17
+ export declare const ACCORDION_DURATION_VAR = "--st-accordion-duration";
18
+ export declare const ACCORDION_EASING_VAR = "--st-accordion-easing";
19
+ /** Window after which the accordion CSS class is removed (ms past duration). */
20
+ export declare const ACCORDION_CLEANUP_BUFFER_MS = 80;
21
+ /**
22
+ * Detect `prefers-reduced-motion: reduce`. Returns `false` outside the
23
+ * browser (SSR) so the call site doesn't have to guard.
24
+ */
25
+ export declare const accordionPrefersReducedMotion: () => boolean;
@@ -1,4 +1,11 @@
1
+ import type Row from "../../types/Row";
2
+ import type TableRow from "../../types/TableRow";
1
3
  import { AbsoluteBodyCell, CellRenderContext } from "./types";
4
+ export interface CellLiveRef {
5
+ row: Row;
6
+ tableRow: TableRow;
7
+ }
8
+ export declare const cellLiveRefMap: WeakMap<HTMLElement, CellLiveRef>;
2
9
  export declare const untrackCellByRow: (rowId: string, cellElement: HTMLElement) => void;
3
10
  export declare const createBodyCellElement: (cell: AbsoluteBodyCell, context: CellRenderContext) => HTMLElement;
4
11
  export declare const updateBodyCellPosition: (cellElement: HTMLElement, cell: AbsoluteBodyCell) => void;
@@ -8,6 +8,7 @@ import type RowState from "../../types/RowState";
8
8
  import type { RowButton } from "../../types/RowButton";
9
9
  import type { CustomTheme } from "../../types/CustomTheme";
10
10
  import type { HeightOffsets } from "../infiniteScrollUtils";
11
+ import type { AccordionAxis } from "../accordionAnimation";
11
12
  import type { VanillaEmptyStateRenderer, VanillaErrorStateRenderer, VanillaLoadingStateRenderer } from "../../types/RowStateRendererProps";
12
13
  type SetStateAction<T> = T | ((prevState: T) => T);
13
14
  type Dispatch<A> = (value: A) => void;
@@ -105,5 +106,15 @@ export interface CellRenderContext {
105
106
  canExpandRowGroup?: (row: Row) => boolean;
106
107
  isLoading?: boolean;
107
108
  pinned?: "left" | "right";
109
+ /** Pinned section viewport width (px); used for row separators so they match the section, not the full table. */
110
+ pinnedSectionWidthPx?: number;
111
+ /**
112
+ * When set, this render is the post-state pass of a row-grouping (vertical)
113
+ * or nested-column (horizontal) expand/collapse. Newly-created cells whose
114
+ * cellId has no entry in the animation snapshot start at zero size in the
115
+ * named axis so the CSS transition can grow them to their final size while
116
+ * sibling rows/cells FLIP into their new positions.
117
+ */
118
+ accordionAxis?: AccordionAxis;
108
119
  }
109
120
  export {};
@@ -3,6 +3,8 @@ import SortColumn from "../../types/SortColumn";
3
3
  import { TableFilterState, FilterCondition } from "../../types/FilterTypes";
4
4
  import { IconsConfig } from "../../types/IconsConfig";
5
5
  import Row from "../../types/Row";
6
+ import type { AccordionAxis } from "../accordionAnimation";
7
+ import type { AnimationCoordinator } from "../../managers/AnimationCoordinator";
6
8
  type SetStateAction<T> = T | ((prevState: T) => T);
7
9
  type Dispatch<A> = (value: A) => void;
8
10
  type MutableRefObject<T> = {
@@ -58,6 +60,8 @@ export interface HeaderRenderContext {
58
60
  onSort: (accessor: Accessor) => void;
59
61
  onTableHeaderDragEnd: (headers: HeaderObject[]) => void;
60
62
  pinned?: "left" | "right";
63
+ /** Mirrors body context: pinned strip width for cache invalidation when only section width changes. */
64
+ pinnedSectionWidthPx?: number;
61
65
  pinnedLeftRef: RefObject<HTMLDivElement>;
62
66
  pinnedRightRef: RefObject<HTMLDivElement>;
63
67
  reverse: boolean;
@@ -73,5 +77,19 @@ export interface HeaderRenderContext {
73
77
  setSelectedCells: Dispatch<SetStateAction<Set<string>>>;
74
78
  setSelectedColumns: Dispatch<SetStateAction<Set<number>>>;
75
79
  sort: SortColumn | null;
80
+ /**
81
+ * Active accordion animation axis (parallel to {@link CellRenderContext.accordionAxis}).
82
+ * Used so newly-visible header cells (e.g. children of a just-expanded
83
+ * collapsible header) start at zero width and CSS-transition to their
84
+ * final width.
85
+ */
86
+ accordionAxis?: AccordionAxis;
87
+ /**
88
+ * Animation coordinator (when enabled). The header renderer uses
89
+ * {@link AnimationCoordinator.hasSnapshotEntry} to detect cells that did
90
+ * not exist in the pre-render layout — those are the incoming cells
91
+ * driving the unfold animation.
92
+ */
93
+ animationCoordinator?: AnimationCoordinator;
76
94
  }
77
95
  export {};
@@ -117,6 +117,24 @@ export declare const generateStableRowKey: (params: {
117
117
  groupingKey?: string;
118
118
  parentStableKey?: string | null;
119
119
  }) => string;
120
+ /**
121
+ * Canonical string key for per-row expandable UI state: {@link expandedRows},
122
+ * {@link collapsedRows}, and entries in {@link rowStateMap} (loading/error/empty).
123
+ *
124
+ * Mirrors {@link TableRow.stableRowKey} whenever it is defined so expand state survives
125
+ * sort/filter reorder while positional `rowId` indices change.
126
+ * Falls back to {@link rowIdToString}(rowId) for synthetic rows without a stable key.
127
+ */
128
+ export declare const expandStateKey: (tableRow: {
129
+ stableRowKey?: string;
130
+ rowId: (string | number)[];
131
+ }) => string;
132
+ /**
133
+ * Stable identity for full-width chrome rows (nested grid, loading/error state)
134
+ * under an expanded parent. Parent {@link expandStateKey} survives sort; path-based
135
+ * `rowId` does not, so SectionRenderer must key DOM maps on this instead.
136
+ */
137
+ export declare const nestedChromeRowKey: (parentExpandStateKey: string | number, groupingKey: string | undefined) => string;
120
138
  /**
121
139
  * Get nested rows from a row based on the grouping path
122
140
  */
@@ -127,14 +145,15 @@ export declare const getNestedRows: (row: Row, groupingKey: string) => Row[];
127
145
  export declare const hasNestedRows: (row: Row, groupingKey?: string) => boolean;
128
146
  /**
129
147
  * Determine if a row is expanded based on expandedDepths and manual row overrides
130
- * @param rowId - The ID of the row to check
148
+ * @param expandStateRowId - Canonical key for expandable row state ({@link expandStateKey}).
149
+ * Matches keys in expandedRows/collapsedRows (stable across sort/filter when stableRowKey is used).
131
150
  * @param depth - The depth level of the row (0-indexed)
132
151
  * @param expandedDepths - Set of depth levels that are expanded
133
152
  * @param expandedRows - Map of row IDs to their depths for rows that user wants expanded
134
153
  * @param collapsedRows - Map of row IDs to their depths for rows that user wants collapsed
135
154
  * @returns true if the row is expanded, false otherwise
136
155
  */
137
- export declare const isRowExpanded: (rowId: string | number, depth: number, expandedDepths: Set<number>, expandedRows: Map<string, number>, collapsedRows: Map<string, number>) => boolean;
156
+ export declare const isRowExpanded: (expandStateRowId: string | number, depth: number, expandedDepths: Set<number>, expandedRows: Map<string, number>, collapsedRows: Map<string, number>) => boolean;
138
157
  /**
139
158
  * Flatten rows recursively based on row grouping configuration
140
159
  * Now calculates ALL properties including position and isLastGroupRow
@@ -15,6 +15,20 @@ export interface StickyParentsContainerProps {
15
15
  scrollTop: number;
16
16
  scrollbarWidth: number;
17
17
  stickyParents: TableRow[];
18
+ /**
19
+ * Global `colIndex` of the first leaf column in each sticky strip section,
20
+ * matching {@link SectionRenderer} body sections (pinned left, main, right).
21
+ */
22
+ stickySectionColStart: {
23
+ left: number;
24
+ main: number;
25
+ right: number;
26
+ };
27
+ /**
28
+ * Row key (`stableRowKey` ?? `rowIdToString(rowId)`) → body slice `rowIndex`
29
+ * for the current `rowsToRender` band, so selection matches virtualized body cells.
30
+ */
31
+ stickyBodyRowIndexByRowKey: Map<string, number>;
18
32
  }
19
33
  export interface StickyParentsRenderContext {
20
34
  collapsedHeaders: Set<string>;
@@ -3,5 +3,9 @@ export declare const basicRowGroupingExampleDefaults: {
3
3
  rowGrouping: readonly ["divisions", "departments"];
4
4
  enableStickyParents: boolean;
5
5
  height: string;
6
+ animations: {
7
+ enabled: boolean;
8
+ duration: number;
9
+ };
6
10
  };
7
11
  export declare function renderBasicRowGroupingExample(args?: Partial<UniversalVanillaArgs>): HTMLElement;
@@ -5,5 +5,9 @@ export declare const collapsibleColumnsExampleDefaults: {
5
5
  selectableCells: boolean;
6
6
  columnReordering: boolean;
7
7
  height: string;
8
+ animations: {
9
+ enabled: boolean;
10
+ duration: number;
11
+ };
8
12
  };
9
13
  export declare function renderCollapsibleColumnsExample(args?: Partial<UniversalVanillaArgs>): HTMLElement;
@@ -1,5 +1,7 @@
1
1
  import { type UniversalVanillaArgs } from "../vanillaStoryConfig";
2
2
  export declare const dynamicNestedTableExampleDefaults: {
3
3
  height: string;
4
+ expandAll: boolean;
5
+ autoExpandColumns: boolean;
4
6
  };
5
7
  export declare function renderDynamicNestedTableExample(args?: Partial<UniversalVanillaArgs>): HTMLElement;
@@ -1,4 +1,5 @@
1
1
  import { type UniversalVanillaArgs } from "../../vanillaStoryConfig";
2
+ import type { Theme } from "../../../src/index";
2
3
  export declare const pinnedColumnsExampleDefaults: {
3
4
  rowGrouping: readonly ["stores"];
4
5
  columnReordering: boolean;
@@ -7,5 +8,6 @@ export declare const pinnedColumnsExampleDefaults: {
7
8
  editColumns: boolean;
8
9
  height: string;
9
10
  enableStickyParents: boolean;
11
+ theme: Theme;
10
12
  };
11
13
  export declare function renderPinnedColumnsExample(args?: Partial<UniversalVanillaArgs>): HTMLElement;
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * NESTED TABLES TESTS
3
- * Ported from React - same tests, vanilla table only.
3
+ * Rich deterministic data (marketing-style companies → divisions → teams), content assertions,
4
+ * and coverage for lazy load, multi-level nesting, sort, selection, filtering, pagination, collapse, and empty nested rows.
4
5
  */
5
6
  import type { Meta } from "@storybook/html";
7
+ import { SimpleTableVanilla } from "../../src/index";
6
8
  declare const meta: Meta;
7
9
  export default meta;
8
10
  export declare const BasicNestedTable: {
9
11
  render: () => HTMLDivElement & {
10
- _table?: import("../../src/index").SimpleTableVanilla | undefined;
12
+ _table?: SimpleTableVanilla | undefined;
11
13
  };
12
14
  play: ({ canvasElement }: {
13
15
  canvasElement: HTMLElement;
@@ -15,7 +17,7 @@ export declare const BasicNestedTable: {
15
17
  };
16
18
  export declare const NestedTableWithIndependentColumns: {
17
19
  render: () => HTMLDivElement & {
18
- _table?: import("../../src/index").SimpleTableVanilla | undefined;
20
+ _table?: SimpleTableVanilla | undefined;
19
21
  };
20
22
  play: ({ canvasElement }: {
21
23
  canvasElement: HTMLElement;
@@ -23,7 +25,7 @@ export declare const NestedTableWithIndependentColumns: {
23
25
  };
24
26
  export declare const NestedTableWithColumnResizing: {
25
27
  render: () => HTMLDivElement & {
26
- _table?: import("../../src/index").SimpleTableVanilla | undefined;
28
+ _table?: SimpleTableVanilla | undefined;
27
29
  };
28
30
  play: ({ canvasElement }: {
29
31
  canvasElement: HTMLElement;
@@ -31,7 +33,7 @@ export declare const NestedTableWithColumnResizing: {
31
33
  };
32
34
  export declare const NestedTableWithPagination: {
33
35
  render: () => HTMLDivElement & {
34
- _table?: import("../../src/index").SimpleTableVanilla | undefined;
36
+ _table?: SimpleTableVanilla | undefined;
35
37
  };
36
38
  play: ({ canvasElement }: {
37
39
  canvasElement: HTMLElement;
@@ -39,7 +41,63 @@ export declare const NestedTableWithPagination: {
39
41
  };
40
42
  export declare const NestedTableWithFiltering: {
41
43
  render: () => HTMLDivElement & {
42
- _table?: import("../../src/index").SimpleTableVanilla | undefined;
44
+ _table?: SimpleTableVanilla | undefined;
45
+ };
46
+ play: ({ canvasElement }: {
47
+ canvasElement: HTMLElement;
48
+ }) => Promise<void>;
49
+ };
50
+ export declare const NestedTableLazyLoadDivisions: {
51
+ render: () => HTMLDivElement & {
52
+ _table?: SimpleTableVanilla | undefined;
53
+ };
54
+ play: ({ canvasElement }: {
55
+ canvasElement: HTMLElement;
56
+ }) => Promise<void>;
57
+ };
58
+ export declare const NestedTableThreeLevels: {
59
+ render: () => HTMLDivElement & {
60
+ _table?: SimpleTableVanilla | undefined;
61
+ };
62
+ play: ({ canvasElement }: {
63
+ canvasElement: HTMLElement;
64
+ }) => Promise<void>;
65
+ };
66
+ export declare const NestedTableExpandCollapse: {
67
+ render: () => HTMLDivElement & {
68
+ _table?: SimpleTableVanilla | undefined;
69
+ };
70
+ play: ({ canvasElement }: {
71
+ canvasElement: HTMLElement;
72
+ }) => Promise<void>;
73
+ };
74
+ export declare const NestedTableNestedSort: {
75
+ render: () => HTMLDivElement & {
76
+ _table?: SimpleTableVanilla | undefined;
77
+ };
78
+ play: ({ canvasElement }: {
79
+ canvasElement: HTMLElement;
80
+ }) => Promise<void>;
81
+ };
82
+ export declare const NestedTableRowSelection: {
83
+ render: () => HTMLDivElement & {
84
+ _table?: SimpleTableVanilla | undefined;
85
+ };
86
+ play: ({ canvasElement }: {
87
+ canvasElement: HTMLElement;
88
+ }) => Promise<void>;
89
+ };
90
+ export declare const NestedTableEmptyDivisions: {
91
+ render: () => HTMLDivElement & {
92
+ _table?: SimpleTableVanilla | undefined;
93
+ };
94
+ play: ({ canvasElement }: {
95
+ canvasElement: HTMLElement;
96
+ }) => Promise<void>;
97
+ };
98
+ export declare const NestedTableAutoExpandNested: {
99
+ render: () => HTMLDivElement & {
100
+ _table?: SimpleTableVanilla | undefined;
43
101
  };
44
102
  play: ({ canvasElement }: {
45
103
  canvasElement: HTMLElement;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * COLLAPSE / EXPAND ACCORDION ANIMATION TESTS
3
+ *
4
+ * Verifies the accordion-style animations on:
5
+ * - Nested column collapse / expand: incoming columns start at width 0 and
6
+ * CSS-transition to their final width while surviving columns FLIP-shift.
7
+ * - Row group collapse / expand: incoming rows start at height 0 and
8
+ * CSS-transition to rowHeight while surviving rows FLIP-shift.
9
+ *
10
+ * The mechanism reuses the existing FLIP `AnimationCoordinator` (no extra
11
+ * config) and is gated by `animations.enabled`. This file exercises the
12
+ * one-render window where:
13
+ * - Root has `.st-accordion-animating`.
14
+ * - Newly-visible cells carry inline `width: 0px` or `height: 0px`.
15
+ */
16
+ import type { Meta } from "@storybook/html";
17
+ declare const meta: Meta;
18
+ export default meta;
19
+ export declare const ColumnExpand_AddsAccordionClass: {
20
+ tags: string[];
21
+ render: () => HTMLDivElement & {
22
+ _table?: import("../../src/index").SimpleTableVanilla | undefined;
23
+ };
24
+ play: ({ canvasElement }: {
25
+ canvasElement: HTMLElement;
26
+ }) => Promise<void>;
27
+ };
28
+ export declare const ColumnExpand_IncomingCellsStartAtZeroWidth: {
29
+ tags: string[];
30
+ render: () => HTMLDivElement & {
31
+ _table?: import("../../src/index").SimpleTableVanilla | undefined;
32
+ };
33
+ play: ({ canvasElement }: {
34
+ canvasElement: HTMLElement;
35
+ }) => Promise<void>;
36
+ };
37
+ export declare const RowExpand_AddsAccordionClass: {
38
+ tags: string[];
39
+ render: () => HTMLDivElement & {
40
+ _table?: import("../../src/index").SimpleTableVanilla | undefined;
41
+ };
42
+ play: ({ canvasElement }: {
43
+ canvasElement: HTMLElement;
44
+ }) => Promise<void>;
45
+ };
46
+ export declare const RowExpand_IncomingCellsStartAtZeroHeight: {
47
+ tags: string[];
48
+ render: () => HTMLDivElement & {
49
+ _table?: import("../../src/index").SimpleTableVanilla | undefined;
50
+ };
51
+ play: ({ canvasElement }: {
52
+ canvasElement: HTMLElement;
53
+ }) => Promise<void>;
54
+ };
55
+ export declare const Disabled_NoAccordionClass: {
56
+ tags: string[];
57
+ render: () => HTMLDivElement & {
58
+ _table?: import("../../src/index").SimpleTableVanilla | undefined;
59
+ };
60
+ play: ({ canvasElement }: {
61
+ canvasElement: HTMLElement;
62
+ }) => Promise<void>;
63
+ };
@@ -25,6 +25,11 @@ export declare const rowExists: (container: HTMLElement, rowIndex: string) => bo
25
25
  */
26
26
  export declare const getVirtualRows: (container: HTMLElement) => HTMLElement[][];
27
27
  export declare const waitForTable: (timeout?: number) => Promise<void>;
28
+ /** Poll until predicate returns true or timeout (reduces flake vs fixed setTimeout). */
29
+ export declare function waitUntil(predicate: () => boolean, options?: {
30
+ timeoutMs?: number;
31
+ intervalMs?: number;
32
+ }): Promise<void>;
28
33
  export declare const validateBasicTableStructure: (canvasElement: HTMLElement) => Promise<void>;
29
34
  export declare const validateColumnCount: (canvasElement: HTMLElement, expectedCount: number) => void;
30
35
  export declare const validateRowCount: (canvasElement: HTMLElement, expectedCount: number) => void;