@zvndev/yable-react 0.3.0 → 0.5.0
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/index.cjs +1322 -267
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +324 -16
- package/dist/index.d.ts +324 -16
- package/dist/index.js +1307 -269
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,10 +1,118 @@
|
|
|
1
1
|
import { canCellEnterEditMode, functionalUpdate, createTable, getDefaultLocale, getFirstKeyboardCell, getResolvedFocusedCell, detectCellChanges } from '@zvndev/yable-core';
|
|
2
2
|
export { CommitError, FormulaEngine, FormulaError, PivotEngine, UndoStack, aggregationFns, createColumnHelper, createLocale, createUndoRedoIntegration, en, filterFns, formulaFunctions, functionalUpdate, generatePivotColumnDefs, getDefaultLocale, getInitialPivotState, getPivotRowModel, resetLocale, setDefaultLocale, sortingFns } from '@zvndev/yable-core';
|
|
3
|
-
import React3, { createContext, useCallback, useMemo, useState, useRef, useEffect
|
|
3
|
+
import React3, { createContext, useCallback, useMemo, useContext, useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
5
6
|
import { getInitialRowDragState, moveRow } from '@zvndev/yable-core/features/rowDragging';
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
9
|
+
var YableContext = createContext({});
|
|
10
|
+
function useYableDefaults() {
|
|
11
|
+
return useContext(YableContext);
|
|
12
|
+
}
|
|
13
|
+
function YableProvider({
|
|
14
|
+
children,
|
|
15
|
+
config,
|
|
16
|
+
tableProfile,
|
|
17
|
+
defaultColumnDef,
|
|
18
|
+
striped,
|
|
19
|
+
stickyHeader,
|
|
20
|
+
bordered,
|
|
21
|
+
compact,
|
|
22
|
+
theme,
|
|
23
|
+
direction,
|
|
24
|
+
ariaLabel
|
|
25
|
+
}) {
|
|
26
|
+
const tableProps = {};
|
|
27
|
+
if (striped !== void 0) tableProps.striped = striped;
|
|
28
|
+
if (stickyHeader !== void 0) tableProps.stickyHeader = stickyHeader;
|
|
29
|
+
if (bordered !== void 0) tableProps.bordered = bordered;
|
|
30
|
+
if (compact !== void 0) tableProps.compact = compact;
|
|
31
|
+
if (theme !== void 0) tableProps.theme = theme;
|
|
32
|
+
if (direction !== void 0) tableProps.direction = direction;
|
|
33
|
+
if (ariaLabel !== void 0) tableProps.ariaLabel = ariaLabel;
|
|
34
|
+
const value = {
|
|
35
|
+
config,
|
|
36
|
+
tableProfile,
|
|
37
|
+
tableProps: Object.keys(tableProps).length > 0 ? tableProps : void 0,
|
|
38
|
+
defaultColumnDef
|
|
39
|
+
};
|
|
40
|
+
return /* @__PURE__ */ jsx(YableContext.Provider, { value, children });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/config.ts
|
|
44
|
+
function createYableConfig(config) {
|
|
45
|
+
return config;
|
|
46
|
+
}
|
|
47
|
+
function resolveYableProfile(config, profileName = "default") {
|
|
48
|
+
const base = pickProfileFields(config);
|
|
49
|
+
const named = profileName === "default" ? void 0 : config?.profiles?.[profileName];
|
|
50
|
+
return {
|
|
51
|
+
name: profileName,
|
|
52
|
+
table: { ...base.table, ...named?.table },
|
|
53
|
+
columns: {
|
|
54
|
+
default: { ...base.columns?.default, ...named?.columns?.default },
|
|
55
|
+
byId: { ...base.columns?.byId, ...named?.columns?.byId }
|
|
56
|
+
},
|
|
57
|
+
rows: { ...base.rows, ...named?.rows },
|
|
58
|
+
cells: {
|
|
59
|
+
default: { ...base.cells?.default, ...named?.cells?.default },
|
|
60
|
+
named: { ...base.cells?.named, ...named?.cells?.named },
|
|
61
|
+
byColumn: { ...base.cells?.byColumn, ...named?.cells?.byColumn }
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getYableDefaultColumnDef(profile) {
|
|
66
|
+
const next = {
|
|
67
|
+
...profile?.columns?.default
|
|
68
|
+
};
|
|
69
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
70
|
+
}
|
|
71
|
+
function applyYableConfigToColumns(columns, profile) {
|
|
72
|
+
if (!profile) return columns;
|
|
73
|
+
return columns.map((columnDef) => applyColumnConfig(columnDef, profile));
|
|
74
|
+
}
|
|
75
|
+
function applyColumnConfig(columnDef, profile) {
|
|
76
|
+
const columnId = getColumnId(columnDef);
|
|
77
|
+
const explicit = columnDef;
|
|
78
|
+
const cellNames = normalizeCellConfigNames(explicit.cellConfig);
|
|
79
|
+
const namedCellConfig = cellNames.reduce(
|
|
80
|
+
(acc, name) => ({ ...acc, ...profile.cells?.named?.[name] }),
|
|
81
|
+
{}
|
|
82
|
+
);
|
|
83
|
+
const defaultCell = profile.cells?.default;
|
|
84
|
+
const columnCell = columnId ? profile.cells?.byColumn?.[columnId] : void 0;
|
|
85
|
+
const columnConfig = columnId ? profile.columns?.byId?.[columnId] : void 0;
|
|
86
|
+
const children = "columns" in columnDef && columnDef.columns ? { columns: columnDef.columns.map((child) => applyColumnConfig(child, profile)) } : void 0;
|
|
87
|
+
return {
|
|
88
|
+
...defaultCell,
|
|
89
|
+
...namedCellConfig,
|
|
90
|
+
...columnCell,
|
|
91
|
+
...columnConfig,
|
|
92
|
+
...columnDef,
|
|
93
|
+
...children
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function pickProfileFields(config) {
|
|
97
|
+
if (!config) return {};
|
|
98
|
+
return {
|
|
99
|
+
table: config.table,
|
|
100
|
+
columns: config.columns,
|
|
101
|
+
rows: config.rows,
|
|
102
|
+
cells: config.cells
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function getColumnId(columnDef) {
|
|
106
|
+
if ("id" in columnDef && columnDef.id) return String(columnDef.id);
|
|
107
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey) return String(columnDef.accessorKey);
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
function normalizeCellConfigNames(value) {
|
|
111
|
+
if (!value) return [];
|
|
112
|
+
return Array.isArray(value) ? value : [value];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/useTable.ts
|
|
8
116
|
function shallowEqual(a, b) {
|
|
9
117
|
if (a === b) return true;
|
|
10
118
|
const keysA = Object.keys(a);
|
|
@@ -17,6 +125,32 @@ function shallowEqual(a, b) {
|
|
|
17
125
|
return true;
|
|
18
126
|
}
|
|
19
127
|
function useTable(options) {
|
|
128
|
+
const providerDefaults = useYableDefaults();
|
|
129
|
+
const optionsWithDefaults = useMemo(() => {
|
|
130
|
+
const profile = resolveYableProfile(
|
|
131
|
+
options.config ?? providerDefaults.config,
|
|
132
|
+
options.configProfile ?? providerDefaults.tableProfile
|
|
133
|
+
);
|
|
134
|
+
const profileDefaultColumnDef = getYableDefaultColumnDef(profile);
|
|
135
|
+
const configuredColumns = applyYableConfigToColumns(options.columns, profile);
|
|
136
|
+
const defaultColumnDef = {
|
|
137
|
+
...profileDefaultColumnDef,
|
|
138
|
+
...providerDefaults.defaultColumnDef,
|
|
139
|
+
...options.defaultColumnDef
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
...options,
|
|
143
|
+
columns: configuredColumns,
|
|
144
|
+
rowClassName: options.rowClassName ?? profile.rows?.className,
|
|
145
|
+
rowStyle: options.rowStyle ?? profile.rows?.style,
|
|
146
|
+
defaultColumnDef: Object.keys(defaultColumnDef).length > 0 ? defaultColumnDef : void 0
|
|
147
|
+
};
|
|
148
|
+
}, [
|
|
149
|
+
options,
|
|
150
|
+
providerDefaults.config,
|
|
151
|
+
providerDefaults.defaultColumnDef,
|
|
152
|
+
providerDefaults.tableProfile
|
|
153
|
+
]);
|
|
20
154
|
const [state, setState] = useState(() => ({
|
|
21
155
|
sorting: [],
|
|
22
156
|
columnFilters: [],
|
|
@@ -56,14 +190,14 @@ function useTable(options) {
|
|
|
56
190
|
}));
|
|
57
191
|
const stateRef = useRef(state);
|
|
58
192
|
stateRef.current = state;
|
|
59
|
-
const prevOptionsRef = useRef(
|
|
193
|
+
const prevOptionsRef = useRef(optionsWithDefaults);
|
|
60
194
|
const stableOptions = useMemo(() => {
|
|
61
|
-
if (shallowEqual(prevOptionsRef.current,
|
|
195
|
+
if (shallowEqual(prevOptionsRef.current, optionsWithDefaults)) {
|
|
62
196
|
return prevOptionsRef.current;
|
|
63
197
|
}
|
|
64
|
-
prevOptionsRef.current =
|
|
65
|
-
return
|
|
66
|
-
}, [
|
|
198
|
+
prevOptionsRef.current = optionsWithDefaults;
|
|
199
|
+
return optionsWithDefaults;
|
|
200
|
+
}, [optionsWithDefaults]);
|
|
67
201
|
const onStateChangeRef = useRef(options.onStateChange);
|
|
68
202
|
onStateChangeRef.current = options.onStateChange;
|
|
69
203
|
const resolvedState = useMemo(
|
|
@@ -73,17 +207,14 @@ function useTable(options) {
|
|
|
73
207
|
}),
|
|
74
208
|
[state, stableOptions.state]
|
|
75
209
|
);
|
|
76
|
-
const onStateChange = useCallback(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
[]
|
|
86
|
-
);
|
|
210
|
+
const onStateChange = useCallback((updater) => {
|
|
211
|
+
const latest = onStateChangeRef.current;
|
|
212
|
+
if (latest) {
|
|
213
|
+
latest(updater);
|
|
214
|
+
} else {
|
|
215
|
+
setState((prev) => functionalUpdate(updater, prev));
|
|
216
|
+
}
|
|
217
|
+
}, []);
|
|
87
218
|
const resolvedOptions = useMemo(
|
|
88
219
|
() => ({
|
|
89
220
|
...stableOptions,
|
|
@@ -96,13 +227,41 @@ function useTable(options) {
|
|
|
96
227
|
if (!tableRef.current) {
|
|
97
228
|
tableRef.current = createTable(resolvedOptions);
|
|
98
229
|
} else {
|
|
99
|
-
tableRef.current.setOptions(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
230
|
+
tableRef.current.setOptions(
|
|
231
|
+
(prev) => ({
|
|
232
|
+
...prev,
|
|
233
|
+
...resolvedOptions,
|
|
234
|
+
state: resolvedState,
|
|
235
|
+
onStateChange
|
|
236
|
+
})
|
|
237
|
+
);
|
|
105
238
|
}
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
const table = tableRef.current;
|
|
241
|
+
if (!table) return;
|
|
242
|
+
const unsubscribers = [
|
|
243
|
+
options.onCellClick && table.events.on("cell:click", options.onCellClick),
|
|
244
|
+
options.onCellDoubleClick && table.events.on("cell:dblclick", options.onCellDoubleClick),
|
|
245
|
+
options.onCellContextMenu && table.events.on("cell:contextmenu", options.onCellContextMenu),
|
|
246
|
+
options.onRowClick && table.events.on("row:click", options.onRowClick),
|
|
247
|
+
options.onRowDoubleClick && table.events.on("row:dblclick", options.onRowDoubleClick),
|
|
248
|
+
options.onRowContextMenu && table.events.on("row:contextmenu", options.onRowContextMenu),
|
|
249
|
+
options.onHeaderClick && table.events.on("header:click", options.onHeaderClick),
|
|
250
|
+
options.onHeaderContextMenu && table.events.on("header:contextmenu", options.onHeaderContextMenu)
|
|
251
|
+
].filter((unsubscribe) => Boolean(unsubscribe));
|
|
252
|
+
return () => {
|
|
253
|
+
unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
254
|
+
};
|
|
255
|
+
}, [
|
|
256
|
+
options.onCellClick,
|
|
257
|
+
options.onCellContextMenu,
|
|
258
|
+
options.onCellDoubleClick,
|
|
259
|
+
options.onHeaderClick,
|
|
260
|
+
options.onHeaderContextMenu,
|
|
261
|
+
options.onRowClick,
|
|
262
|
+
options.onRowContextMenu,
|
|
263
|
+
options.onRowDoubleClick
|
|
264
|
+
]);
|
|
106
265
|
useEffect(() => {
|
|
107
266
|
return () => {
|
|
108
267
|
if (tableRef.current) {
|
|
@@ -112,6 +271,311 @@ function useTable(options) {
|
|
|
112
271
|
}, []);
|
|
113
272
|
return tableRef.current;
|
|
114
273
|
}
|
|
274
|
+
function useServerTable({
|
|
275
|
+
fetchData,
|
|
276
|
+
updateRow,
|
|
277
|
+
initialRows = [],
|
|
278
|
+
initialCursor = null,
|
|
279
|
+
initialHasMore = true,
|
|
280
|
+
initialRowCount,
|
|
281
|
+
initialPageCount,
|
|
282
|
+
initialSorting = [],
|
|
283
|
+
initialColumnFilters = [],
|
|
284
|
+
initialGlobalFilter = "",
|
|
285
|
+
initialPagination = { pageIndex: 0, pageSize: 50 },
|
|
286
|
+
autoLoad = true,
|
|
287
|
+
getRowId,
|
|
288
|
+
...tableOptions
|
|
289
|
+
}) {
|
|
290
|
+
const [rows, setRows] = useState(initialRows);
|
|
291
|
+
const [cursor, setCursor] = useState(initialCursor);
|
|
292
|
+
const [hasMore, setHasMore] = useState(initialHasMore);
|
|
293
|
+
const [rowCount, setRowCount] = useState(initialRowCount);
|
|
294
|
+
const [pageCount, setPageCount] = useState(initialPageCount);
|
|
295
|
+
const [sorting, setSorting] = useState(initialSorting);
|
|
296
|
+
const [columnFilters, setColumnFilters] = useState(initialColumnFilters);
|
|
297
|
+
const [globalFilter, setGlobalFilter] = useState(initialGlobalFilter);
|
|
298
|
+
const [pagination, setPagination] = useState(initialPagination);
|
|
299
|
+
const [loading, setLoading] = useState(false);
|
|
300
|
+
const [error, setError] = useState(null);
|
|
301
|
+
const abortRef = useRef(null);
|
|
302
|
+
const cursorRef = useRef(cursor);
|
|
303
|
+
const fetchDataRef = useRef(fetchData);
|
|
304
|
+
const updateRowRef = useRef(updateRow);
|
|
305
|
+
const resolveRowId = useCallback(
|
|
306
|
+
(row, index) => getRowId?.(row, index) ?? String(row.id ?? index),
|
|
307
|
+
[getRowId]
|
|
308
|
+
);
|
|
309
|
+
const runFetch = useCallback(
|
|
310
|
+
async (mode) => {
|
|
311
|
+
abortRef.current?.abort();
|
|
312
|
+
const abort = new AbortController();
|
|
313
|
+
abortRef.current = abort;
|
|
314
|
+
setLoading(true);
|
|
315
|
+
setError(null);
|
|
316
|
+
try {
|
|
317
|
+
const result = await fetchDataRef.current({
|
|
318
|
+
sorting,
|
|
319
|
+
columnFilters,
|
|
320
|
+
globalFilter,
|
|
321
|
+
pagination,
|
|
322
|
+
cursor: mode === "append" ? cursorRef.current : null,
|
|
323
|
+
signal: abort.signal
|
|
324
|
+
});
|
|
325
|
+
if (abort.signal.aborted) return;
|
|
326
|
+
setRows((prev) => mode === "append" ? [...prev, ...result.rows] : result.rows);
|
|
327
|
+
setCursor(result.cursor ?? null);
|
|
328
|
+
setHasMore((prev) => result.hasMore ?? prev);
|
|
329
|
+
setRowCount((prev) => result.rowCount ?? prev);
|
|
330
|
+
setPageCount((prev) => result.pageCount ?? prev);
|
|
331
|
+
} catch (nextError) {
|
|
332
|
+
if (!abort.signal.aborted) setError(nextError);
|
|
333
|
+
} finally {
|
|
334
|
+
if (!abort.signal.aborted) setLoading(false);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
[columnFilters, globalFilter, pagination, sorting]
|
|
338
|
+
);
|
|
339
|
+
const refresh = useCallback(() => runFetch("replace"), [runFetch]);
|
|
340
|
+
const loadMore = useCallback(async () => {
|
|
341
|
+
if (!hasMore || loading) return;
|
|
342
|
+
await runFetch("append");
|
|
343
|
+
}, [hasMore, loading, runFetch]);
|
|
344
|
+
const patchRow = useCallback(
|
|
345
|
+
async (rowId, patch) => {
|
|
346
|
+
const previousRow = rows.find((row, index) => resolveRowId(row, index) === rowId);
|
|
347
|
+
setRows(
|
|
348
|
+
(prev) => prev.map((row, index) => resolveRowId(row, index) === rowId ? { ...row, ...patch } : row)
|
|
349
|
+
);
|
|
350
|
+
if (!updateRowRef.current) return;
|
|
351
|
+
const abort = new AbortController();
|
|
352
|
+
try {
|
|
353
|
+
const result = await updateRowRef.current({
|
|
354
|
+
rowId,
|
|
355
|
+
patch,
|
|
356
|
+
previousRow,
|
|
357
|
+
signal: abort.signal
|
|
358
|
+
});
|
|
359
|
+
if (!result) return;
|
|
360
|
+
setRows(
|
|
361
|
+
(prev) => prev.map(
|
|
362
|
+
(row, index) => resolveRowId(row, index) === rowId ? { ...row, ...result } : row
|
|
363
|
+
)
|
|
364
|
+
);
|
|
365
|
+
} catch (nextError) {
|
|
366
|
+
setError(nextError);
|
|
367
|
+
if (previousRow) {
|
|
368
|
+
setRows(
|
|
369
|
+
(prev) => prev.map((row, index) => resolveRowId(row, index) === rowId ? previousRow : row)
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
[resolveRowId, rows]
|
|
375
|
+
);
|
|
376
|
+
useEffect(() => {
|
|
377
|
+
fetchDataRef.current = fetchData;
|
|
378
|
+
}, [fetchData]);
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
updateRowRef.current = updateRow;
|
|
381
|
+
}, [updateRow]);
|
|
382
|
+
useEffect(() => {
|
|
383
|
+
if (!autoLoad) return;
|
|
384
|
+
void refresh();
|
|
385
|
+
}, [autoLoad, refresh]);
|
|
386
|
+
useEffect(() => {
|
|
387
|
+
cursorRef.current = cursor;
|
|
388
|
+
}, [cursor]);
|
|
389
|
+
useEffect(() => () => abortRef.current?.abort(), []);
|
|
390
|
+
const table = useTable({
|
|
391
|
+
...tableOptions,
|
|
392
|
+
data: rows,
|
|
393
|
+
getRowId: resolveRowId,
|
|
394
|
+
manualSorting: true,
|
|
395
|
+
manualFiltering: true,
|
|
396
|
+
manualPagination: true,
|
|
397
|
+
rowCount,
|
|
398
|
+
pageCount,
|
|
399
|
+
state: {
|
|
400
|
+
sorting,
|
|
401
|
+
columnFilters,
|
|
402
|
+
globalFilter,
|
|
403
|
+
pagination
|
|
404
|
+
},
|
|
405
|
+
onSortingChange: (updater) => {
|
|
406
|
+
setSorting((prev) => functionalUpdate(updater, prev));
|
|
407
|
+
setCursor(null);
|
|
408
|
+
setHasMore(true);
|
|
409
|
+
},
|
|
410
|
+
onColumnFiltersChange: (updater) => {
|
|
411
|
+
setColumnFilters((prev) => functionalUpdate(updater, prev));
|
|
412
|
+
setCursor(null);
|
|
413
|
+
setHasMore(true);
|
|
414
|
+
},
|
|
415
|
+
onGlobalFilterChange: (updater) => {
|
|
416
|
+
setGlobalFilter((prev) => functionalUpdate(updater, prev));
|
|
417
|
+
setCursor(null);
|
|
418
|
+
setHasMore(true);
|
|
419
|
+
},
|
|
420
|
+
onPaginationChange: (updater) => {
|
|
421
|
+
setPagination((prev) => functionalUpdate(updater, prev));
|
|
422
|
+
setCursor(null);
|
|
423
|
+
setHasMore(true);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
return useMemo(
|
|
427
|
+
() => ({
|
|
428
|
+
table,
|
|
429
|
+
rows,
|
|
430
|
+
loading,
|
|
431
|
+
error,
|
|
432
|
+
cursor,
|
|
433
|
+
hasMore,
|
|
434
|
+
rowCount,
|
|
435
|
+
pageCount,
|
|
436
|
+
sorting,
|
|
437
|
+
columnFilters,
|
|
438
|
+
globalFilter,
|
|
439
|
+
pagination,
|
|
440
|
+
refresh,
|
|
441
|
+
loadMore,
|
|
442
|
+
updateRow: patchRow
|
|
443
|
+
}),
|
|
444
|
+
[
|
|
445
|
+
table,
|
|
446
|
+
rows,
|
|
447
|
+
loading,
|
|
448
|
+
error,
|
|
449
|
+
cursor,
|
|
450
|
+
hasMore,
|
|
451
|
+
rowCount,
|
|
452
|
+
pageCount,
|
|
453
|
+
sorting,
|
|
454
|
+
columnFilters,
|
|
455
|
+
globalFilter,
|
|
456
|
+
pagination,
|
|
457
|
+
refresh,
|
|
458
|
+
loadMore,
|
|
459
|
+
patchRow
|
|
460
|
+
]
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
var DEFAULT_PERSISTED_KEYS = [
|
|
464
|
+
"columnVisibility",
|
|
465
|
+
"columnOrder",
|
|
466
|
+
"columnSizing",
|
|
467
|
+
"columnPinning"
|
|
468
|
+
];
|
|
469
|
+
function resolveStorage(custom) {
|
|
470
|
+
if (custom) return custom;
|
|
471
|
+
if (typeof window !== "undefined") {
|
|
472
|
+
try {
|
|
473
|
+
return window.localStorage;
|
|
474
|
+
} catch {
|
|
475
|
+
return void 0;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return void 0;
|
|
479
|
+
}
|
|
480
|
+
function pick(obj, keys) {
|
|
481
|
+
const result = {};
|
|
482
|
+
for (const k of keys) {
|
|
483
|
+
if (k in obj) {
|
|
484
|
+
result[k] = obj[k];
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
function readState(storage, key, version, persistedKeys) {
|
|
490
|
+
if (!storage) return {};
|
|
491
|
+
try {
|
|
492
|
+
const raw = storage.getItem(key);
|
|
493
|
+
if (!raw) return {};
|
|
494
|
+
const envelope = JSON.parse(raw);
|
|
495
|
+
if (envelope.version !== version) {
|
|
496
|
+
storage.removeItem(key);
|
|
497
|
+
return {};
|
|
498
|
+
}
|
|
499
|
+
return pick(envelope.state, persistedKeys);
|
|
500
|
+
} catch {
|
|
501
|
+
if (typeof console !== "undefined") {
|
|
502
|
+
console.warn(`[yable] Failed to read persisted state for key "${key}"`);
|
|
503
|
+
}
|
|
504
|
+
return {};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function writeState(storage, key, version, state) {
|
|
508
|
+
if (!storage) return;
|
|
509
|
+
try {
|
|
510
|
+
const envelope = { version, state };
|
|
511
|
+
storage.setItem(key, JSON.stringify(envelope));
|
|
512
|
+
} catch {
|
|
513
|
+
if (typeof console !== "undefined") {
|
|
514
|
+
console.warn(`[yable] Failed to persist state for key "${key}" (storage may be full)`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function useTablePersistence(options) {
|
|
519
|
+
const {
|
|
520
|
+
key,
|
|
521
|
+
persistedKeys = DEFAULT_PERSISTED_KEYS,
|
|
522
|
+
debounce: debounceMs = 100,
|
|
523
|
+
version = 0,
|
|
524
|
+
storage: customStorage
|
|
525
|
+
} = options;
|
|
526
|
+
const storage = useMemo(() => resolveStorage(customStorage), [customStorage]);
|
|
527
|
+
const initialState = useMemo(
|
|
528
|
+
() => readState(storage, key, version, persistedKeys),
|
|
529
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally read only on mount
|
|
530
|
+
[]
|
|
531
|
+
);
|
|
532
|
+
const [state, setState] = useState(initialState);
|
|
533
|
+
const timerRef = useRef(null);
|
|
534
|
+
const keyRef = useRef(key);
|
|
535
|
+
keyRef.current = key;
|
|
536
|
+
const versionRef = useRef(version);
|
|
537
|
+
versionRef.current = version;
|
|
538
|
+
const persistedKeysRef = useRef(persistedKeys);
|
|
539
|
+
persistedKeysRef.current = persistedKeys;
|
|
540
|
+
const debounceRef = useRef(debounceMs);
|
|
541
|
+
debounceRef.current = debounceMs;
|
|
542
|
+
const storageRef = useRef(storage);
|
|
543
|
+
storageRef.current = storage;
|
|
544
|
+
const onStateChange = useCallback((updater) => {
|
|
545
|
+
setState((prev) => {
|
|
546
|
+
const next = functionalUpdate(updater, prev);
|
|
547
|
+
if (timerRef.current !== null) {
|
|
548
|
+
clearTimeout(timerRef.current);
|
|
549
|
+
}
|
|
550
|
+
timerRef.current = setTimeout(() => {
|
|
551
|
+
const sliced = pick(
|
|
552
|
+
next,
|
|
553
|
+
persistedKeysRef.current
|
|
554
|
+
);
|
|
555
|
+
writeState(storageRef.current, keyRef.current, versionRef.current, sliced);
|
|
556
|
+
timerRef.current = null;
|
|
557
|
+
}, debounceRef.current);
|
|
558
|
+
return next;
|
|
559
|
+
});
|
|
560
|
+
}, []);
|
|
561
|
+
useEffect(() => {
|
|
562
|
+
return () => {
|
|
563
|
+
if (timerRef.current !== null) {
|
|
564
|
+
clearTimeout(timerRef.current);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}, []);
|
|
568
|
+
const clearPersistedState = useCallback(() => {
|
|
569
|
+
const s = storageRef.current;
|
|
570
|
+
if (s) {
|
|
571
|
+
try {
|
|
572
|
+
s.removeItem(keyRef.current);
|
|
573
|
+
} catch {
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}, []);
|
|
577
|
+
return { initialState, state, onStateChange, clearPersistedState };
|
|
578
|
+
}
|
|
115
579
|
var EMPTY_RESULT = {
|
|
116
580
|
virtualRows: [],
|
|
117
581
|
totalHeight: 0,
|
|
@@ -125,11 +589,14 @@ function useVirtualization({
|
|
|
125
589
|
overscan = 5,
|
|
126
590
|
estimateRowHeight: _estimateRowHeight,
|
|
127
591
|
pretextHeights,
|
|
128
|
-
pretextPrefixSums
|
|
592
|
+
pretextPrefixSums,
|
|
593
|
+
columnSizingHash
|
|
129
594
|
}) {
|
|
130
595
|
const hasPretextHeights = !!(pretextHeights && pretextPrefixSums && pretextHeights.length >= totalRows);
|
|
131
596
|
const isFixedHeight = typeof rowHeight === "number" && !hasPretextHeights;
|
|
132
597
|
const heightCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
598
|
+
const heightCacheVersionRef = useRef(0);
|
|
599
|
+
const [heightCacheVersion, setHeightCacheVersion] = useState(0);
|
|
133
600
|
const getRowHeight = useCallback(
|
|
134
601
|
(index) => {
|
|
135
602
|
if (hasPretextHeights) return pretextHeights[index];
|
|
@@ -140,7 +607,9 @@ function useVirtualization({
|
|
|
140
607
|
heightCacheRef.current.set(index, height);
|
|
141
608
|
return height;
|
|
142
609
|
},
|
|
143
|
-
|
|
610
|
+
// heightCacheVersion forces a new callback identity after cache invalidation
|
|
611
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
612
|
+
[rowHeight, isFixedHeight, hasPretextHeights, pretextHeights, heightCacheVersion]
|
|
144
613
|
);
|
|
145
614
|
const [scrollState, setScrollState] = useState({ scrollTop: 0, containerHeight: 0 });
|
|
146
615
|
const rafRef = useRef(null);
|
|
@@ -187,12 +656,24 @@ function useVirtualization({
|
|
|
187
656
|
resizeObserver.disconnect();
|
|
188
657
|
}
|
|
189
658
|
};
|
|
190
|
-
}, [containerRef]);
|
|
659
|
+
}, [containerRef, totalRows]);
|
|
191
660
|
useEffect(() => {
|
|
192
661
|
if (!isFixedHeight) {
|
|
193
662
|
heightCacheRef.current.clear();
|
|
194
663
|
}
|
|
195
664
|
}, [totalRows, isFixedHeight]);
|
|
665
|
+
useEffect(() => {
|
|
666
|
+
if (!isFixedHeight && columnSizingHash !== void 0) {
|
|
667
|
+
heightCacheRef.current.clear();
|
|
668
|
+
heightCacheVersionRef.current += 1;
|
|
669
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
670
|
+
}
|
|
671
|
+
}, [columnSizingHash]);
|
|
672
|
+
const invalidateRowHeights = useCallback(() => {
|
|
673
|
+
heightCacheRef.current.clear();
|
|
674
|
+
heightCacheVersionRef.current += 1;
|
|
675
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
676
|
+
}, []);
|
|
196
677
|
const scrollTo = useCallback(
|
|
197
678
|
(index) => {
|
|
198
679
|
const container = containerRef.current;
|
|
@@ -229,10 +710,18 @@ function useVirtualization({
|
|
|
229
710
|
total += getRowHeight(i);
|
|
230
711
|
}
|
|
231
712
|
return total;
|
|
232
|
-
}, [
|
|
713
|
+
}, [
|
|
714
|
+
totalRows,
|
|
715
|
+
rowHeight,
|
|
716
|
+
isFixedHeight,
|
|
717
|
+
getRowHeight,
|
|
718
|
+
hasPretextHeights,
|
|
719
|
+
pretextPrefixSums,
|
|
720
|
+
heightCacheVersion
|
|
721
|
+
]);
|
|
233
722
|
const { scrollTop, containerHeight } = scrollState;
|
|
234
723
|
if (totalRows === 0) {
|
|
235
|
-
return { ...EMPTY_RESULT, scrollTo };
|
|
724
|
+
return { ...EMPTY_RESULT, scrollTo, invalidateRowHeights };
|
|
236
725
|
}
|
|
237
726
|
if (containerHeight === 0) {
|
|
238
727
|
return {
|
|
@@ -240,7 +729,8 @@ function useVirtualization({
|
|
|
240
729
|
totalHeight,
|
|
241
730
|
startIndex: 0,
|
|
242
731
|
endIndex: 0,
|
|
243
|
-
scrollTo
|
|
732
|
+
scrollTo,
|
|
733
|
+
invalidateRowHeights
|
|
244
734
|
};
|
|
245
735
|
}
|
|
246
736
|
let startIndex = 0;
|
|
@@ -336,7 +826,8 @@ function useVirtualization({
|
|
|
336
826
|
totalHeight,
|
|
337
827
|
startIndex: overscanStart,
|
|
338
828
|
endIndex: overscanEnd,
|
|
339
|
-
scrollTo
|
|
829
|
+
scrollTo,
|
|
830
|
+
invalidateRowHeights
|
|
340
831
|
};
|
|
341
832
|
}
|
|
342
833
|
function binarySearchOffsets(offsets, target) {
|
|
@@ -356,14 +847,20 @@ function useColumnVirtualization({
|
|
|
356
847
|
containerRef,
|
|
357
848
|
columns,
|
|
358
849
|
overscan = 2,
|
|
359
|
-
enabled = true
|
|
850
|
+
enabled = true,
|
|
851
|
+
sizingKey
|
|
360
852
|
}) {
|
|
361
853
|
const [scrollState, setScrollState] = useState({
|
|
362
854
|
scrollLeft: 0,
|
|
363
855
|
containerWidth: 0
|
|
364
856
|
});
|
|
365
857
|
const rafRef = useRef(null);
|
|
366
|
-
const sizes = useMemo(
|
|
858
|
+
const sizes = useMemo(
|
|
859
|
+
() => columns.map((column) => column.getSize()),
|
|
860
|
+
// `sizingKey` is an explicit invalidation hook for stable Column objects whose getSize value changed.
|
|
861
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
862
|
+
[columns, sizingKey]
|
|
863
|
+
);
|
|
367
864
|
const offsets = useMemo(() => {
|
|
368
865
|
const next = new Array(columns.length + 1);
|
|
369
866
|
next[0] = 0;
|
|
@@ -941,12 +1438,12 @@ function getRegisteredCellTypes() {
|
|
|
941
1438
|
|
|
942
1439
|
// src/hooks/useAutoMeasurements.ts
|
|
943
1440
|
var NON_DATA_COLUMN_IDS = /* @__PURE__ */ new Set(["select", "expand", "drag", "actions"]);
|
|
944
|
-
function
|
|
1441
|
+
function getColumnId2(col) {
|
|
945
1442
|
const id = col.id ?? col.accessorKey;
|
|
946
1443
|
return typeof id === "string" ? id : void 0;
|
|
947
1444
|
}
|
|
948
1445
|
function defaultShouldMeasure(col) {
|
|
949
|
-
const id =
|
|
1446
|
+
const id = getColumnId2(col);
|
|
950
1447
|
if (!id) return false;
|
|
951
1448
|
if (id.startsWith("_")) return false;
|
|
952
1449
|
if (NON_DATA_COLUMN_IDS.has(id)) return false;
|
|
@@ -971,11 +1468,11 @@ function useAutoMeasurements({
|
|
|
971
1468
|
getColumnWidth = defaultGetColumnWidth,
|
|
972
1469
|
shouldMeasureColumn = defaultShouldMeasure
|
|
973
1470
|
}) {
|
|
974
|
-
const widthKey = columns.map((c) => `${
|
|
1471
|
+
const widthKey = columns.map((c) => `${getColumnId2(c) ?? "?"}:${getColumnWidth(c)}`).join("|");
|
|
975
1472
|
return useMemo(() => {
|
|
976
1473
|
const result = [];
|
|
977
1474
|
for (const col of columns) {
|
|
978
|
-
const id =
|
|
1475
|
+
const id = getColumnId2(col);
|
|
979
1476
|
if (!id) continue;
|
|
980
1477
|
if (!shouldMeasureColumn(col)) continue;
|
|
981
1478
|
const recipe = resolveMeasureRecipe(col, defaultRecipe);
|
|
@@ -1294,16 +1791,170 @@ function FloatingFilter({ column }) {
|
|
|
1294
1791
|
}
|
|
1295
1792
|
) });
|
|
1296
1793
|
}
|
|
1297
|
-
var
|
|
1794
|
+
var REORDER_TRANSITION = "transform 180ms cubic-bezier(0.2, 0, 0, 1)";
|
|
1795
|
+
function transformAt(i, d) {
|
|
1796
|
+
if (i === d.fromIndex) return 0;
|
|
1797
|
+
if (d.toIndex > d.fromIndex) return i > d.fromIndex && i < d.toIndex ? -d.width : 0;
|
|
1798
|
+
return i >= d.toIndex && i < d.fromIndex ? d.width : 0;
|
|
1799
|
+
}
|
|
1298
1800
|
function TableHeader({
|
|
1299
1801
|
table,
|
|
1300
1802
|
floatingFilters = false
|
|
1301
1803
|
}) {
|
|
1302
1804
|
const headerGroups = table.getHeaderGroups();
|
|
1303
1805
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1806
|
+
const theadRef = useRef(null);
|
|
1807
|
+
const reorderEndRef = useRef(0);
|
|
1808
|
+
const [drag, setDrag] = useState(null);
|
|
1809
|
+
const commitReorder = useCallback(
|
|
1810
|
+
(d) => {
|
|
1811
|
+
if (d.toIndex === d.fromIndex || d.toIndex === d.fromIndex + 1) return;
|
|
1812
|
+
const order = table.getState().columnOrder;
|
|
1813
|
+
const base = order && order.length > 0 ? [...order] : d.layout.map((l) => l.id);
|
|
1814
|
+
const targetId = d.toIndex < d.layout.length ? d.layout[d.toIndex].id : null;
|
|
1815
|
+
const next = base.filter((id) => id !== d.columnId);
|
|
1816
|
+
let insertAt = targetId ? next.indexOf(targetId) : next.length;
|
|
1817
|
+
if (insertAt === -1) insertAt = next.length;
|
|
1818
|
+
next.splice(insertAt, 0, d.columnId);
|
|
1819
|
+
table.setColumnOrder(next);
|
|
1820
|
+
},
|
|
1821
|
+
[table]
|
|
1822
|
+
);
|
|
1823
|
+
const beginReorder = useCallback(
|
|
1824
|
+
(e, columnId) => {
|
|
1825
|
+
if (e.button !== 0) return;
|
|
1826
|
+
const thead = theadRef.current;
|
|
1827
|
+
if (!thead) return;
|
|
1828
|
+
const startX = e.clientX;
|
|
1829
|
+
const startY = e.clientY;
|
|
1830
|
+
const layout = [];
|
|
1831
|
+
let top = 0;
|
|
1832
|
+
let height = 0;
|
|
1833
|
+
for (const c of visibleColumns) {
|
|
1834
|
+
const th = thead.querySelector(`th[data-column-id="${CSS.escape(c.id)}"]`);
|
|
1835
|
+
if (!th) return;
|
|
1836
|
+
const r = th.getBoundingClientRect();
|
|
1837
|
+
layout.push({ id: c.id, left: r.left, width: r.width });
|
|
1838
|
+
if (c.id === columnId) {
|
|
1839
|
+
top = r.top;
|
|
1840
|
+
height = r.height;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
const fromIndex = layout.findIndex((l) => l.id === columnId);
|
|
1844
|
+
if (fromIndex < 0) return;
|
|
1845
|
+
const src = layout[fromIndex];
|
|
1846
|
+
const bodyRoot = thead.closest("table");
|
|
1847
|
+
const applyBody = (d) => {
|
|
1848
|
+
if (!bodyRoot) return;
|
|
1849
|
+
visibleColumns.forEach((col, i) => {
|
|
1850
|
+
if (col.getIsPinned()) return;
|
|
1851
|
+
const tx = transformAt(i, d);
|
|
1852
|
+
bodyRoot.querySelectorAll(`td[data-column-id="${CSS.escape(col.id)}"]`).forEach((td) => {
|
|
1853
|
+
td.style.transition = REORDER_TRANSITION;
|
|
1854
|
+
td.style.opacity = i === d.fromIndex ? "0" : "";
|
|
1855
|
+
td.style.transform = i !== d.fromIndex && tx ? `translateX(${tx}px)` : "";
|
|
1856
|
+
});
|
|
1857
|
+
});
|
|
1858
|
+
};
|
|
1859
|
+
const clearBody = () => {
|
|
1860
|
+
bodyRoot?.querySelectorAll("td[data-column-id]").forEach((td) => {
|
|
1861
|
+
td.style.transform = "";
|
|
1862
|
+
td.style.transition = "";
|
|
1863
|
+
td.style.opacity = "";
|
|
1864
|
+
});
|
|
1865
|
+
};
|
|
1866
|
+
let started = false;
|
|
1867
|
+
let latest = {
|
|
1868
|
+
columnId,
|
|
1869
|
+
fromIndex,
|
|
1870
|
+
toIndex: fromIndex,
|
|
1871
|
+
pointerX: startX,
|
|
1872
|
+
grabOffsetX: startX - src.left,
|
|
1873
|
+
width: src.width,
|
|
1874
|
+
top,
|
|
1875
|
+
height,
|
|
1876
|
+
layout
|
|
1877
|
+
};
|
|
1878
|
+
const computeToIndex = (x) => {
|
|
1879
|
+
let t = layout.findIndex((l) => x < l.left + l.width / 2);
|
|
1880
|
+
if (t === -1) t = layout.length;
|
|
1881
|
+
return t;
|
|
1882
|
+
};
|
|
1883
|
+
const onMove = (ev) => {
|
|
1884
|
+
if (!started) {
|
|
1885
|
+
if (Math.abs(ev.clientX - startX) < 4 && Math.abs(ev.clientY - startY) < 4) return;
|
|
1886
|
+
started = true;
|
|
1887
|
+
table.setColumnDragActive(true);
|
|
1888
|
+
document.body.style.userSelect = "none";
|
|
1889
|
+
document.body.style.cursor = "grabbing";
|
|
1890
|
+
}
|
|
1891
|
+
latest = { ...latest, pointerX: ev.clientX, toIndex: computeToIndex(ev.clientX) };
|
|
1892
|
+
setDrag(latest);
|
|
1893
|
+
applyBody(latest);
|
|
1894
|
+
};
|
|
1895
|
+
const finish = () => {
|
|
1896
|
+
window.removeEventListener("pointermove", onMove);
|
|
1897
|
+
window.removeEventListener("pointerup", finish);
|
|
1898
|
+
window.removeEventListener("pointercancel", finish);
|
|
1899
|
+
if (started) {
|
|
1900
|
+
commitReorder(latest);
|
|
1901
|
+
reorderEndRef.current = Date.now();
|
|
1902
|
+
table.setColumnDragActive(false);
|
|
1903
|
+
document.body.style.userSelect = "";
|
|
1904
|
+
document.body.style.cursor = "";
|
|
1905
|
+
clearBody();
|
|
1906
|
+
}
|
|
1907
|
+
setDrag(null);
|
|
1908
|
+
};
|
|
1909
|
+
window.addEventListener("pointermove", onMove);
|
|
1910
|
+
window.addEventListener("pointerup", finish);
|
|
1911
|
+
window.addEventListener("pointercancel", finish);
|
|
1912
|
+
},
|
|
1913
|
+
[visibleColumns, table, commitReorder]
|
|
1914
|
+
);
|
|
1915
|
+
const transformFor = useCallback(
|
|
1916
|
+
(columnId) => {
|
|
1917
|
+
if (!drag) return 0;
|
|
1918
|
+
const i = visibleColumns.findIndex((c) => c.id === columnId);
|
|
1919
|
+
if (i < 0) return 0;
|
|
1920
|
+
return transformAt(i, drag);
|
|
1921
|
+
},
|
|
1922
|
+
[drag, visibleColumns]
|
|
1923
|
+
);
|
|
1924
|
+
const dragColumn = drag ? visibleColumns.find((c) => c.id === drag.columnId) : null;
|
|
1925
|
+
return /* @__PURE__ */ jsxs("thead", { className: "yable-thead", ref: theadRef, children: [
|
|
1926
|
+
headerGroups.map((headerGroup) => /* @__PURE__ */ jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(
|
|
1927
|
+
HeaderCell,
|
|
1928
|
+
{
|
|
1929
|
+
header,
|
|
1930
|
+
table,
|
|
1931
|
+
onReorderPointerDown: beginReorder,
|
|
1932
|
+
dragTransform: transformFor(header.column.id),
|
|
1933
|
+
isDragSource: drag?.columnId === header.column.id,
|
|
1934
|
+
dragActive: drag !== null,
|
|
1935
|
+
reorderEndRef
|
|
1936
|
+
},
|
|
1937
|
+
header.id
|
|
1938
|
+
)) }, headerGroup.id)),
|
|
1939
|
+
floatingFilters && visibleColumns.length > 0 && /* @__PURE__ */ jsx("tr", { className: "yable-header-row yable-header-row--filters", children: visibleColumns.map((column) => /* @__PURE__ */ jsx(FloatingFilterCell, { column }, `${column.id}-filter`)) }),
|
|
1940
|
+
drag && dragColumn && typeof document !== "undefined" && createPortal(
|
|
1941
|
+
/* @__PURE__ */ jsx(
|
|
1942
|
+
"div",
|
|
1943
|
+
{
|
|
1944
|
+
className: "yable-col-drag-ghost",
|
|
1945
|
+
"aria-hidden": "true",
|
|
1946
|
+
style: {
|
|
1947
|
+
position: "fixed",
|
|
1948
|
+
top: drag.top,
|
|
1949
|
+
left: drag.pointerX - drag.grabOffsetX,
|
|
1950
|
+
width: drag.width,
|
|
1951
|
+
height: drag.height
|
|
1952
|
+
},
|
|
1953
|
+
children: typeof dragColumn.columnDef.header === "string" ? dragColumn.columnDef.header : dragColumn.id
|
|
1954
|
+
}
|
|
1955
|
+
),
|
|
1956
|
+
document.body
|
|
1957
|
+
)
|
|
1307
1958
|
] });
|
|
1308
1959
|
}
|
|
1309
1960
|
function FloatingFilterCell({
|
|
@@ -1332,7 +1983,12 @@ function FloatingFilterCell({
|
|
|
1332
1983
|
}
|
|
1333
1984
|
function HeaderCell({
|
|
1334
1985
|
header,
|
|
1335
|
-
table
|
|
1986
|
+
table,
|
|
1987
|
+
onReorderPointerDown,
|
|
1988
|
+
dragTransform,
|
|
1989
|
+
isDragSource,
|
|
1990
|
+
dragActive,
|
|
1991
|
+
reorderEndRef
|
|
1336
1992
|
}) {
|
|
1337
1993
|
const column = header.column;
|
|
1338
1994
|
const canSort = column.getCanSort();
|
|
@@ -1340,6 +1996,7 @@ function HeaderCell({
|
|
|
1340
1996
|
const sortIndex = column.getSortIndex();
|
|
1341
1997
|
const canResize = column.getCanResize();
|
|
1342
1998
|
const canReorder = column.getCanReorder() && !header.isPlaceholder;
|
|
1999
|
+
const pinned = column.getIsPinned();
|
|
1343
2000
|
const headerContent = header.isPlaceholder ? null : typeof column.columnDef.header === "function" ? column.columnDef.header(header.getContext()) : column.columnDef.header ?? header.id;
|
|
1344
2001
|
const style = useMemo(() => {
|
|
1345
2002
|
const s = {
|
|
@@ -1347,18 +2004,19 @@ function HeaderCell({
|
|
|
1347
2004
|
minWidth: column.columnDef.minSize,
|
|
1348
2005
|
maxWidth: column.columnDef.maxSize
|
|
1349
2006
|
};
|
|
1350
|
-
|
|
1351
|
-
if (pinned2) {
|
|
2007
|
+
if (pinned) {
|
|
1352
2008
|
s.position = "sticky";
|
|
1353
|
-
if (
|
|
2009
|
+
if (pinned === "left") {
|
|
1354
2010
|
s.left = header.getStart("left");
|
|
1355
2011
|
} else {
|
|
1356
2012
|
s.right = header.getStart("right");
|
|
1357
2013
|
}
|
|
1358
2014
|
}
|
|
2015
|
+
if (!pinned && !isDragSource && dragTransform !== 0) {
|
|
2016
|
+
s.transform = `translateX(${dragTransform}px)`;
|
|
2017
|
+
}
|
|
1359
2018
|
return s;
|
|
1360
|
-
}, [header, column]);
|
|
1361
|
-
const pinned = column.getIsPinned();
|
|
2019
|
+
}, [header, column, pinned, isDragSource, dragTransform]);
|
|
1362
2020
|
const lastResizeEndRef = useRef(0);
|
|
1363
2021
|
const startResize = useCallback(
|
|
1364
2022
|
(e) => {
|
|
@@ -1378,124 +2036,66 @@ function HeaderCell({
|
|
|
1378
2036
|
const handleResizeClick = useCallback((e) => {
|
|
1379
2037
|
e.stopPropagation();
|
|
1380
2038
|
}, []);
|
|
1381
|
-
const
|
|
1382
|
-
const handleDragStart = useCallback(
|
|
2039
|
+
const handleContentPointerDown = useCallback(
|
|
1383
2040
|
(e) => {
|
|
1384
|
-
if (!canReorder) return;
|
|
1385
|
-
|
|
1386
|
-
if (target && target.closest(".yable-resize-handle")) {
|
|
1387
|
-
e.preventDefault();
|
|
1388
|
-
return;
|
|
1389
|
-
}
|
|
1390
|
-
e.stopPropagation();
|
|
1391
|
-
e.dataTransfer.effectAllowed = "move";
|
|
1392
|
-
try {
|
|
1393
|
-
e.dataTransfer.setData(DRAG_MIME, column.id);
|
|
1394
|
-
e.dataTransfer.setData("text/plain", column.id);
|
|
1395
|
-
} catch {
|
|
1396
|
-
}
|
|
1397
|
-
},
|
|
1398
|
-
[canReorder, column.id]
|
|
1399
|
-
);
|
|
1400
|
-
const handleDragOver = useCallback(
|
|
1401
|
-
(e) => {
|
|
1402
|
-
if (!canReorder) return;
|
|
1403
|
-
const types = e.dataTransfer.types;
|
|
1404
|
-
let isYableDrag = false;
|
|
1405
|
-
for (let i = 0; i < types.length; i++) {
|
|
1406
|
-
if (types[i] === DRAG_MIME) {
|
|
1407
|
-
isYableDrag = true;
|
|
1408
|
-
break;
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
if (!isYableDrag) return;
|
|
1412
|
-
e.preventDefault();
|
|
1413
|
-
e.dataTransfer.dropEffect = "move";
|
|
1414
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
1415
|
-
const midpoint = rect.left + rect.width / 2;
|
|
1416
|
-
setDragOver(e.clientX < midpoint ? "left" : "right");
|
|
1417
|
-
},
|
|
1418
|
-
[canReorder]
|
|
1419
|
-
);
|
|
1420
|
-
const handleDragLeave = useCallback((e) => {
|
|
1421
|
-
const next = e.relatedTarget;
|
|
1422
|
-
if (next && e.currentTarget.contains(next)) return;
|
|
1423
|
-
setDragOver(null);
|
|
1424
|
-
}, []);
|
|
1425
|
-
const handleDragEnd = useCallback(() => {
|
|
1426
|
-
setDragOver(null);
|
|
1427
|
-
}, []);
|
|
1428
|
-
const handleDrop = useCallback(
|
|
1429
|
-
(e) => {
|
|
1430
|
-
if (!canReorder) return;
|
|
1431
|
-
e.preventDefault();
|
|
1432
|
-
e.stopPropagation();
|
|
1433
|
-
const sourceId = e.dataTransfer.getData(DRAG_MIME);
|
|
1434
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
1435
|
-
const insertAfter = e.clientX >= rect.left + rect.width / 2;
|
|
1436
|
-
setDragOver(null);
|
|
1437
|
-
if (!sourceId || sourceId === column.id) return;
|
|
1438
|
-
const state = table.getState();
|
|
1439
|
-
const allLeafs = table.getAllLeafColumns();
|
|
1440
|
-
const baseOrder = state.columnOrder && state.columnOrder.length > 0 ? state.columnOrder : allLeafs.map((c) => c.id);
|
|
1441
|
-
const next = [];
|
|
1442
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1443
|
-
for (const id of baseOrder) {
|
|
1444
|
-
if (allLeafs.some((c) => c.id === id)) {
|
|
1445
|
-
next.push(id);
|
|
1446
|
-
seen.add(id);
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
for (const c of allLeafs) {
|
|
1450
|
-
if (!seen.has(c.id)) {
|
|
1451
|
-
next.push(c.id);
|
|
1452
|
-
seen.add(c.id);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
const fromIdx = next.indexOf(sourceId);
|
|
1456
|
-
if (fromIdx === -1) return;
|
|
1457
|
-
next.splice(fromIdx, 1);
|
|
1458
|
-
let toIdx = next.indexOf(column.id);
|
|
1459
|
-
if (toIdx === -1) return;
|
|
1460
|
-
if (insertAfter) toIdx += 1;
|
|
1461
|
-
next.splice(toIdx, 0, sourceId);
|
|
1462
|
-
table.setColumnOrder(next);
|
|
2041
|
+
if (!canReorder || pinned) return;
|
|
2042
|
+
onReorderPointerDown(e, column.id);
|
|
1463
2043
|
},
|
|
1464
|
-
[canReorder, column.id
|
|
2044
|
+
[canReorder, pinned, onReorderPointerDown, column.id]
|
|
1465
2045
|
);
|
|
1466
2046
|
const handleHeaderClick = useCallback(
|
|
1467
2047
|
(e) => {
|
|
2048
|
+
table.events.emit("header:click", {
|
|
2049
|
+
column,
|
|
2050
|
+
header,
|
|
2051
|
+
originalEvent: e
|
|
2052
|
+
});
|
|
1468
2053
|
if (!canSort) return;
|
|
1469
2054
|
if (Date.now() - lastResizeEndRef.current < 250) return;
|
|
2055
|
+
if (Date.now() - reorderEndRef.current < 250) return;
|
|
1470
2056
|
const handler = column.getToggleSortingHandler();
|
|
1471
2057
|
if (handler) handler(e);
|
|
1472
2058
|
},
|
|
1473
|
-
[canSort, column]
|
|
2059
|
+
[canSort, column, header, table.events, reorderEndRef]
|
|
2060
|
+
);
|
|
2061
|
+
const handleHeaderContextMenu = useCallback(
|
|
2062
|
+
(e) => {
|
|
2063
|
+
table.events.emit("header:contextmenu", {
|
|
2064
|
+
column,
|
|
2065
|
+
header,
|
|
2066
|
+
originalEvent: e
|
|
2067
|
+
});
|
|
2068
|
+
},
|
|
2069
|
+
[column, header, table.events]
|
|
1474
2070
|
);
|
|
1475
2071
|
return /* @__PURE__ */ jsxs(
|
|
1476
2072
|
"th",
|
|
1477
2073
|
{
|
|
1478
2074
|
className: "yable-th",
|
|
1479
2075
|
style,
|
|
2076
|
+
"data-column-id": column.id,
|
|
1480
2077
|
"data-sortable": canSort || void 0,
|
|
1481
2078
|
"data-pinned": pinned || void 0,
|
|
1482
|
-
"data-reorderable": canReorder || void 0,
|
|
1483
|
-
"data-
|
|
2079
|
+
"data-reorderable": canReorder && !pinned || void 0,
|
|
2080
|
+
"data-reordering": dragActive && !pinned || void 0,
|
|
2081
|
+
"data-drag-source": isDragSource || void 0,
|
|
1484
2082
|
"aria-sort": sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : canSort ? "none" : void 0,
|
|
1485
2083
|
role: "columnheader",
|
|
1486
2084
|
colSpan: header.colSpan,
|
|
1487
|
-
draggable: canReorder || void 0,
|
|
1488
2085
|
onClick: handleHeaderClick,
|
|
1489
|
-
|
|
1490
|
-
onDragOver: canReorder ? handleDragOver : void 0,
|
|
1491
|
-
onDragLeave: canReorder ? handleDragLeave : void 0,
|
|
1492
|
-
onDragEnd: canReorder ? handleDragEnd : void 0,
|
|
1493
|
-
onDrop: canReorder ? handleDrop : void 0,
|
|
2086
|
+
onContextMenu: handleHeaderContextMenu,
|
|
1494
2087
|
children: [
|
|
1495
|
-
/* @__PURE__ */ jsxs(
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
2088
|
+
/* @__PURE__ */ jsxs(
|
|
2089
|
+
"div",
|
|
2090
|
+
{
|
|
2091
|
+
className: "yable-th-content",
|
|
2092
|
+
onPointerDown: canReorder && !pinned ? handleContentPointerDown : void 0,
|
|
2093
|
+
children: [
|
|
2094
|
+
/* @__PURE__ */ jsx("span", { children: headerContent }),
|
|
2095
|
+
canSort && /* @__PURE__ */ jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
|
|
2096
|
+
]
|
|
2097
|
+
}
|
|
2098
|
+
),
|
|
1499
2099
|
canResize && /* @__PURE__ */ jsx(
|
|
1500
2100
|
"div",
|
|
1501
2101
|
{
|
|
@@ -1503,9 +2103,7 @@ function HeaderCell({
|
|
|
1503
2103
|
"data-resizing": column.getIsResizing() || void 0,
|
|
1504
2104
|
onMouseDown: startResize,
|
|
1505
2105
|
onTouchStart: startResize,
|
|
1506
|
-
onClick: handleResizeClick
|
|
1507
|
-
draggable: false,
|
|
1508
|
-
onDragStart: (e) => e.preventDefault()
|
|
2106
|
+
onClick: handleResizeClick
|
|
1509
2107
|
}
|
|
1510
2108
|
)
|
|
1511
2109
|
]
|
|
@@ -1603,6 +2201,7 @@ function TableCell({
|
|
|
1603
2201
|
const isAlwaysEditable = cell.getIsAlwaysEditable();
|
|
1604
2202
|
const pinned = column.getIsPinned();
|
|
1605
2203
|
const keyboardNavigationEnabled = table.options.enableKeyboardNavigation !== false;
|
|
2204
|
+
const cellSelectionEnabled = table.options.enableCellSelection !== false && column.columnDef.enableCellSelection !== false;
|
|
1606
2205
|
const style = {
|
|
1607
2206
|
width: column.getSize(),
|
|
1608
2207
|
minWidth: column.columnDef.minSize,
|
|
@@ -1687,6 +2286,7 @@ function TableCell({
|
|
|
1687
2286
|
const handleMouseDown = useCallback(
|
|
1688
2287
|
(e) => {
|
|
1689
2288
|
if (e.button !== 0) return;
|
|
2289
|
+
if (!cellSelectionEnabled) return;
|
|
1690
2290
|
const clickTarget = e.target;
|
|
1691
2291
|
if (isInteractiveClickTarget(clickTarget)) return;
|
|
1692
2292
|
e.preventDefault();
|
|
@@ -1694,16 +2294,22 @@ function TableCell({
|
|
|
1694
2294
|
table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
|
|
1695
2295
|
e.currentTarget.focus({ preventScroll: true });
|
|
1696
2296
|
},
|
|
1697
|
-
[columnIndex, rowIndex, table]
|
|
2297
|
+
[cellSelectionEnabled, columnIndex, rowIndex, table]
|
|
1698
2298
|
);
|
|
1699
2299
|
const handleMouseEnter = useCallback(() => {
|
|
2300
|
+
if (!cellSelectionEnabled) return;
|
|
1700
2301
|
if (!table.getState().cellSelection?.isDragging) return;
|
|
1701
2302
|
table.updateCellRangeSelection({ rowIndex, columnIndex });
|
|
1702
|
-
}, [columnIndex, rowIndex, table]);
|
|
2303
|
+
}, [cellSelectionEnabled, columnIndex, rowIndex, table]);
|
|
1703
2304
|
const handleMouseUp = useCallback(() => {
|
|
1704
2305
|
if (!table.getState().cellSelection?.isDragging) return;
|
|
1705
2306
|
table.endCellRangeSelection();
|
|
1706
2307
|
}, [table]);
|
|
2308
|
+
const cellClassNameDef = column.columnDef.cellClassName;
|
|
2309
|
+
const userClassName = typeof cellClassNameDef === "function" ? cellClassNameDef(cell.getContext()) : cellClassNameDef;
|
|
2310
|
+
const cellStyleDef = column.columnDef.cellStyle;
|
|
2311
|
+
const userStyle = typeof cellStyleDef === "function" ? cellStyleDef(cell.getContext()) : cellStyleDef;
|
|
2312
|
+
const mergedStyle = userStyle ? { ...style, ...userStyle } : style;
|
|
1707
2313
|
const classNames = [
|
|
1708
2314
|
"yable-td",
|
|
1709
2315
|
isFocused && "yable-cell--focused",
|
|
@@ -1711,13 +2317,14 @@ function TableCell({
|
|
|
1711
2317
|
selectionEdges?.top && "yable-cell--selection-top",
|
|
1712
2318
|
selectionEdges?.right && "yable-cell--selection-right",
|
|
1713
2319
|
selectionEdges?.bottom && "yable-cell--selection-bottom",
|
|
1714
|
-
selectionEdges?.left && "yable-cell--selection-left"
|
|
2320
|
+
selectionEdges?.left && "yable-cell--selection-left",
|
|
2321
|
+
userClassName
|
|
1715
2322
|
].filter(Boolean).join(" ");
|
|
1716
2323
|
return /* @__PURE__ */ jsxs(
|
|
1717
2324
|
"td",
|
|
1718
2325
|
{
|
|
1719
2326
|
className: classNames,
|
|
1720
|
-
style,
|
|
2327
|
+
style: mergedStyle,
|
|
1721
2328
|
"data-editing": isEditing || void 0,
|
|
1722
2329
|
"data-focused": isFocused || void 0,
|
|
1723
2330
|
"data-pinned": pinned || void 0,
|
|
@@ -1857,7 +2464,38 @@ var CellErrorBoundary = class extends React3.Component {
|
|
|
1857
2464
|
return this.props.children;
|
|
1858
2465
|
}
|
|
1859
2466
|
};
|
|
1860
|
-
function
|
|
2467
|
+
function MasterDetail({
|
|
2468
|
+
row,
|
|
2469
|
+
table,
|
|
2470
|
+
colSpan,
|
|
2471
|
+
renderDetailPanel,
|
|
2472
|
+
animationClass
|
|
2473
|
+
}) {
|
|
2474
|
+
const renderer = renderDetailPanel ?? table.options.renderDetailPanel;
|
|
2475
|
+
if (!renderer) return null;
|
|
2476
|
+
const content = renderer(row);
|
|
2477
|
+
if (content == null) return null;
|
|
2478
|
+
const classes = [
|
|
2479
|
+
"yable-detail-row",
|
|
2480
|
+
"yable-detail-row--animated",
|
|
2481
|
+
animationClass
|
|
2482
|
+
].filter(Boolean).join(" ");
|
|
2483
|
+
return /* @__PURE__ */ jsx(
|
|
2484
|
+
"tr",
|
|
2485
|
+
{
|
|
2486
|
+
className: classes,
|
|
2487
|
+
"data-detail-for": row.id,
|
|
2488
|
+
role: "row",
|
|
2489
|
+
"aria-label": `Details for row ${row.id}`,
|
|
2490
|
+
children: /* @__PURE__ */ jsx("td", { className: "yable-detail-cell", colSpan, role: "cell", children: /* @__PURE__ */ jsx("div", { className: "yable-detail-panel", children: /* @__PURE__ */ jsx("div", { className: "yable-detail-panel-inner", children: content }) }) })
|
|
2491
|
+
}
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
function TableBody({
|
|
2495
|
+
table,
|
|
2496
|
+
clickableRows,
|
|
2497
|
+
colgroup
|
|
2498
|
+
}) {
|
|
1861
2499
|
const rows = table.getRowModel().rows;
|
|
1862
2500
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1863
2501
|
const activeCell = table.getState().editing.activeCell;
|
|
@@ -1866,6 +2504,7 @@ function TableBody({ table, clickableRows }) {
|
|
|
1866
2504
|
range: null,
|
|
1867
2505
|
isDragging: false
|
|
1868
2506
|
};
|
|
2507
|
+
const pendingValues = table.getState().editing.pendingValues ?? {};
|
|
1869
2508
|
const options = table.options;
|
|
1870
2509
|
const enableVirtualization = options.enableVirtualization ?? false;
|
|
1871
2510
|
const scrollContainerRef = useRef(null);
|
|
@@ -1874,6 +2513,19 @@ function TableBody({ table, clickableRows }) {
|
|
|
1874
2513
|
const estimateRowHeight = options.estimateRowHeight;
|
|
1875
2514
|
const pretextHeights = options.pretextHeights ?? null;
|
|
1876
2515
|
const pretextPrefixSums = options.pretextPrefixSums ?? null;
|
|
2516
|
+
const columnSizing = table.getState().columnSizing;
|
|
2517
|
+
const columnSizingHash = useMemo(() => {
|
|
2518
|
+
const entries = Object.entries(columnSizing);
|
|
2519
|
+
if (entries.length === 0) return 0;
|
|
2520
|
+
let h = 0;
|
|
2521
|
+
for (const [key, value] of entries) {
|
|
2522
|
+
for (let i = 0; i < key.length; i++) {
|
|
2523
|
+
h = h * 31 + key.charCodeAt(i) | 0;
|
|
2524
|
+
}
|
|
2525
|
+
h = h * 31 + (value | 0) | 0;
|
|
2526
|
+
}
|
|
2527
|
+
return h;
|
|
2528
|
+
}, [columnSizing]);
|
|
1877
2529
|
const { virtualRows, totalHeight } = useVirtualization({
|
|
1878
2530
|
containerRef: scrollContainerRef,
|
|
1879
2531
|
totalRows: rows.length,
|
|
@@ -1881,7 +2533,8 @@ function TableBody({ table, clickableRows }) {
|
|
|
1881
2533
|
overscan,
|
|
1882
2534
|
estimateRowHeight,
|
|
1883
2535
|
pretextHeights,
|
|
1884
|
-
pretextPrefixSums
|
|
2536
|
+
pretextPrefixSums,
|
|
2537
|
+
columnSizingHash
|
|
1885
2538
|
});
|
|
1886
2539
|
const cellSelectionKey = cellSelection.range ? `${cellSelection.range.start.rowIndex}:${cellSelection.range.start.columnIndex}:${cellSelection.range.end.rowIndex}:${cellSelection.range.end.columnIndex}:${cellSelection.isDragging ? "dragging" : "idle"}` : `none:${cellSelection.isDragging ? "dragging" : "idle"}`;
|
|
1887
2540
|
useEffect(() => {
|
|
@@ -1895,24 +2548,40 @@ function TableBody({ table, clickableRows }) {
|
|
|
1895
2548
|
window.removeEventListener("mouseup", handleWindowMouseUp);
|
|
1896
2549
|
};
|
|
1897
2550
|
}, [table]);
|
|
2551
|
+
const renderRow = (row, rowIndex, pinnedPosition) => /* @__PURE__ */ jsx(
|
|
2552
|
+
MemoizedTableRow,
|
|
2553
|
+
{
|
|
2554
|
+
row,
|
|
2555
|
+
table,
|
|
2556
|
+
rowIndex,
|
|
2557
|
+
visibleColumns,
|
|
2558
|
+
isSelected: row.getIsSelected(),
|
|
2559
|
+
isExpanded: row.getIsExpanded(),
|
|
2560
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
2561
|
+
focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
|
|
2562
|
+
hasFocusedCell: focusedCell !== null,
|
|
2563
|
+
cellSelectionKey,
|
|
2564
|
+
pendingValuesKey: getPendingValuesKey(pendingValues[row.id]),
|
|
2565
|
+
clickable: clickableRows,
|
|
2566
|
+
pinnedPosition
|
|
2567
|
+
},
|
|
2568
|
+
row.id
|
|
2569
|
+
);
|
|
1898
2570
|
if (!enableVirtualization) {
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
},
|
|
1914
|
-
row.id
|
|
1915
|
-
)) });
|
|
2571
|
+
const rowPinning = table.getState().rowPinning;
|
|
2572
|
+
const hasPinnedRows = (rowPinning.top?.length ?? 0) > 0 || (rowPinning.bottom?.length ?? 0) > 0;
|
|
2573
|
+
if (hasPinnedRows) {
|
|
2574
|
+
const topRows = table.getTopRows();
|
|
2575
|
+
const centerRows = table.getCenterRows();
|
|
2576
|
+
const bottomRows = table.getBottomRows();
|
|
2577
|
+
let visualIndex = 0;
|
|
2578
|
+
return /* @__PURE__ */ jsxs("tbody", { className: "yable-tbody", children: [
|
|
2579
|
+
topRows.map((row) => renderRow(row, visualIndex++, "top")),
|
|
2580
|
+
centerRows.map((row) => renderRow(row, visualIndex++)),
|
|
2581
|
+
bottomRows.map((row) => renderRow(row, visualIndex++, "bottom"))
|
|
2582
|
+
] });
|
|
2583
|
+
}
|
|
2584
|
+
return /* @__PURE__ */ jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => renderRow(row, rowIndex)) });
|
|
1916
2585
|
}
|
|
1917
2586
|
const hasPretextData = !!(pretextHeights && pretextPrefixSums);
|
|
1918
2587
|
const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
|
|
@@ -1932,7 +2601,7 @@ function TableBody({ table, clickableRows }) {
|
|
|
1932
2601
|
{
|
|
1933
2602
|
className: "yable-virtual-spacer",
|
|
1934
2603
|
style: { height: totalHeight, position: "relative" },
|
|
1935
|
-
children: /* @__PURE__ */
|
|
2604
|
+
children: /* @__PURE__ */ jsxs(
|
|
1936
2605
|
"table",
|
|
1937
2606
|
{
|
|
1938
2607
|
style: {
|
|
@@ -1943,35 +2612,39 @@ function TableBody({ table, clickableRows }) {
|
|
|
1943
2612
|
tableLayout: "fixed",
|
|
1944
2613
|
borderCollapse: "collapse"
|
|
1945
2614
|
},
|
|
1946
|
-
children:
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2615
|
+
children: [
|
|
2616
|
+
colgroup,
|
|
2617
|
+
/* @__PURE__ */ jsx("tbody", { children: virtualRows.map((vRow) => {
|
|
2618
|
+
const row = rows[vRow.index];
|
|
2619
|
+
if (!row) return null;
|
|
2620
|
+
return /* @__PURE__ */ jsx(
|
|
2621
|
+
MemoizedTableRow,
|
|
2622
|
+
{
|
|
2623
|
+
row,
|
|
2624
|
+
table,
|
|
2625
|
+
rowIndex: vRow.index,
|
|
2626
|
+
visibleColumns,
|
|
2627
|
+
isSelected: row.getIsSelected(),
|
|
2628
|
+
isExpanded: row.getIsExpanded(),
|
|
2629
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
2630
|
+
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
2631
|
+
hasFocusedCell: focusedCell !== null,
|
|
2632
|
+
cellSelectionKey,
|
|
2633
|
+
pendingValuesKey: getPendingValuesKey(pendingValues[row.id]),
|
|
2634
|
+
clickable: clickableRows,
|
|
2635
|
+
virtualStyle: {
|
|
2636
|
+
position: "absolute",
|
|
2637
|
+
top: 0,
|
|
2638
|
+
left: 0,
|
|
2639
|
+
width: "100%",
|
|
2640
|
+
height: vRow.size,
|
|
2641
|
+
transform: `translateY(${vRow.start}px)`
|
|
2642
|
+
}
|
|
2643
|
+
},
|
|
2644
|
+
row.id
|
|
2645
|
+
);
|
|
2646
|
+
}) })
|
|
2647
|
+
]
|
|
1975
2648
|
}
|
|
1976
2649
|
)
|
|
1977
2650
|
}
|
|
@@ -1990,13 +2663,18 @@ function TableRowInner({
|
|
|
1990
2663
|
focusedColumnIndex,
|
|
1991
2664
|
hasFocusedCell,
|
|
1992
2665
|
cellSelectionKey: _cellSelectionKey,
|
|
2666
|
+
pendingValuesKey: _pendingValuesKey,
|
|
1993
2667
|
clickable,
|
|
2668
|
+
pinnedPosition,
|
|
1994
2669
|
virtualStyle
|
|
1995
2670
|
}) {
|
|
1996
2671
|
const allCells = row.getAllCells();
|
|
1997
2672
|
const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
|
|
1998
2673
|
const handleClick = useCallback(
|
|
1999
2674
|
(e) => {
|
|
2675
|
+
if (table.options.enableRowClickSelection && row.getCanSelect() && !isInteractiveClickTarget2(e.target)) {
|
|
2676
|
+
row.toggleSelected();
|
|
2677
|
+
}
|
|
2000
2678
|
if (clickable) {
|
|
2001
2679
|
table.events.emit("row:click", {
|
|
2002
2680
|
row,
|
|
@@ -2004,7 +2682,7 @@ function TableRowInner({
|
|
|
2004
2682
|
});
|
|
2005
2683
|
}
|
|
2006
2684
|
},
|
|
2007
|
-
[clickable, table
|
|
2685
|
+
[clickable, table, row]
|
|
2008
2686
|
);
|
|
2009
2687
|
const handleDoubleClick = useCallback(
|
|
2010
2688
|
(e) => {
|
|
@@ -2026,15 +2704,26 @@ function TableRowInner({
|
|
|
2026
2704
|
);
|
|
2027
2705
|
const selectionEnabled = Boolean(table.options.enableRowSelection);
|
|
2028
2706
|
const expansionEnabled = Boolean(table.options.enableExpanding);
|
|
2707
|
+
const rowClassNameDef = table.options.rowClassName;
|
|
2708
|
+
const userRowClassName = typeof rowClassNameDef === "function" ? rowClassNameDef(row) : rowClassNameDef;
|
|
2709
|
+
const rowStyleDef = table.options.rowStyle;
|
|
2710
|
+
const userRowStyle = typeof rowStyleDef === "function" ? rowStyleDef(row) : rowStyleDef;
|
|
2711
|
+
const mergedRowStyle = userRowStyle ? { ...virtualStyle, ...userRowStyle } : virtualStyle;
|
|
2712
|
+
const rowClassName = [
|
|
2713
|
+
"yable-tr",
|
|
2714
|
+
pinnedPosition && `yable-tr--pinned-${pinnedPosition}`,
|
|
2715
|
+
userRowClassName
|
|
2716
|
+
].filter(Boolean).join(" ");
|
|
2029
2717
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2030
2718
|
/* @__PURE__ */ jsx(
|
|
2031
2719
|
"tr",
|
|
2032
2720
|
{
|
|
2033
|
-
className:
|
|
2034
|
-
style:
|
|
2721
|
+
className: rowClassName,
|
|
2722
|
+
style: mergedRowStyle,
|
|
2035
2723
|
"data-selected": isSelected || void 0,
|
|
2036
2724
|
"data-expanded": isExpanded || void 0,
|
|
2037
2725
|
"data-clickable": clickable || void 0,
|
|
2726
|
+
"data-pinned-row": pinnedPosition,
|
|
2038
2727
|
"data-row-id": row.id,
|
|
2039
2728
|
"data-row-index": rowIndex,
|
|
2040
2729
|
"aria-selected": selectionEnabled ? isSelected : void 0,
|
|
@@ -2066,7 +2755,7 @@ function TableRowInner({
|
|
|
2066
2755
|
})
|
|
2067
2756
|
}
|
|
2068
2757
|
),
|
|
2069
|
-
isExpanded && /* @__PURE__ */ jsx(
|
|
2758
|
+
isExpanded && /* @__PURE__ */ jsx(MasterDetail, { row, table, colSpan: visibleColumns.length })
|
|
2070
2759
|
] });
|
|
2071
2760
|
}
|
|
2072
2761
|
function areRowPropsEqual(prev, next) {
|
|
@@ -2077,10 +2766,12 @@ function areRowPropsEqual(prev, next) {
|
|
|
2077
2766
|
if (prev.isSelected !== next.isSelected) return false;
|
|
2078
2767
|
if (prev.isExpanded !== next.isExpanded) return false;
|
|
2079
2768
|
if (prev.clickable !== next.clickable) return false;
|
|
2769
|
+
if (prev.pinnedPosition !== next.pinnedPosition) return false;
|
|
2080
2770
|
if (prev.activeColumnId !== next.activeColumnId) return false;
|
|
2081
2771
|
if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
|
|
2082
2772
|
if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
|
|
2083
2773
|
if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
|
|
2774
|
+
if (prev.pendingValuesKey !== next.pendingValuesKey) return false;
|
|
2084
2775
|
if (prev.virtualStyle !== next.virtualStyle) {
|
|
2085
2776
|
if (!prev.virtualStyle || !next.virtualStyle) return false;
|
|
2086
2777
|
if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
|
|
@@ -2090,6 +2781,16 @@ function areRowPropsEqual(prev, next) {
|
|
|
2090
2781
|
return true;
|
|
2091
2782
|
}
|
|
2092
2783
|
var MemoizedTableRow = React3.memo(TableRowInner, areRowPropsEqual);
|
|
2784
|
+
function getPendingValuesKey(values) {
|
|
2785
|
+
if (!values) return "";
|
|
2786
|
+
return Object.keys(values).sort().map((key) => `${key}:${String(values[key])}`).join("|");
|
|
2787
|
+
}
|
|
2788
|
+
function isInteractiveClickTarget2(target) {
|
|
2789
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
2790
|
+
return Boolean(
|
|
2791
|
+
target.closest('input, textarea, select, button, a[href], [contenteditable="true"]')
|
|
2792
|
+
);
|
|
2793
|
+
}
|
|
2093
2794
|
function TableFooter({ table }) {
|
|
2094
2795
|
const footerGroups = table.getFooterGroups();
|
|
2095
2796
|
if (!footerGroups.length) return null;
|
|
@@ -2377,29 +3078,73 @@ function StatusBar({
|
|
|
2377
3078
|
] });
|
|
2378
3079
|
}
|
|
2379
3080
|
function SearchIcon() {
|
|
2380
|
-
return /* @__PURE__ */ jsxs(
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
3081
|
+
return /* @__PURE__ */ jsxs(
|
|
3082
|
+
"svg",
|
|
3083
|
+
{
|
|
3084
|
+
className: "yable-sidebar-search-icon",
|
|
3085
|
+
width: "13",
|
|
3086
|
+
height: "13",
|
|
3087
|
+
viewBox: "0 0 14 14",
|
|
3088
|
+
fill: "none",
|
|
3089
|
+
"aria-hidden": "true",
|
|
3090
|
+
children: [
|
|
3091
|
+
/* @__PURE__ */ jsx("circle", { cx: "6.25", cy: "6.25", r: "4.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
3092
|
+
/* @__PURE__ */ jsx("path", { d: "M9.5 9.5L12.5 12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
3093
|
+
]
|
|
3094
|
+
}
|
|
3095
|
+
);
|
|
2384
3096
|
}
|
|
2385
3097
|
function VisibilityIcon({ visible }) {
|
|
2386
3098
|
if (visible) {
|
|
2387
3099
|
return /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: [
|
|
2388
|
-
/* @__PURE__ */ jsx(
|
|
3100
|
+
/* @__PURE__ */ jsx(
|
|
3101
|
+
"path",
|
|
3102
|
+
{
|
|
3103
|
+
d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z",
|
|
3104
|
+
stroke: "currentColor",
|
|
3105
|
+
strokeWidth: "1.2",
|
|
3106
|
+
strokeLinejoin: "round"
|
|
3107
|
+
}
|
|
3108
|
+
),
|
|
2389
3109
|
/* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "2", stroke: "currentColor", strokeWidth: "1.2" })
|
|
2390
3110
|
] });
|
|
2391
3111
|
}
|
|
2392
3112
|
return /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: [
|
|
2393
|
-
/* @__PURE__ */ jsx(
|
|
2394
|
-
|
|
3113
|
+
/* @__PURE__ */ jsx(
|
|
3114
|
+
"path",
|
|
3115
|
+
{
|
|
3116
|
+
d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z",
|
|
3117
|
+
stroke: "currentColor",
|
|
3118
|
+
strokeWidth: "1.2",
|
|
3119
|
+
strokeLinejoin: "round",
|
|
3120
|
+
opacity: "0.3"
|
|
3121
|
+
}
|
|
3122
|
+
),
|
|
3123
|
+
/* @__PURE__ */ jsx(
|
|
3124
|
+
"line",
|
|
3125
|
+
{
|
|
3126
|
+
x1: "2",
|
|
3127
|
+
y1: "2",
|
|
3128
|
+
x2: "12",
|
|
3129
|
+
y2: "12",
|
|
3130
|
+
stroke: "currentColor",
|
|
3131
|
+
strokeWidth: "1.2",
|
|
3132
|
+
strokeLinecap: "round",
|
|
3133
|
+
opacity: "0.5"
|
|
3134
|
+
}
|
|
3135
|
+
)
|
|
2395
3136
|
] });
|
|
2396
3137
|
}
|
|
2397
|
-
function ColumnsPanel({
|
|
2398
|
-
table
|
|
2399
|
-
}) {
|
|
3138
|
+
function ColumnsPanel({ table }) {
|
|
2400
3139
|
const [search, setSearch] = useState("");
|
|
2401
3140
|
const [draggedId, setDraggedId] = useState(null);
|
|
2402
|
-
const
|
|
3141
|
+
const allColumns = table.getAllLeafColumns();
|
|
3142
|
+
const columnOrder = table.getState().columnOrder;
|
|
3143
|
+
const columns = columnOrder && columnOrder.length > 0 ? [...allColumns].sort((a, b) => {
|
|
3144
|
+
const ia = columnOrder.indexOf(a.id);
|
|
3145
|
+
const ib = columnOrder.indexOf(b.id);
|
|
3146
|
+
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
3147
|
+
}) : allColumns;
|
|
2403
3148
|
const visibleCount = columns.filter((c) => c.getIsVisible()).length;
|
|
2404
3149
|
const filteredColumns = search ? columns.filter((col) => {
|
|
2405
3150
|
const header = typeof col.columnDef.header === "string" ? col.columnDef.header : col.id;
|
|
@@ -2826,6 +3571,7 @@ function ContextMenu({
|
|
|
2826
3571
|
y,
|
|
2827
3572
|
onClose,
|
|
2828
3573
|
table,
|
|
3574
|
+
targetColumnId,
|
|
2829
3575
|
customItems
|
|
2830
3576
|
}) {
|
|
2831
3577
|
const menuRef = useRef(null);
|
|
@@ -2869,6 +3615,17 @@ function ContextMenu({
|
|
|
2869
3615
|
},
|
|
2870
3616
|
[onClose]
|
|
2871
3617
|
);
|
|
3618
|
+
const resolveSortColumn = () => {
|
|
3619
|
+
if (targetColumnId) {
|
|
3620
|
+
const column = table.getColumn(targetColumnId);
|
|
3621
|
+
if (column) return column;
|
|
3622
|
+
}
|
|
3623
|
+
const focused = table.getFocusedCell();
|
|
3624
|
+
if (focused) {
|
|
3625
|
+
return table.getVisibleLeafColumns()[focused.columnIndex];
|
|
3626
|
+
}
|
|
3627
|
+
return void 0;
|
|
3628
|
+
};
|
|
2872
3629
|
const defaultItems = [
|
|
2873
3630
|
{
|
|
2874
3631
|
id: "copy",
|
|
@@ -2917,14 +3674,14 @@ function ContextMenu({
|
|
|
2917
3674
|
id: "sort-asc",
|
|
2918
3675
|
label: "Sort Ascending",
|
|
2919
3676
|
action: () => {
|
|
2920
|
-
|
|
3677
|
+
resolveSortColumn()?.toggleSorting(false);
|
|
2921
3678
|
}
|
|
2922
3679
|
},
|
|
2923
3680
|
{
|
|
2924
3681
|
id: "sort-desc",
|
|
2925
3682
|
label: "Sort Descending",
|
|
2926
3683
|
action: () => {
|
|
2927
|
-
|
|
3684
|
+
resolveSortColumn()?.toggleSorting(true);
|
|
2928
3685
|
}
|
|
2929
3686
|
},
|
|
2930
3687
|
{
|
|
@@ -3016,11 +3773,13 @@ function useContextMenu() {
|
|
|
3016
3773
|
const [x, setX] = useState(0);
|
|
3017
3774
|
const [y, setY] = useState(0);
|
|
3018
3775
|
const [targetTable, setTargetTable] = useState(null);
|
|
3776
|
+
const [targetColumnId, setTargetColumnId] = useState(void 0);
|
|
3019
3777
|
const open = useCallback(
|
|
3020
|
-
(clientX, clientY, table) => {
|
|
3778
|
+
(clientX, clientY, table, columnId) => {
|
|
3021
3779
|
setX(clientX);
|
|
3022
3780
|
setY(clientY);
|
|
3023
3781
|
setTargetTable(table);
|
|
3782
|
+
setTargetColumnId(columnId);
|
|
3024
3783
|
setIsOpen(true);
|
|
3025
3784
|
},
|
|
3026
3785
|
[]
|
|
@@ -3028,6 +3787,7 @@ function useContextMenu() {
|
|
|
3028
3787
|
const close = useCallback(() => {
|
|
3029
3788
|
setIsOpen(false);
|
|
3030
3789
|
setTargetTable(null);
|
|
3790
|
+
setTargetColumnId(void 0);
|
|
3031
3791
|
}, []);
|
|
3032
3792
|
useEffect(() => {
|
|
3033
3793
|
if (!isOpen) return;
|
|
@@ -3042,7 +3802,7 @@ function useContextMenu() {
|
|
|
3042
3802
|
document.removeEventListener("click", handleClick);
|
|
3043
3803
|
};
|
|
3044
3804
|
}, [isOpen, close]);
|
|
3045
|
-
return { isOpen, x, y, targetTable, open, close };
|
|
3805
|
+
return { isOpen, x, y, targetTable, targetColumnId, open, close };
|
|
3046
3806
|
}
|
|
3047
3807
|
function useKeyboardNavigation(table, options = {}) {
|
|
3048
3808
|
const {
|
|
@@ -3250,11 +4010,13 @@ function filterHeaderGroups(groups, visibleColumnIds) {
|
|
|
3250
4010
|
}
|
|
3251
4011
|
function Table({
|
|
3252
4012
|
table,
|
|
3253
|
-
stickyHeader,
|
|
3254
|
-
striped,
|
|
3255
|
-
bordered,
|
|
3256
|
-
compact,
|
|
3257
|
-
theme,
|
|
4013
|
+
stickyHeader: stickyHeaderProp,
|
|
4014
|
+
striped: stripedProp,
|
|
4015
|
+
bordered: borderedProp,
|
|
4016
|
+
compact: compactProp,
|
|
4017
|
+
theme: themeProp,
|
|
4018
|
+
config,
|
|
4019
|
+
configProfile,
|
|
3258
4020
|
clickableRows,
|
|
3259
4021
|
footer,
|
|
3260
4022
|
loading,
|
|
@@ -3268,21 +4030,43 @@ function Table({
|
|
|
3268
4030
|
renderLoading,
|
|
3269
4031
|
children,
|
|
3270
4032
|
className,
|
|
3271
|
-
direction,
|
|
4033
|
+
direction: directionProp,
|
|
3272
4034
|
statusBar,
|
|
3273
4035
|
statusBarPanels,
|
|
3274
4036
|
sidebar,
|
|
3275
|
-
sidebarPanels
|
|
4037
|
+
sidebarPanels,
|
|
3276
4038
|
defaultSidebarPanel,
|
|
3277
4039
|
floatingFilters,
|
|
3278
4040
|
columnVirtualization,
|
|
3279
4041
|
columnVirtualizationOverscan,
|
|
3280
|
-
ariaLabel,
|
|
4042
|
+
ariaLabel: ariaLabelProp,
|
|
3281
4043
|
...rest
|
|
3282
4044
|
}) {
|
|
4045
|
+
const providerDefaults = useYableDefaults();
|
|
4046
|
+
const { tableProps: providerTableProps } = providerDefaults;
|
|
4047
|
+
const profile = resolveYableProfile(
|
|
4048
|
+
config ?? providerDefaults.config,
|
|
4049
|
+
configProfile ?? providerDefaults.tableProfile
|
|
4050
|
+
);
|
|
4051
|
+
const profileTableProps = profile.table;
|
|
4052
|
+
const stickyHeader = stickyHeaderProp ?? profileTableProps?.stickyHeader ?? providerTableProps?.stickyHeader;
|
|
4053
|
+
const striped = stripedProp ?? profileTableProps?.striped ?? providerTableProps?.striped;
|
|
4054
|
+
const bordered = borderedProp ?? profileTableProps?.bordered ?? providerTableProps?.bordered;
|
|
4055
|
+
const compact = compactProp ?? profileTableProps?.compact ?? providerTableProps?.compact;
|
|
4056
|
+
const theme = themeProp ?? profileTableProps?.theme ?? providerTableProps?.theme;
|
|
4057
|
+
const direction = directionProp ?? profileTableProps?.direction ?? providerTableProps?.direction;
|
|
4058
|
+
const ariaLabel = ariaLabelProp ?? profileTableProps?.ariaLabel ?? providerTableProps?.ariaLabel;
|
|
4059
|
+
const resolvedClickableRows = clickableRows ?? profileTableProps?.clickableRows;
|
|
4060
|
+
const resolvedStatusBar = statusBar ?? profileTableProps?.statusBar;
|
|
4061
|
+
const resolvedSidebar = sidebar ?? profileTableProps?.sidebar;
|
|
4062
|
+
const resolvedSidebarPanels = sidebarPanels ?? profileTableProps?.sidebarPanels ?? ["columns", "filters"];
|
|
4063
|
+
const resolvedDefaultSidebarPanel = defaultSidebarPanel ?? profileTableProps?.defaultSidebarPanel;
|
|
4064
|
+
const resolvedFloatingFilters = floatingFilters ?? profileTableProps?.floatingFilters;
|
|
4065
|
+
const resolvedColumnVirtualization = columnVirtualization ?? profileTableProps?.columnVirtualization;
|
|
4066
|
+
const resolvedColumnVirtualizationOverscan = columnVirtualizationOverscan ?? profileTableProps?.columnVirtualizationOverscan;
|
|
3283
4067
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
3284
4068
|
const [sidebarPanel, setSidebarPanel] = useState(
|
|
3285
|
-
|
|
4069
|
+
resolvedDefaultSidebarPanel ?? "columns"
|
|
3286
4070
|
);
|
|
3287
4071
|
const containerRef = useRef(null);
|
|
3288
4072
|
const horizontalScrollRef = useRef(null);
|
|
@@ -3306,12 +4090,14 @@ function Table({
|
|
|
3306
4090
|
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
3307
4091
|
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
3308
4092
|
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
3309
|
-
const canVirtualizeColumns = Boolean(
|
|
4093
|
+
const canVirtualizeColumns = Boolean(resolvedColumnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
4094
|
+
const allVisibleColumnSizeSignature = allVisibleColumns.map((column) => `${column.id}:${column.getSize()}`).join("|");
|
|
3310
4095
|
const columnVirtualState = useColumnVirtualization({
|
|
3311
4096
|
containerRef: horizontalScrollRef,
|
|
3312
4097
|
columns: allVisibleColumns,
|
|
3313
|
-
overscan:
|
|
3314
|
-
enabled: canVirtualizeColumns
|
|
4098
|
+
overscan: resolvedColumnVirtualizationOverscan ?? 2,
|
|
4099
|
+
enabled: canVirtualizeColumns,
|
|
4100
|
+
sizingKey: allVisibleColumnSizeSignature
|
|
3315
4101
|
});
|
|
3316
4102
|
const renderTable = useMemo(() => {
|
|
3317
4103
|
if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
|
|
@@ -3386,24 +4172,47 @@ function Table({
|
|
|
3386
4172
|
const handleContextMenu = useCallback(
|
|
3387
4173
|
(e) => {
|
|
3388
4174
|
e.preventDefault();
|
|
3389
|
-
|
|
4175
|
+
const targetEl = e.target?.closest?.("[data-column-id]");
|
|
4176
|
+
const targetColumnId = targetEl?.getAttribute("data-column-id") ?? void 0;
|
|
4177
|
+
contextMenu.open(e.clientX, e.clientY, table, targetColumnId);
|
|
3390
4178
|
},
|
|
3391
4179
|
[contextMenu, table]
|
|
3392
4180
|
);
|
|
3393
|
-
const
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
4181
|
+
const visibleLeafColumns = renderTable.getVisibleLeafColumns();
|
|
4182
|
+
const visibleColumnTotalSize = visibleLeafColumns.reduce(
|
|
4183
|
+
(sum, column) => sum + column.getSize(),
|
|
4184
|
+
0
|
|
4185
|
+
);
|
|
4186
|
+
const colgroup = visibleLeafColumns.length === 0 ? null : /* @__PURE__ */ jsx("colgroup", { children: visibleLeafColumns.map((col) => /* @__PURE__ */ jsx("col", { style: { width: col.getSize() } }, col.id)) });
|
|
4187
|
+
const outerTableStyle = useMemo(() => {
|
|
4188
|
+
if (columnVirtualState.isVirtualized) {
|
|
4189
|
+
return {
|
|
3398
4190
|
width: columnVirtualState.visibleWidth,
|
|
3399
4191
|
minWidth: columnVirtualState.visibleWidth,
|
|
3400
4192
|
marginLeft: columnVirtualState.startOffset,
|
|
3401
4193
|
tableLayout: "fixed"
|
|
3402
|
-
}
|
|
4194
|
+
};
|
|
4195
|
+
}
|
|
4196
|
+
return {
|
|
4197
|
+
minWidth: visibleColumnTotalSize || void 0,
|
|
4198
|
+
tableLayout: "fixed"
|
|
4199
|
+
};
|
|
4200
|
+
}, [
|
|
4201
|
+
columnVirtualState.isVirtualized,
|
|
4202
|
+
columnVirtualState.visibleWidth,
|
|
4203
|
+
columnVirtualState.startOffset,
|
|
4204
|
+
visibleColumnTotalSize
|
|
4205
|
+
]);
|
|
4206
|
+
const tableNode = /* @__PURE__ */ jsxs(
|
|
4207
|
+
"table",
|
|
4208
|
+
{
|
|
4209
|
+
className: "yable-table",
|
|
4210
|
+
style: outerTableStyle,
|
|
3403
4211
|
"data-column-virtualized": columnVirtualState.isVirtualized || void 0,
|
|
3404
4212
|
children: [
|
|
3405
|
-
|
|
3406
|
-
/* @__PURE__ */ jsx(
|
|
4213
|
+
colgroup,
|
|
4214
|
+
/* @__PURE__ */ jsx(TableHeader, { table: renderTable, floatingFilters: resolvedFloatingFilters }),
|
|
4215
|
+
/* @__PURE__ */ jsx(TableBody, { table: renderTable, clickableRows: resolvedClickableRows, colgroup }),
|
|
3407
4216
|
footer && /* @__PURE__ */ jsx(TableFooter, { table: renderTable })
|
|
3408
4217
|
]
|
|
3409
4218
|
}
|
|
@@ -3469,18 +4278,43 @@ function Table({
|
|
|
3469
4278
|
}
|
|
3470
4279
|
))
|
|
3471
4280
|
] }),
|
|
3472
|
-
|
|
4281
|
+
resolvedSidebar && !sidebarOpen && /* @__PURE__ */ jsx(
|
|
4282
|
+
"button",
|
|
4283
|
+
{
|
|
4284
|
+
type: "button",
|
|
4285
|
+
className: "yable-sidebar-trigger",
|
|
4286
|
+
"aria-label": "Open tool panel",
|
|
4287
|
+
title: "Open tool panel",
|
|
4288
|
+
onClick: () => setSidebarOpen(true),
|
|
4289
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
4290
|
+
/* @__PURE__ */ jsx(
|
|
4291
|
+
"rect",
|
|
4292
|
+
{
|
|
4293
|
+
x: "3",
|
|
4294
|
+
y: "4",
|
|
4295
|
+
width: "18",
|
|
4296
|
+
height: "16",
|
|
4297
|
+
rx: "2",
|
|
4298
|
+
stroke: "currentColor",
|
|
4299
|
+
strokeWidth: "2"
|
|
4300
|
+
}
|
|
4301
|
+
),
|
|
4302
|
+
/* @__PURE__ */ jsx("line", { x1: "14", y1: "4", x2: "14", y2: "20", stroke: "currentColor", strokeWidth: "2" })
|
|
4303
|
+
] })
|
|
4304
|
+
}
|
|
4305
|
+
),
|
|
4306
|
+
resolvedSidebar && /* @__PURE__ */ jsx(
|
|
3473
4307
|
Sidebar,
|
|
3474
4308
|
{
|
|
3475
4309
|
table,
|
|
3476
4310
|
open: sidebarOpen,
|
|
3477
4311
|
onClose: () => setSidebarOpen(false),
|
|
3478
|
-
panels:
|
|
4312
|
+
panels: resolvedSidebarPanels,
|
|
3479
4313
|
activePanel: sidebarPanel,
|
|
3480
4314
|
onPanelChange: setSidebarPanel
|
|
3481
4315
|
}
|
|
3482
4316
|
),
|
|
3483
|
-
|
|
4317
|
+
resolvedStatusBar && /* @__PURE__ */ jsx(StatusBar, { table, panels: statusBarPanels }),
|
|
3484
4318
|
children,
|
|
3485
4319
|
contextMenu.isOpen && /* @__PURE__ */ jsx(
|
|
3486
4320
|
ContextMenu,
|
|
@@ -3488,7 +4322,8 @@ function Table({
|
|
|
3488
4322
|
x: contextMenu.x,
|
|
3489
4323
|
y: contextMenu.y,
|
|
3490
4324
|
onClose: contextMenu.close,
|
|
3491
|
-
table
|
|
4325
|
+
table,
|
|
4326
|
+
targetColumnId: contextMenu.targetColumnId
|
|
3492
4327
|
}
|
|
3493
4328
|
),
|
|
3494
4329
|
/* @__PURE__ */ jsx(
|
|
@@ -4416,33 +5251,6 @@ function TreeToggle({
|
|
|
4416
5251
|
}
|
|
4417
5252
|
);
|
|
4418
5253
|
}
|
|
4419
|
-
function MasterDetail({
|
|
4420
|
-
row,
|
|
4421
|
-
table,
|
|
4422
|
-
colSpan,
|
|
4423
|
-
renderDetailPanel,
|
|
4424
|
-
animationClass
|
|
4425
|
-
}) {
|
|
4426
|
-
const renderer = renderDetailPanel ?? table.options.renderDetailPanel;
|
|
4427
|
-
if (!renderer) return null;
|
|
4428
|
-
const content = renderer(row);
|
|
4429
|
-
if (content == null) return null;
|
|
4430
|
-
const classes = [
|
|
4431
|
-
"yable-detail-row",
|
|
4432
|
-
"yable-detail-row--animated",
|
|
4433
|
-
animationClass
|
|
4434
|
-
].filter(Boolean).join(" ");
|
|
4435
|
-
return /* @__PURE__ */ jsx(
|
|
4436
|
-
"tr",
|
|
4437
|
-
{
|
|
4438
|
-
className: classes,
|
|
4439
|
-
"data-detail-for": row.id,
|
|
4440
|
-
role: "row",
|
|
4441
|
-
"aria-label": `Details for row ${row.id}`,
|
|
4442
|
-
children: /* @__PURE__ */ jsx("td", { className: "yable-detail-cell", colSpan, role: "cell", children: /* @__PURE__ */ jsx("div", { className: "yable-detail-panel", children: /* @__PURE__ */ jsx("div", { className: "yable-detail-panel-inner", children: content }) }) })
|
|
4443
|
-
}
|
|
4444
|
-
);
|
|
4445
|
-
}
|
|
4446
5254
|
function ExpandIcon({
|
|
4447
5255
|
isExpanded,
|
|
4448
5256
|
onClick,
|
|
@@ -5411,7 +6219,237 @@ function useTheme(options = {}) {
|
|
|
5411
6219
|
containerRef
|
|
5412
6220
|
};
|
|
5413
6221
|
}
|
|
6222
|
+
function selectColumn(options = {}) {
|
|
6223
|
+
const { id = "_select", size = 40, headerAriaLabel = "Select all rows" } = options;
|
|
6224
|
+
return {
|
|
6225
|
+
id,
|
|
6226
|
+
header: ({ table }) => /* @__PURE__ */ jsx("label", { className: "yable-checkbox-hitbox", onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx(
|
|
6227
|
+
"input",
|
|
6228
|
+
{
|
|
6229
|
+
type: "checkbox",
|
|
6230
|
+
className: "yable-checkbox",
|
|
6231
|
+
checked: table.getIsAllPageRowsSelected(),
|
|
6232
|
+
ref: (el) => {
|
|
6233
|
+
if (el)
|
|
6234
|
+
el.indeterminate = table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected();
|
|
6235
|
+
},
|
|
6236
|
+
onChange: () => table.toggleAllPageRowsSelected(),
|
|
6237
|
+
"aria-label": headerAriaLabel
|
|
6238
|
+
}
|
|
6239
|
+
) }),
|
|
6240
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("label", { className: "yable-checkbox-hitbox", onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx(
|
|
6241
|
+
"input",
|
|
6242
|
+
{
|
|
6243
|
+
type: "checkbox",
|
|
6244
|
+
className: "yable-checkbox",
|
|
6245
|
+
checked: row.getIsSelected(),
|
|
6246
|
+
disabled: !row.getCanSelect(),
|
|
6247
|
+
onChange: row.getToggleSelectedHandler(),
|
|
6248
|
+
"aria-label": "Select row"
|
|
6249
|
+
}
|
|
6250
|
+
) }),
|
|
6251
|
+
size,
|
|
6252
|
+
enableSorting: true,
|
|
6253
|
+
sortingFn: (rowA, rowB) => Number(rowA.getIsSelected()) - Number(rowB.getIsSelected()),
|
|
6254
|
+
enableColumnFilter: false,
|
|
6255
|
+
enableResizing: false,
|
|
6256
|
+
enableReorder: false,
|
|
6257
|
+
enableHiding: false,
|
|
6258
|
+
lockVisible: true
|
|
6259
|
+
};
|
|
6260
|
+
}
|
|
6261
|
+
|
|
6262
|
+
// src/presets/rowNumberColumn.tsx
|
|
6263
|
+
function rowNumberColumn(options = {}) {
|
|
6264
|
+
const { id = "_rowNumber", header = "#", size = 50, startFrom = 1 } = options;
|
|
6265
|
+
return {
|
|
6266
|
+
id,
|
|
6267
|
+
header,
|
|
6268
|
+
cell: ({ row }) => row.index + startFrom,
|
|
6269
|
+
size,
|
|
6270
|
+
enableSorting: false,
|
|
6271
|
+
enableColumnFilter: false,
|
|
6272
|
+
enableResizing: false,
|
|
6273
|
+
enableReorder: false,
|
|
6274
|
+
lockVisible: true
|
|
6275
|
+
};
|
|
6276
|
+
}
|
|
6277
|
+
function actionsColumn(options) {
|
|
6278
|
+
const { id = "_actions", header = "", size = 100, actions } = options;
|
|
6279
|
+
return {
|
|
6280
|
+
id,
|
|
6281
|
+
header,
|
|
6282
|
+
cell: (ctx) => {
|
|
6283
|
+
const items = typeof actions === "function" ? actions(ctx.row) : actions;
|
|
6284
|
+
return /* @__PURE__ */ jsx("div", { className: "yable-cell-actions", children: items.filter((a) => !a.hidden || !a.hidden(ctx.row)).map((action, i) => /* @__PURE__ */ jsx(
|
|
6285
|
+
"button",
|
|
6286
|
+
{
|
|
6287
|
+
type: "button",
|
|
6288
|
+
className: "yable-action-btn",
|
|
6289
|
+
disabled: action.disabled?.(ctx.row),
|
|
6290
|
+
onClick: (e) => {
|
|
6291
|
+
e.stopPropagation();
|
|
6292
|
+
action.onClick(ctx.row);
|
|
6293
|
+
},
|
|
6294
|
+
title: action.label,
|
|
6295
|
+
children: action.icon ?? action.label
|
|
6296
|
+
},
|
|
6297
|
+
i
|
|
6298
|
+
)) });
|
|
6299
|
+
},
|
|
6300
|
+
size,
|
|
6301
|
+
enableSorting: false,
|
|
6302
|
+
enableColumnFilter: false,
|
|
6303
|
+
enableResizing: false,
|
|
6304
|
+
enableReorder: false
|
|
6305
|
+
};
|
|
6306
|
+
}
|
|
6307
|
+
function expandColumn(options = {}) {
|
|
6308
|
+
const { id = "_expand", size = 40 } = options;
|
|
6309
|
+
return {
|
|
6310
|
+
id,
|
|
6311
|
+
header: () => null,
|
|
6312
|
+
cell: ({ row }) => {
|
|
6313
|
+
if (!row.getCanExpand()) return null;
|
|
6314
|
+
return /* @__PURE__ */ jsx(
|
|
6315
|
+
"button",
|
|
6316
|
+
{
|
|
6317
|
+
type: "button",
|
|
6318
|
+
className: "yable-expand-btn",
|
|
6319
|
+
onClick: (e) => {
|
|
6320
|
+
e.stopPropagation();
|
|
6321
|
+
row.toggleExpanded();
|
|
6322
|
+
},
|
|
6323
|
+
"aria-expanded": row.getIsExpanded(),
|
|
6324
|
+
"aria-label": row.getIsExpanded() ? "Collapse row" : "Expand row",
|
|
6325
|
+
children: /* @__PURE__ */ jsx(
|
|
6326
|
+
"span",
|
|
6327
|
+
{
|
|
6328
|
+
className: "yable-expand-icon",
|
|
6329
|
+
style: {
|
|
6330
|
+
display: "inline-block",
|
|
6331
|
+
transform: row.getIsExpanded() ? "rotate(90deg)" : "rotate(0deg)",
|
|
6332
|
+
transition: "transform 150ms ease"
|
|
6333
|
+
},
|
|
6334
|
+
children: "\u25B6"
|
|
6335
|
+
}
|
|
6336
|
+
)
|
|
6337
|
+
}
|
|
6338
|
+
);
|
|
6339
|
+
},
|
|
6340
|
+
size,
|
|
6341
|
+
enableSorting: false,
|
|
6342
|
+
enableColumnFilter: false,
|
|
6343
|
+
enableResizing: false,
|
|
6344
|
+
enableReorder: false,
|
|
6345
|
+
lockVisible: true
|
|
6346
|
+
};
|
|
6347
|
+
}
|
|
6348
|
+
function CellStack({ children, gap = 2 }) {
|
|
6349
|
+
return /* @__PURE__ */ jsx(
|
|
6350
|
+
"div",
|
|
6351
|
+
{
|
|
6352
|
+
className: "yable-cell-stack",
|
|
6353
|
+
style: {
|
|
6354
|
+
display: "flex",
|
|
6355
|
+
flexDirection: "column",
|
|
6356
|
+
gap
|
|
6357
|
+
},
|
|
6358
|
+
children
|
|
6359
|
+
}
|
|
6360
|
+
);
|
|
6361
|
+
}
|
|
6362
|
+
function CellRow({ children, gap = 6, align = "center", justify = "start" }) {
|
|
6363
|
+
const justifyMap = {
|
|
6364
|
+
start: "flex-start",
|
|
6365
|
+
center: "center",
|
|
6366
|
+
end: "flex-end",
|
|
6367
|
+
between: "space-between"
|
|
6368
|
+
};
|
|
6369
|
+
return /* @__PURE__ */ jsx(
|
|
6370
|
+
"div",
|
|
6371
|
+
{
|
|
6372
|
+
className: "yable-cell-row",
|
|
6373
|
+
style: {
|
|
6374
|
+
display: "flex",
|
|
6375
|
+
flexDirection: "row",
|
|
6376
|
+
alignItems: align === "baseline" ? "baseline" : align === "start" ? "flex-start" : align === "end" ? "flex-end" : "center",
|
|
6377
|
+
justifyContent: justifyMap[justify] || "flex-start",
|
|
6378
|
+
gap
|
|
6379
|
+
},
|
|
6380
|
+
children
|
|
6381
|
+
}
|
|
6382
|
+
);
|
|
6383
|
+
}
|
|
6384
|
+
function CellWithIcon({ icon, children, gap = 6, iconSize }) {
|
|
6385
|
+
return /* @__PURE__ */ jsxs(
|
|
6386
|
+
"div",
|
|
6387
|
+
{
|
|
6388
|
+
className: "yable-cell-with-icon",
|
|
6389
|
+
style: {
|
|
6390
|
+
display: "flex",
|
|
6391
|
+
flexDirection: "row",
|
|
6392
|
+
alignItems: "center",
|
|
6393
|
+
gap
|
|
6394
|
+
},
|
|
6395
|
+
children: [
|
|
6396
|
+
/* @__PURE__ */ jsx(
|
|
6397
|
+
"span",
|
|
6398
|
+
{
|
|
6399
|
+
className: "yable-cell-icon",
|
|
6400
|
+
style: {
|
|
6401
|
+
display: "inline-flex",
|
|
6402
|
+
alignItems: "center",
|
|
6403
|
+
justifyContent: "center",
|
|
6404
|
+
flexShrink: 0,
|
|
6405
|
+
...iconSize ? { width: iconSize, height: iconSize } : {}
|
|
6406
|
+
},
|
|
6407
|
+
children: icon
|
|
6408
|
+
}
|
|
6409
|
+
),
|
|
6410
|
+
/* @__PURE__ */ jsx("span", { className: "yable-cell-icon-content", style: { minWidth: 0 }, children })
|
|
6411
|
+
]
|
|
6412
|
+
}
|
|
6413
|
+
);
|
|
6414
|
+
}
|
|
6415
|
+
function CellText({
|
|
6416
|
+
children,
|
|
6417
|
+
variant = "primary",
|
|
6418
|
+
bold,
|
|
6419
|
+
truncate,
|
|
6420
|
+
size = "md"
|
|
6421
|
+
}) {
|
|
6422
|
+
const fontSizeMap = { sm: "0.75rem", md: "0.875rem", lg: "1rem" };
|
|
6423
|
+
return /* @__PURE__ */ jsx(
|
|
6424
|
+
"span",
|
|
6425
|
+
{
|
|
6426
|
+
className: `yable-cell-text yable-cell-text--${variant}`,
|
|
6427
|
+
style: {
|
|
6428
|
+
fontSize: fontSizeMap[size],
|
|
6429
|
+
fontWeight: bold ? 600 : void 0,
|
|
6430
|
+
color: variant === "secondary" ? "var(--yable-text-secondary, #6b7280)" : variant === "muted" ? "var(--yable-text-muted, #9ca3af)" : void 0,
|
|
6431
|
+
...truncate ? {
|
|
6432
|
+
overflow: "hidden",
|
|
6433
|
+
textOverflow: "ellipsis",
|
|
6434
|
+
whiteSpace: "nowrap"
|
|
6435
|
+
} : {}
|
|
6436
|
+
},
|
|
6437
|
+
children
|
|
6438
|
+
}
|
|
6439
|
+
);
|
|
6440
|
+
}
|
|
6441
|
+
|
|
6442
|
+
// src/utils/mergeEditChanges.ts
|
|
6443
|
+
function mergeEditChanges(data, changes, getRowId = (_, i) => String(i)) {
|
|
6444
|
+
const changeKeys = Object.keys(changes);
|
|
6445
|
+
if (changeKeys.length === 0) return data;
|
|
6446
|
+
return data.map((row, i) => {
|
|
6447
|
+
const id = getRowId(row, i);
|
|
6448
|
+
const patch = changes[id];
|
|
6449
|
+
return patch ? { ...row, ...patch } : row;
|
|
6450
|
+
});
|
|
6451
|
+
}
|
|
5414
6452
|
|
|
5415
|
-
export { CellBadge, CellBoolean, CellCheckbox, CellCurrency, CellDate, CellDatePicker, CellErrorBoundary, CellInput, CellLink, CellNumeric, CellProgress, CellRating, CellSelect, CellStatus, CellStatusBadge, CellToggle, ColumnsPanel, ContextMenu, ContextMenuItem, DEFAULT_TEXT_RECIPE, DragHandle, ErrorBoundary, ExpandIcon, FillHandle, FiltersPanel, FlashCell, FloatingFilter, GlobalFilter, LoadingOverlay, MasterDetail, NoRowsOverlay, Pagination, PivotConfigPanel, PrintLayout, SetFilter, Sidebar, SortIndicator, StatusBar, StatusBarPanelComponent, Table, TableBody, TableCell, TableFooter, TableHeader, TableProvider, Tooltip, TreeToggle, getMeasureRecipeForCellType, getRegisteredCellTypes, resolveMeasureRecipe, useAutoMeasurements, useCellFlash, useClipboard, useColumnVirtualization, useContextMenu, useFillHandle, useKeyboardNavigation, usePretextMeasurement, usePrintLayout, useRowAnimation, useRowDrag, useTable, useTableContext, useTableRowHeights, useTheme, useTooltip, useVirtualization };
|
|
6453
|
+
export { CellBadge, CellBoolean, CellCheckbox, CellCurrency, CellDate, CellDatePicker, CellErrorBoundary, CellInput, CellLink, CellNumeric, CellProgress, CellRating, CellRow, CellSelect, CellStack, CellStatus, CellStatusBadge, CellText, CellToggle, CellWithIcon, ColumnsPanel, ContextMenu, ContextMenuItem, DEFAULT_TEXT_RECIPE, DragHandle, ErrorBoundary, ExpandIcon, FillHandle, FiltersPanel, FlashCell, FloatingFilter, GlobalFilter, LoadingOverlay, MasterDetail, NoRowsOverlay, Pagination, PivotConfigPanel, PrintLayout, SetFilter, Sidebar, SortIndicator, StatusBar, StatusBarPanelComponent, Table, TableBody, TableCell, TableFooter, TableHeader, TableProvider, Tooltip, TreeToggle, YableProvider, actionsColumn, applyYableConfigToColumns, createYableConfig, expandColumn, getMeasureRecipeForCellType, getRegisteredCellTypes, getYableDefaultColumnDef, mergeEditChanges, resolveMeasureRecipe, resolveYableProfile, rowNumberColumn, selectColumn, useAutoMeasurements, useCellFlash, useClipboard, useColumnVirtualization, useContextMenu, useFillHandle, useKeyboardNavigation, usePretextMeasurement, usePrintLayout, useRowAnimation, useRowDrag, useServerTable, useTable, useTableContext, useTablePersistence, useTableRowHeights, useTheme, useTooltip, useVirtualization, useYableDefaults };
|
|
5416
6454
|
//# sourceMappingURL=index.js.map
|
|
5417
6455
|
//# sourceMappingURL=index.js.map
|