impact-nova 1.7.2 → 1.7.3
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/dist/components/ui/accordion.d.ts +5 -0
- package/dist/components/ui/accordion.js +51 -39
- package/dist/components/ui/ag-grid-react/headers/header-search-input.js +207 -209
- package/dist/components/ui/ag-grid-react/index.js +86 -84
- package/dist/components/ui/ag-grid-react/theme.js +3 -0
- package/dist/components/ui/data-table/data-table-column-list.js +84 -78
- package/dist/components/ui/expandable-sku/expandable-sku.d.ts +38 -0
- package/dist/components/ui/expandable-sku/expandable-sku.js +244 -0
- package/dist/components/ui/expandable-sku/expandable-sku.types.d.ts +35 -0
- package/dist/components/ui/expandable-sku/index.d.ts +2 -0
- package/dist/components/ui/expandable-sku/index.js +4 -0
- package/dist/components/ui/filter-strip/filter-tag-list.d.ts +8 -1
- package/dist/components/ui/filter-strip/filter-tag-list.js +1 -0
- package/dist/components/ui/select/select.js +221 -210
- package/dist/impact-nova.css +1 -1
- package/dist/index.d.ts +57 -0
- package/dist/index.js +318 -300
- package/dist/lib/virtualized/index.d.ts +9 -0
- package/dist/lib/virtualized/sectioned.d.ts +37 -0
- package/dist/lib/virtualized/sectioned.js +38 -0
- package/dist/lib/virtualized/selection-counts.d.ts +14 -0
- package/dist/lib/virtualized/selection-counts.js +12 -0
- package/dist/lib/virtualized/types.d.ts +131 -0
- package/dist/lib/virtualized/useDataGrid.d.ts +15 -0
- package/dist/lib/virtualized/useDataGrid.js +12 -0
- package/dist/lib/virtualized/useDataSource.d.ts +8 -0
- package/dist/lib/virtualized/useDataSource.js +34 -0
- package/dist/lib/virtualized/useDebouncedValue.d.ts +4 -0
- package/dist/lib/virtualized/useDebouncedValue.js +11 -0
- package/dist/lib/virtualized/useRowState.d.ts +15 -0
- package/dist/lib/virtualized/useRowState.js +127 -0
- package/dist/lib/virtualized/useVirtualizedList.d.ts +72 -0
- package/dist/lib/virtualized/useVirtualizedList.js +155 -0
- package/dist/lib/virtualized/useVirtualizedRows.d.ts +22 -0
- package/dist/lib/virtualized/useVirtualizedRows.js +27 -0
- package/package.json +23 -1
- package/tailwind.config.js +2 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { DataSourceApi, DataSourceConfig, RowSelectionMode, RowSelectionState, SelectionCounts, UseRowStateOptions, UseRowStateResult, VirtualItem, VirtualListKey, VirtualRowDataStatus, VirtualRowModel, } from './types';
|
|
2
|
+
export { getSelectionCountsFromState } from './selection-counts';
|
|
3
|
+
export { useDataSource } from './useDataSource';
|
|
4
|
+
export { useRowState } from './useRowState';
|
|
5
|
+
export { useVirtualizedRows, type UseVirtualizedRowsOptions } from './useVirtualizedRows';
|
|
6
|
+
export { useVirtualizedList, type UseVirtualizedListOptions, type UseVirtualizedListResult, } from './useVirtualizedList';
|
|
7
|
+
export { buildSectionedFlatList, type DataSectionBlock, type HeaderSectionBlock, type SectionBlock, type SectionedFlatList, type SectionedFlatRow, } from './sectioned';
|
|
8
|
+
export { useDebouncedValue } from './useDebouncedValue';
|
|
9
|
+
export { useDataGridVirtualRows, type DataGridVirtualRowsResult, } from './useDataGrid';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flatten **section headers + data rows** into a single virtualized index space.
|
|
3
|
+
* Use with {@link useVirtualizedList} by setting `rowCount` to `flatRowCount` and resolving
|
|
4
|
+
* `getRowData` / `getRowId` from {@link SectionedFlatList.describeFlatIndex}.
|
|
5
|
+
*/
|
|
6
|
+
export type SectionedFlatRow = {
|
|
7
|
+
kind: "header";
|
|
8
|
+
sectionKey: string;
|
|
9
|
+
title: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "data";
|
|
12
|
+
sectionKey: string;
|
|
13
|
+
sourceIndex: number;
|
|
14
|
+
};
|
|
15
|
+
export type HeaderSectionBlock = {
|
|
16
|
+
type: "header";
|
|
17
|
+
sectionKey: string;
|
|
18
|
+
title: string;
|
|
19
|
+
};
|
|
20
|
+
export type DataSectionBlock = {
|
|
21
|
+
type: "data";
|
|
22
|
+
sectionKey: string;
|
|
23
|
+
rowCount: number;
|
|
24
|
+
/** Maps offset within this block (0 … rowCount - 1) to a logical source index (e.g. global SKU index). */
|
|
25
|
+
getSourceIndex: (offsetInBlock: number) => number;
|
|
26
|
+
};
|
|
27
|
+
export type SectionBlock = HeaderSectionBlock | DataSectionBlock;
|
|
28
|
+
export interface SectionedFlatList {
|
|
29
|
+
flatRowCount: number;
|
|
30
|
+
describeFlatIndex: (flatIndex: number) => SectionedFlatRow | null;
|
|
31
|
+
getStableKey: (flatIndex: number) => string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build O(#sections) metadata for a flattened virtual list (headers + variable data blocks).
|
|
35
|
+
* Safe for large `rowCount` inside data blocks — no dense array of all rows is allocated.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildSectionedFlatList(blocks: readonly SectionBlock[]): SectionedFlatList;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function f(c) {
|
|
2
|
+
let n = 0;
|
|
3
|
+
const r = [];
|
|
4
|
+
for (const t of c)
|
|
5
|
+
t.type === "header" ? (r.push({ flatStart: n, flatEnd: n + 1, block: t }), n += 1) : (r.push({
|
|
6
|
+
flatStart: n,
|
|
7
|
+
flatEnd: n + t.rowCount,
|
|
8
|
+
block: t
|
|
9
|
+
}), n += t.rowCount);
|
|
10
|
+
function i(t) {
|
|
11
|
+
if (t < 0 || t >= n) return null;
|
|
12
|
+
for (const e of r) {
|
|
13
|
+
if (t < e.flatStart || t >= e.flatEnd) continue;
|
|
14
|
+
const o = e.block;
|
|
15
|
+
if (o.type === "header")
|
|
16
|
+
return {
|
|
17
|
+
kind: "header",
|
|
18
|
+
sectionKey: o.sectionKey,
|
|
19
|
+
title: o.title
|
|
20
|
+
};
|
|
21
|
+
const s = t - e.flatStart;
|
|
22
|
+
return {
|
|
23
|
+
kind: "data",
|
|
24
|
+
sectionKey: o.sectionKey,
|
|
25
|
+
sourceIndex: o.getSourceIndex(s)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function u(t) {
|
|
31
|
+
const e = i(t);
|
|
32
|
+
return e ? e.kind === "header" ? `h:${e.sectionKey}` : `d:${e.sectionKey}:${e.sourceIndex}` : `oob-${t}`;
|
|
33
|
+
}
|
|
34
|
+
return { flatRowCount: n, describeFlatIndex: i, getStableKey: u };
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
f as buildSectionedFlatList
|
|
38
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RowSelectionState, SelectionCounts } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Selected / unselected **counts** from an AG Grid–compatible {@link RowSelectionState}.
|
|
4
|
+
*
|
|
5
|
+
* You must pass **`totalLogicalRows`** (your dataset size, e.g. server total count). Without it,
|
|
6
|
+
* when `selectAll` is true you cannot infer how many rows are selected — only how many **exceptions**
|
|
7
|
+
* (`toggledIds.size`) are unselected.
|
|
8
|
+
*
|
|
9
|
+
* | `selectAll` | Meaning of `toggledIds` | `selected` | `unselected` |
|
|
10
|
+
* |-------------|-------------------------|------------|----------------|
|
|
11
|
+
* | `false` | explicitly selected ids | `toggledIds.size` | `total - selected` |
|
|
12
|
+
* | `true` | exception (deselected) ids | `total - toggledIds.size` | `toggledIds.size` |
|
|
13
|
+
*/
|
|
14
|
+
export declare function getSelectionCountsFromState(state: RowSelectionState, totalLogicalRows: number): SelectionCounts;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
function s(e, l) {
|
|
2
|
+
const t = Math.max(0, Math.floor(l));
|
|
3
|
+
if (!e.selectAll) {
|
|
4
|
+
const o = e.toggledIds.size;
|
|
5
|
+
return { selected: o, unselected: Math.max(0, t - o) };
|
|
6
|
+
}
|
|
7
|
+
const n = e.toggledIds.size;
|
|
8
|
+
return { selected: Math.max(0, t - n), unselected: n };
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
s as getSelectionCountsFromState
|
|
12
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { VirtualItem } from '@tanstack/virtual-core';
|
|
2
|
+
export type { VirtualItem };
|
|
3
|
+
/** Stable virtual row key type (matches TanStack Virtual item keys). */
|
|
4
|
+
export type VirtualListKey = VirtualItem["key"];
|
|
5
|
+
/**
|
|
6
|
+
* Row payload availability for virtualized lists (server/windowed or sparse client data).
|
|
7
|
+
*/
|
|
8
|
+
export type VirtualRowDataStatus = "loading" | "ready" | "error";
|
|
9
|
+
/**
|
|
10
|
+
* Per-row view model passed to render functions. Indices are virtualization-only;
|
|
11
|
+
* stable {@link VirtualRowModel.id} is used for selection and expansion.
|
|
12
|
+
*/
|
|
13
|
+
export interface VirtualRowModel<TData> {
|
|
14
|
+
index: number;
|
|
15
|
+
id: string;
|
|
16
|
+
/** Resolved row data when available */
|
|
17
|
+
data: TData | undefined;
|
|
18
|
+
/** Alias for {@link VirtualRowModel.data} */
|
|
19
|
+
item: TData | undefined;
|
|
20
|
+
status: VirtualRowDataStatus;
|
|
21
|
+
error?: unknown;
|
|
22
|
+
isSelected: boolean;
|
|
23
|
+
isExpanded: boolean;
|
|
24
|
+
toggleSelect: () => void;
|
|
25
|
+
toggleExpand: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configure how row data is resolved without allocating an array of length `rowCount`.
|
|
29
|
+
* In server mode, implement {@link DataSourceConfig.isRowLoaded} and optional
|
|
30
|
+
* {@link DataSourceConfig.prefetchRange} while keeping `rowCount` as total logical rows.
|
|
31
|
+
*/
|
|
32
|
+
export interface DataSourceConfig<TData> {
|
|
33
|
+
rowCount: number;
|
|
34
|
+
getRowData: (index: number) => TData | undefined;
|
|
35
|
+
/** When false, the row is treated as not yet hydrated (skeleton / placeholder). */
|
|
36
|
+
isRowLoaded?: (index: number) => boolean;
|
|
37
|
+
/** Optional viewport hint for fetching (e.g. infinite query). */
|
|
38
|
+
prefetchRange?: (startIndex: number, endIndex: number) => void;
|
|
39
|
+
getRowError?: (index: number) => unknown;
|
|
40
|
+
}
|
|
41
|
+
export interface DataSourceApi<TData> {
|
|
42
|
+
rowCount: number;
|
|
43
|
+
getRowData: (index: number) => TData | undefined;
|
|
44
|
+
isRowLoaded: (index: number) => boolean;
|
|
45
|
+
prefetchRange?: (startIndex: number, endIndex: number) => void;
|
|
46
|
+
getRowStatus: (index: number) => VirtualRowDataStatus;
|
|
47
|
+
getRowError: (index: number) => unknown | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Row selection snapshot aligned with AG Grid server-side selection / SSRM:
|
|
51
|
+
* - `selectAll === false` → `toggledIds` lists **included** (selected) row ids only.
|
|
52
|
+
* - `selectAll === true` → `toggledIds` lists **exceptions** (deselected) row ids; all other rows count as selected.
|
|
53
|
+
*/
|
|
54
|
+
export interface RowSelectionState {
|
|
55
|
+
selectAll: boolean;
|
|
56
|
+
toggledIds: Set<string>;
|
|
57
|
+
}
|
|
58
|
+
/** Returned by {@link UseRowStateResult.getSelectionCounts} and {@link getSelectionCountsFromState}. */
|
|
59
|
+
export interface SelectionCounts {
|
|
60
|
+
selected: number;
|
|
61
|
+
unselected: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* - **`explicit`**: finite selection only — `selectedIds` is the source of truth (same as before).
|
|
65
|
+
* - **`selectAllWithExceptions`**: AG Grid–style SSRM selection — global `selectAll` + exception `toggledIds`
|
|
66
|
+
* without enumerating every row id (`isSelected` uses the inversion formula).
|
|
67
|
+
*/
|
|
68
|
+
export type RowSelectionMode = "explicit" | "selectAllWithExceptions";
|
|
69
|
+
export interface UseRowStateOptions {
|
|
70
|
+
/**
|
|
71
|
+
* @default "explicit"
|
|
72
|
+
*/
|
|
73
|
+
selectionMode?: RowSelectionMode;
|
|
74
|
+
/** --- `explicit` mode (default) --- */
|
|
75
|
+
/** Controlled selection; pass a stable reference (e.g. memoized `Set` or `string[]`). */
|
|
76
|
+
selectedIds?: ReadonlySet<string> | readonly string[];
|
|
77
|
+
onSelectedIdsChange?: (next: Set<string>) => void;
|
|
78
|
+
defaultSelectedIds?: ReadonlySet<string> | readonly string[];
|
|
79
|
+
/** --- `selectAllWithExceptions` mode (AG Grid SSRM–style) --- */
|
|
80
|
+
/** Controlled global “select all rows” flag. */
|
|
81
|
+
selectAll?: boolean;
|
|
82
|
+
/** Controlled exception ids (exclusions when `selectAll` is true; inclusions when `selectAll` is false). */
|
|
83
|
+
toggledIds?: ReadonlySet<string> | readonly string[];
|
|
84
|
+
onSelectionStateChange?: (next: RowSelectionState) => void;
|
|
85
|
+
defaultSelectAll?: boolean;
|
|
86
|
+
defaultToggledIds?: ReadonlySet<string> | readonly string[];
|
|
87
|
+
expandedIds?: ReadonlySet<string> | readonly string[];
|
|
88
|
+
onExpandedIdsChange?: (next: Set<string>) => void;
|
|
89
|
+
defaultExpandedIds?: ReadonlySet<string> | readonly string[];
|
|
90
|
+
}
|
|
91
|
+
export interface UseRowStateResult {
|
|
92
|
+
selectionMode: RowSelectionMode;
|
|
93
|
+
/** Snapshot for reading selection membership (finite set). When `selectAll` is true in SSRM mode, this Set cannot list every selected id — use {@link getSelectionState} instead (may be empty). */
|
|
94
|
+
selectedIds: ReadonlySet<string>;
|
|
95
|
+
/**
|
|
96
|
+
* AG Grid–compatible flags. In `explicit` mode, `selectAll` is always `false` and `toggledIds` matches {@link selectedIds}.
|
|
97
|
+
*/
|
|
98
|
+
selectAll: boolean;
|
|
99
|
+
/** Exception / inclusion ids depending on {@link selectAll} (see {@link RowSelectionState}). */
|
|
100
|
+
toggledIds: ReadonlySet<string>;
|
|
101
|
+
/** Same shape as AG Grid `getServerSideSelectionState()` for wiring to APIs. */
|
|
102
|
+
getSelectionState: () => RowSelectionState;
|
|
103
|
+
/**
|
|
104
|
+
* Selected / unselected **counts** when you know **total logical row count** (e.g. server `totalCount`).
|
|
105
|
+
* See {@link getSelectionCountsFromState} for the formula (depends on `selectAll` + `toggledIds`).
|
|
106
|
+
*/
|
|
107
|
+
getSelectionCounts: (totalLogicalRows: number) => SelectionCounts;
|
|
108
|
+
/**
|
|
109
|
+
* Sets global select-all and clears exceptions (AG Grid: select entire result set without listing ids).
|
|
110
|
+
* No-op in `explicit` mode except `setSelectAll(false)` which clears selection.
|
|
111
|
+
*/
|
|
112
|
+
setSelectAll: (value: boolean) => void;
|
|
113
|
+
expandedIds: ReadonlySet<string>;
|
|
114
|
+
isSelected: (id: string) => boolean;
|
|
115
|
+
isExpanded: (id: string) => boolean;
|
|
116
|
+
toggleSelect: (id: string) => void;
|
|
117
|
+
toggleExpand: (id: string) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Adds ids to the current selection (explicit: union into `selectedIds`; SSRM: merges into `toggledIds`
|
|
120
|
+
* — when `selectAll` is true, removes ids from toggled so they become selected; when false, adds ids to toggled).
|
|
121
|
+
*/
|
|
122
|
+
mergeSelectedIds: (ids: string[]) => void;
|
|
123
|
+
/**
|
|
124
|
+
* If every id is already selected, removes those ids in one update; otherwise adds all ids
|
|
125
|
+
* (same merge as {@link mergeSelectedIds}). Use for “select / deselect visible window” toggles.
|
|
126
|
+
*/
|
|
127
|
+
toggleSelectAll: (ids: ReadonlyArray<string>) => void;
|
|
128
|
+
clearSelection: () => void;
|
|
129
|
+
isAllSelected: (candidateIds: string[]) => boolean;
|
|
130
|
+
clearExpansion: () => void;
|
|
131
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Row, Table } from '@tanstack/react-table';
|
|
2
|
+
export interface DataGridVirtualRowsResult<TData> {
|
|
3
|
+
rowCount: number;
|
|
4
|
+
getRowData: (index: number) => TData | undefined;
|
|
5
|
+
getRowId: (index: number) => string;
|
|
6
|
+
getTanStackRow: (index: number) => Row<TData> | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Maps a TanStack Table row model into the shape expected by {@link useVirtualizedList}.
|
|
10
|
+
*
|
|
11
|
+
* **Important:** This reads `table.getRowModel().rows`, which materializes every row in memory.
|
|
12
|
+
* Use only for moderate in-browser datasets (on the order of thousands of rows). For 100k+ rows,
|
|
13
|
+
* keep a windowed store or infinite query and drive the list from {@link useDataSource} instead.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useDataGridVirtualRows<TData>(table: Table<TData>): DataGridVirtualRowsResult<TData>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DataSourceApi, DataSourceConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Headless data access for virtualized lists. Never materializes `rowCount` items in memory.
|
|
4
|
+
*
|
|
5
|
+
* - **Client**: omit `isRowLoaded` — rows are considered ready; `getRowData` may still return `undefined`.
|
|
6
|
+
* - **Server / partial**: provide `isRowLoaded` and optionally `prefetchRange` for windowed fetches.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useDataSource<TData>(config: DataSourceConfig<TData>): DataSourceApi<TData>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useCallback as a, useMemo as g } from "react";
|
|
2
|
+
function l(R) {
|
|
3
|
+
const { rowCount: o, getRowData: n, isRowLoaded: u, prefetchRange: s, getRowError: t } = R, e = a(
|
|
4
|
+
(r) => r < 0 || r >= o ? !1 : u ? u(r) : !0,
|
|
5
|
+
[o, u]
|
|
6
|
+
), c = a(
|
|
7
|
+
(r) => {
|
|
8
|
+
if (r < 0 || r >= o) return "ready";
|
|
9
|
+
const w = t?.(r);
|
|
10
|
+
return w != null ? "error" : e(r) ? "ready" : "loading";
|
|
11
|
+
},
|
|
12
|
+
[o, t, e]
|
|
13
|
+
), f = a(
|
|
14
|
+
(r) => {
|
|
15
|
+
if (!(r < 0 || r >= o))
|
|
16
|
+
return t?.(r);
|
|
17
|
+
},
|
|
18
|
+
[o, t]
|
|
19
|
+
);
|
|
20
|
+
return g(
|
|
21
|
+
() => ({
|
|
22
|
+
rowCount: o,
|
|
23
|
+
getRowData: n,
|
|
24
|
+
isRowLoaded: e,
|
|
25
|
+
prefetchRange: s,
|
|
26
|
+
getRowStatus: c,
|
|
27
|
+
getRowError: f
|
|
28
|
+
}),
|
|
29
|
+
[o, n, e, s, c, f]
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
l as useDataSource
|
|
34
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UseRowStateOptions, UseRowStateResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Headless selection and expansion for virtualized rows.
|
|
4
|
+
*
|
|
5
|
+
* **Selection modes**
|
|
6
|
+
* - **`explicit` (default)**: finite `selectedIds` set — same model as before.
|
|
7
|
+
* - **`selectAllWithExceptions`**: AG Grid SSRM–style `{ selectAll, toggledIds }` where
|
|
8
|
+
* `isSelected(id) === selectAll ? !toggledIds.has(id) : toggledIds.has(id)` so you do not
|
|
9
|
+
* need every row id for a global “select all”.
|
|
10
|
+
*
|
|
11
|
+
* **Ids vs indices**: Key state by stable row ids (`getRowId`), not visible index.
|
|
12
|
+
*
|
|
13
|
+
* **Controlled**: pass the matching props + `on*Change` handlers with stable references when possible.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useRowState(options?: UseRowStateOptions): UseRowStateResult;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { useState as b, useMemo as w, useCallback as c } from "react";
|
|
2
|
+
import { getSelectionCountsFromState as J } from "./selection-counts.js";
|
|
3
|
+
function f(d) {
|
|
4
|
+
return d ? d instanceof Set ? new Set(d) : new Set(d) : /* @__PURE__ */ new Set();
|
|
5
|
+
}
|
|
6
|
+
function K(d) {
|
|
7
|
+
return (d.selectionMode ?? "explicit") === "selectAllWithExceptions" ? {
|
|
8
|
+
all: d.defaultSelectAll ?? !1,
|
|
9
|
+
toggled: f(d.defaultToggledIds)
|
|
10
|
+
} : {
|
|
11
|
+
all: !1,
|
|
12
|
+
toggled: f(d.defaultSelectedIds)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function O(d = {}) {
|
|
16
|
+
const o = d.selectionMode ?? "explicit", {
|
|
17
|
+
selectedIds: g,
|
|
18
|
+
onSelectedIdsChange: h,
|
|
19
|
+
expandedIds: x,
|
|
20
|
+
onExpandedIdsChange: m,
|
|
21
|
+
defaultExpandedIds: R,
|
|
22
|
+
onSelectionStateChange: P,
|
|
23
|
+
selectAll: S,
|
|
24
|
+
toggledIds: u
|
|
25
|
+
} = d, [I, A] = b(() => K(d)), [v, y] = b(
|
|
26
|
+
() => f(R)
|
|
27
|
+
), r = x !== void 0, E = w(() => r ? f(x) : v, [r, x, v]), l = w(
|
|
28
|
+
() => o === "selectAllWithExceptions" ? S !== void 0 ? S : I.all : !1,
|
|
29
|
+
[o, S, I.all]
|
|
30
|
+
), s = w(() => o === "explicit" ? g !== void 0 ? f(g) : I.toggled : u !== void 0 ? f(u) : I.toggled, [o, g, u, I.toggled]), W = w(() => o === "explicit" || !l ? s : /* @__PURE__ */ new Set(), [o, l, s]), k = c(
|
|
31
|
+
(e) => l ? !s.has(e) : s.has(e),
|
|
32
|
+
[l, s]
|
|
33
|
+
), F = c((e) => E.has(e), [E]), p = c(
|
|
34
|
+
(e) => {
|
|
35
|
+
h?.(e), g === void 0 && A((t) => ({ ...t, all: !1, toggled: e }));
|
|
36
|
+
},
|
|
37
|
+
[h, g]
|
|
38
|
+
), i = c(
|
|
39
|
+
(e) => {
|
|
40
|
+
P?.(e), S === void 0 && u === void 0 ? A({ all: e.selectAll, toggled: e.toggledIds }) : u === void 0 ? A((t) => ({ ...t, toggled: e.toggledIds })) : S === void 0 && A((t) => ({ ...t, all: e.selectAll }));
|
|
41
|
+
},
|
|
42
|
+
[P, S, u]
|
|
43
|
+
), T = c(
|
|
44
|
+
(e) => {
|
|
45
|
+
const t = new Set(s);
|
|
46
|
+
t.has(e) ? t.delete(e) : t.add(e), o === "explicit" ? p(t) : i({ selectAll: l, toggledIds: t });
|
|
47
|
+
},
|
|
48
|
+
[o, s, l, p, i]
|
|
49
|
+
), j = c(
|
|
50
|
+
(e) => {
|
|
51
|
+
const t = r ? f(x) : v, n = new Set(t);
|
|
52
|
+
n.has(e) ? n.delete(e) : n.add(e), r ? m?.(n) : y(n);
|
|
53
|
+
},
|
|
54
|
+
[r, x, v, m]
|
|
55
|
+
), q = c(
|
|
56
|
+
(e) => {
|
|
57
|
+
const t = new Set(s);
|
|
58
|
+
for (const n of e)
|
|
59
|
+
l ? t.delete(n) : t.add(n);
|
|
60
|
+
o === "explicit" ? p(t) : i({ selectAll: l, toggledIds: t });
|
|
61
|
+
},
|
|
62
|
+
[o, s, l, p, i]
|
|
63
|
+
), z = c(
|
|
64
|
+
(e) => {
|
|
65
|
+
if (e.length === 0) return;
|
|
66
|
+
const t = e.every(
|
|
67
|
+
(a) => l ? !s.has(a) : s.has(a)
|
|
68
|
+
), n = new Set(s);
|
|
69
|
+
if (t)
|
|
70
|
+
for (const a of e)
|
|
71
|
+
l ? n.add(a) : n.delete(a);
|
|
72
|
+
else
|
|
73
|
+
for (const a of e)
|
|
74
|
+
l ? n.delete(a) : n.add(a);
|
|
75
|
+
o === "explicit" ? p(n) : i({ selectAll: l, toggledIds: n });
|
|
76
|
+
},
|
|
77
|
+
[o, l, s, p, i]
|
|
78
|
+
), C = c(() => {
|
|
79
|
+
const e = /* @__PURE__ */ new Set();
|
|
80
|
+
o === "explicit" ? (h?.(e), g === void 0 && A((t) => ({ ...t, all: !1, toggled: e }))) : i({ selectAll: !1, toggledIds: e });
|
|
81
|
+
}, [o, h, g, i]), B = c(
|
|
82
|
+
(e) => {
|
|
83
|
+
if (o === "explicit") {
|
|
84
|
+
e || C();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
i({ selectAll: e, toggledIds: /* @__PURE__ */ new Set() });
|
|
88
|
+
},
|
|
89
|
+
[o, C, i]
|
|
90
|
+
), M = c(() => ({
|
|
91
|
+
selectAll: l,
|
|
92
|
+
toggledIds: new Set(s)
|
|
93
|
+
}), [l, s]), D = c(
|
|
94
|
+
(e) => J(M(), e),
|
|
95
|
+
[M]
|
|
96
|
+
), G = c(
|
|
97
|
+
(e) => e.length === 0 ? !0 : e.every(
|
|
98
|
+
(t) => l ? !s.has(t) : s.has(t)
|
|
99
|
+
),
|
|
100
|
+
[l, s]
|
|
101
|
+
), H = c(() => {
|
|
102
|
+
const e = /* @__PURE__ */ new Set();
|
|
103
|
+
r ? m?.(e) : y(e);
|
|
104
|
+
}, [r, m]);
|
|
105
|
+
return {
|
|
106
|
+
selectionMode: o,
|
|
107
|
+
selectedIds: W,
|
|
108
|
+
selectAll: l,
|
|
109
|
+
toggledIds: s,
|
|
110
|
+
getSelectionState: M,
|
|
111
|
+
getSelectionCounts: D,
|
|
112
|
+
setSelectAll: B,
|
|
113
|
+
expandedIds: E,
|
|
114
|
+
isSelected: k,
|
|
115
|
+
isExpanded: F,
|
|
116
|
+
toggleSelect: T,
|
|
117
|
+
toggleExpand: j,
|
|
118
|
+
mergeSelectedIds: q,
|
|
119
|
+
toggleSelectAll: z,
|
|
120
|
+
clearSelection: C,
|
|
121
|
+
isAllSelected: G,
|
|
122
|
+
clearExpansion: H
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
O as useRowState
|
|
127
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Virtualizer } from '@tanstack/virtual-core';
|
|
2
|
+
import { CSSProperties, RefObject } from 'react';
|
|
3
|
+
import { ReactVirtualizerOptions } from '@tanstack/react-virtual';
|
|
4
|
+
import { DataSourceConfig, UseRowStateOptions, UseRowStateResult, VirtualItem, VirtualListKey, VirtualRowModel } from './types';
|
|
5
|
+
export type UseVirtualizedListOptions<TData, TScrollElement extends Element = HTMLDivElement, TItemElement extends Element = HTMLDivElement> = DataSourceConfig<TData> & UseRowStateOptions & {
|
|
6
|
+
scrollElementRef: RefObject<TScrollElement | null>;
|
|
7
|
+
/** Stable logical id for each row index (required for selection / expansion). */
|
|
8
|
+
getRowId: (index: number) => string;
|
|
9
|
+
estimateSize: (index: number) => number;
|
|
10
|
+
overscan?: number;
|
|
11
|
+
getItemKey?: (index: number) => VirtualListKey;
|
|
12
|
+
/** How close to the last logical index `onEndReached` fires (default 3). */
|
|
13
|
+
endReachedThreshold?: number;
|
|
14
|
+
onEndReached?: () => void;
|
|
15
|
+
/** When false, `onEndReached` is not invoked (e.g. no further pages). */
|
|
16
|
+
hasMore?: boolean;
|
|
17
|
+
} & Omit<Partial<ReactVirtualizerOptions<TScrollElement, TItemElement>>, "count" | "getScrollElement" | "estimateSize" | "overscan" | "getItemKey" | "onChange"> & {
|
|
18
|
+
/** Merged with the internal handler that powers `onEndReached`. */
|
|
19
|
+
onChange?: ReactVirtualizerOptions<TScrollElement, TItemElement>["onChange"];
|
|
20
|
+
};
|
|
21
|
+
export interface UseVirtualizedListResult<TData, TScrollElement extends Element = HTMLDivElement, TItemElement extends Element = HTMLDivElement> {
|
|
22
|
+
virtualItems: VirtualItem[];
|
|
23
|
+
/** Total scrollable size in pixels (alias of `totalSize`). */
|
|
24
|
+
totalHeight: number;
|
|
25
|
+
totalSize: number;
|
|
26
|
+
measureElement: Virtualizer<TScrollElement, TItemElement>["measureElement"];
|
|
27
|
+
virtualizer: Virtualizer<TScrollElement, TItemElement>;
|
|
28
|
+
scrollToIndex: Virtualizer<TScrollElement, TItemElement>["scrollToIndex"];
|
|
29
|
+
getRow: (index: number) => VirtualRowModel<TData>;
|
|
30
|
+
getItemProps: (virtualItemOrIndex: VirtualItem | number, options?: {
|
|
31
|
+
measure?: boolean;
|
|
32
|
+
}) => {
|
|
33
|
+
key: VirtualListKey;
|
|
34
|
+
role: "row";
|
|
35
|
+
"data-index": number;
|
|
36
|
+
ref: Virtualizer<TScrollElement, TItemElement>["measureElement"] | undefined;
|
|
37
|
+
style: CSSProperties;
|
|
38
|
+
};
|
|
39
|
+
rowState: UseRowStateResult;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Composes {@link useDataSource}, {@link useRowState}, and {@link useVirtualizedRows}.
|
|
43
|
+
* Intended for 100k+ rows: never builds an array of length `rowCount`; resolve data per index only.
|
|
44
|
+
*
|
|
45
|
+
* **Render pattern**
|
|
46
|
+
* ```tsx
|
|
47
|
+
* virtualItems.map((vItem) => {
|
|
48
|
+
* const row = getRow(vItem.index);
|
|
49
|
+
* return renderItem(row);
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* **SSR**: pass `initialRect` (and related options) through to the underlying virtualizer.
|
|
54
|
+
*
|
|
55
|
+
* **Infinite loading**: implement `onEndReached` and set `hasMore` when no pages remain; optionally
|
|
56
|
+
* use `prefetchRange` so a parent cache (e.g. TanStack Query) can fetch the visible window.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const parentRef = useRef<HTMLDivElement>(null);
|
|
61
|
+
* const list = useVirtualizedList({
|
|
62
|
+
* scrollElementRef: parentRef,
|
|
63
|
+
* rowCount: 100_000,
|
|
64
|
+
* getRowId: (i) => String(i),
|
|
65
|
+
* getRowData: (i) => rows.get(i),
|
|
66
|
+
* estimateSize: () => 52,
|
|
67
|
+
* onEndReached: fetchNextPage,
|
|
68
|
+
* hasMore,
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function useVirtualizedList<TData, TScrollElement extends Element = HTMLDivElement, TItemElement extends Element = HTMLDivElement>(options: UseVirtualizedListOptions<TData, TScrollElement, TItemElement>): UseVirtualizedListResult<TData, TScrollElement, TItemElement>;
|