@zvndev/yable-react 0.2.0 → 0.4.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/LICENSE +21 -0
- package/dist/index.cjs +1245 -202
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +262 -14
- package/dist/index.d.ts +262 -14
- package/dist/index.js +1232 -204
- package/dist/index.js.map +1 -1
- package/package.json +34 -16
package/dist/index.js
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
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
5
|
import { getInitialRowDragState, moveRow } from '@zvndev/yable-core/features/rowDragging';
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
|
+
var YableContext = createContext({});
|
|
9
|
+
function useYableDefaults() {
|
|
10
|
+
return useContext(YableContext);
|
|
11
|
+
}
|
|
12
|
+
function YableProvider({
|
|
13
|
+
children,
|
|
14
|
+
defaultColumnDef,
|
|
15
|
+
striped,
|
|
16
|
+
stickyHeader,
|
|
17
|
+
bordered,
|
|
18
|
+
compact,
|
|
19
|
+
theme,
|
|
20
|
+
direction,
|
|
21
|
+
ariaLabel
|
|
22
|
+
}) {
|
|
23
|
+
const tableProps = {};
|
|
24
|
+
if (striped !== void 0) tableProps.striped = striped;
|
|
25
|
+
if (stickyHeader !== void 0) tableProps.stickyHeader = stickyHeader;
|
|
26
|
+
if (bordered !== void 0) tableProps.bordered = bordered;
|
|
27
|
+
if (compact !== void 0) tableProps.compact = compact;
|
|
28
|
+
if (theme !== void 0) tableProps.theme = theme;
|
|
29
|
+
if (direction !== void 0) tableProps.direction = direction;
|
|
30
|
+
if (ariaLabel !== void 0) tableProps.ariaLabel = ariaLabel;
|
|
31
|
+
const value = {
|
|
32
|
+
tableProps: Object.keys(tableProps).length > 0 ? tableProps : void 0,
|
|
33
|
+
defaultColumnDef
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ jsx(YableContext.Provider, { value, children });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/useTable.ts
|
|
8
39
|
function shallowEqual(a, b) {
|
|
9
40
|
if (a === b) return true;
|
|
10
41
|
const keysA = Object.keys(a);
|
|
@@ -17,6 +48,17 @@ function shallowEqual(a, b) {
|
|
|
17
48
|
return true;
|
|
18
49
|
}
|
|
19
50
|
function useTable(options) {
|
|
51
|
+
const providerDefaults = useYableDefaults();
|
|
52
|
+
const optionsWithDefaults = useMemo(() => {
|
|
53
|
+
if (!providerDefaults.defaultColumnDef) return options;
|
|
54
|
+
return {
|
|
55
|
+
...options,
|
|
56
|
+
defaultColumnDef: {
|
|
57
|
+
...providerDefaults.defaultColumnDef,
|
|
58
|
+
...options.defaultColumnDef
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}, [options, providerDefaults.defaultColumnDef]);
|
|
20
62
|
const [state, setState] = useState(() => ({
|
|
21
63
|
sorting: [],
|
|
22
64
|
columnFilters: [],
|
|
@@ -56,14 +98,14 @@ function useTable(options) {
|
|
|
56
98
|
}));
|
|
57
99
|
const stateRef = useRef(state);
|
|
58
100
|
stateRef.current = state;
|
|
59
|
-
const prevOptionsRef = useRef(
|
|
101
|
+
const prevOptionsRef = useRef(optionsWithDefaults);
|
|
60
102
|
const stableOptions = useMemo(() => {
|
|
61
|
-
if (shallowEqual(prevOptionsRef.current,
|
|
103
|
+
if (shallowEqual(prevOptionsRef.current, optionsWithDefaults)) {
|
|
62
104
|
return prevOptionsRef.current;
|
|
63
105
|
}
|
|
64
|
-
prevOptionsRef.current =
|
|
65
|
-
return
|
|
66
|
-
}, [
|
|
106
|
+
prevOptionsRef.current = optionsWithDefaults;
|
|
107
|
+
return optionsWithDefaults;
|
|
108
|
+
}, [optionsWithDefaults]);
|
|
67
109
|
const onStateChangeRef = useRef(options.onStateChange);
|
|
68
110
|
onStateChangeRef.current = options.onStateChange;
|
|
69
111
|
const resolvedState = useMemo(
|
|
@@ -73,17 +115,14 @@ function useTable(options) {
|
|
|
73
115
|
}),
|
|
74
116
|
[state, stableOptions.state]
|
|
75
117
|
);
|
|
76
|
-
const onStateChange = useCallback(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
[]
|
|
86
|
-
);
|
|
118
|
+
const onStateChange = useCallback((updater) => {
|
|
119
|
+
const latest = onStateChangeRef.current;
|
|
120
|
+
if (latest) {
|
|
121
|
+
latest(updater);
|
|
122
|
+
} else {
|
|
123
|
+
setState((prev) => functionalUpdate(updater, prev));
|
|
124
|
+
}
|
|
125
|
+
}, []);
|
|
87
126
|
const resolvedOptions = useMemo(
|
|
88
127
|
() => ({
|
|
89
128
|
...stableOptions,
|
|
@@ -96,12 +135,14 @@ function useTable(options) {
|
|
|
96
135
|
if (!tableRef.current) {
|
|
97
136
|
tableRef.current = createTable(resolvedOptions);
|
|
98
137
|
} else {
|
|
99
|
-
tableRef.current.setOptions(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
138
|
+
tableRef.current.setOptions(
|
|
139
|
+
(prev) => ({
|
|
140
|
+
...prev,
|
|
141
|
+
...resolvedOptions,
|
|
142
|
+
state: resolvedState,
|
|
143
|
+
onStateChange
|
|
144
|
+
})
|
|
145
|
+
);
|
|
105
146
|
}
|
|
106
147
|
useEffect(() => {
|
|
107
148
|
return () => {
|
|
@@ -112,6 +153,122 @@ function useTable(options) {
|
|
|
112
153
|
}, []);
|
|
113
154
|
return tableRef.current;
|
|
114
155
|
}
|
|
156
|
+
var DEFAULT_PERSISTED_KEYS = [
|
|
157
|
+
"columnVisibility",
|
|
158
|
+
"columnOrder",
|
|
159
|
+
"columnSizing",
|
|
160
|
+
"columnPinning"
|
|
161
|
+
];
|
|
162
|
+
function resolveStorage(custom) {
|
|
163
|
+
if (custom) return custom;
|
|
164
|
+
if (typeof window !== "undefined") {
|
|
165
|
+
try {
|
|
166
|
+
return window.localStorage;
|
|
167
|
+
} catch {
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
function pick(obj, keys) {
|
|
174
|
+
const result = {};
|
|
175
|
+
for (const k of keys) {
|
|
176
|
+
if (k in obj) {
|
|
177
|
+
result[k] = obj[k];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
function readState(storage, key, version, persistedKeys) {
|
|
183
|
+
if (!storage) return {};
|
|
184
|
+
try {
|
|
185
|
+
const raw = storage.getItem(key);
|
|
186
|
+
if (!raw) return {};
|
|
187
|
+
const envelope = JSON.parse(raw);
|
|
188
|
+
if (envelope.version !== version) {
|
|
189
|
+
storage.removeItem(key);
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
return pick(envelope.state, persistedKeys);
|
|
193
|
+
} catch {
|
|
194
|
+
if (typeof console !== "undefined") {
|
|
195
|
+
console.warn(`[yable] Failed to read persisted state for key "${key}"`);
|
|
196
|
+
}
|
|
197
|
+
return {};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function writeState(storage, key, version, state) {
|
|
201
|
+
if (!storage) return;
|
|
202
|
+
try {
|
|
203
|
+
const envelope = { version, state };
|
|
204
|
+
storage.setItem(key, JSON.stringify(envelope));
|
|
205
|
+
} catch {
|
|
206
|
+
if (typeof console !== "undefined") {
|
|
207
|
+
console.warn(`[yable] Failed to persist state for key "${key}" (storage may be full)`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function useTablePersistence(options) {
|
|
212
|
+
const {
|
|
213
|
+
key,
|
|
214
|
+
persistedKeys = DEFAULT_PERSISTED_KEYS,
|
|
215
|
+
debounce: debounceMs = 100,
|
|
216
|
+
version = 0,
|
|
217
|
+
storage: customStorage
|
|
218
|
+
} = options;
|
|
219
|
+
const storage = useMemo(() => resolveStorage(customStorage), [customStorage]);
|
|
220
|
+
const initialState = useMemo(
|
|
221
|
+
() => readState(storage, key, version, persistedKeys),
|
|
222
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally read only on mount
|
|
223
|
+
[]
|
|
224
|
+
);
|
|
225
|
+
const [state, setState] = useState(initialState);
|
|
226
|
+
const timerRef = useRef(null);
|
|
227
|
+
const keyRef = useRef(key);
|
|
228
|
+
keyRef.current = key;
|
|
229
|
+
const versionRef = useRef(version);
|
|
230
|
+
versionRef.current = version;
|
|
231
|
+
const persistedKeysRef = useRef(persistedKeys);
|
|
232
|
+
persistedKeysRef.current = persistedKeys;
|
|
233
|
+
const debounceRef = useRef(debounceMs);
|
|
234
|
+
debounceRef.current = debounceMs;
|
|
235
|
+
const storageRef = useRef(storage);
|
|
236
|
+
storageRef.current = storage;
|
|
237
|
+
const onStateChange = useCallback((updater) => {
|
|
238
|
+
setState((prev) => {
|
|
239
|
+
const next = functionalUpdate(updater, prev);
|
|
240
|
+
if (timerRef.current !== null) {
|
|
241
|
+
clearTimeout(timerRef.current);
|
|
242
|
+
}
|
|
243
|
+
timerRef.current = setTimeout(() => {
|
|
244
|
+
const sliced = pick(
|
|
245
|
+
next,
|
|
246
|
+
persistedKeysRef.current
|
|
247
|
+
);
|
|
248
|
+
writeState(storageRef.current, keyRef.current, versionRef.current, sliced);
|
|
249
|
+
timerRef.current = null;
|
|
250
|
+
}, debounceRef.current);
|
|
251
|
+
return next;
|
|
252
|
+
});
|
|
253
|
+
}, []);
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
return () => {
|
|
256
|
+
if (timerRef.current !== null) {
|
|
257
|
+
clearTimeout(timerRef.current);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}, []);
|
|
261
|
+
const clearPersistedState = useCallback(() => {
|
|
262
|
+
const s = storageRef.current;
|
|
263
|
+
if (s) {
|
|
264
|
+
try {
|
|
265
|
+
s.removeItem(keyRef.current);
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}, []);
|
|
270
|
+
return { initialState, state, onStateChange, clearPersistedState };
|
|
271
|
+
}
|
|
115
272
|
var EMPTY_RESULT = {
|
|
116
273
|
virtualRows: [],
|
|
117
274
|
totalHeight: 0,
|
|
@@ -125,11 +282,14 @@ function useVirtualization({
|
|
|
125
282
|
overscan = 5,
|
|
126
283
|
estimateRowHeight: _estimateRowHeight,
|
|
127
284
|
pretextHeights,
|
|
128
|
-
pretextPrefixSums
|
|
285
|
+
pretextPrefixSums,
|
|
286
|
+
columnSizingHash
|
|
129
287
|
}) {
|
|
130
288
|
const hasPretextHeights = !!(pretextHeights && pretextPrefixSums && pretextHeights.length >= totalRows);
|
|
131
289
|
const isFixedHeight = typeof rowHeight === "number" && !hasPretextHeights;
|
|
132
290
|
const heightCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
291
|
+
const heightCacheVersionRef = useRef(0);
|
|
292
|
+
const [heightCacheVersion, setHeightCacheVersion] = useState(0);
|
|
133
293
|
const getRowHeight = useCallback(
|
|
134
294
|
(index) => {
|
|
135
295
|
if (hasPretextHeights) return pretextHeights[index];
|
|
@@ -140,7 +300,9 @@ function useVirtualization({
|
|
|
140
300
|
heightCacheRef.current.set(index, height);
|
|
141
301
|
return height;
|
|
142
302
|
},
|
|
143
|
-
|
|
303
|
+
// heightCacheVersion forces a new callback identity after cache invalidation
|
|
304
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
305
|
+
[rowHeight, isFixedHeight, hasPretextHeights, pretextHeights, heightCacheVersion]
|
|
144
306
|
);
|
|
145
307
|
const [scrollState, setScrollState] = useState({ scrollTop: 0, containerHeight: 0 });
|
|
146
308
|
const rafRef = useRef(null);
|
|
@@ -193,6 +355,18 @@ function useVirtualization({
|
|
|
193
355
|
heightCacheRef.current.clear();
|
|
194
356
|
}
|
|
195
357
|
}, [totalRows, isFixedHeight]);
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
if (!isFixedHeight && columnSizingHash !== void 0) {
|
|
360
|
+
heightCacheRef.current.clear();
|
|
361
|
+
heightCacheVersionRef.current += 1;
|
|
362
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
363
|
+
}
|
|
364
|
+
}, [columnSizingHash]);
|
|
365
|
+
const invalidateRowHeights = useCallback(() => {
|
|
366
|
+
heightCacheRef.current.clear();
|
|
367
|
+
heightCacheVersionRef.current += 1;
|
|
368
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
369
|
+
}, []);
|
|
196
370
|
const scrollTo = useCallback(
|
|
197
371
|
(index) => {
|
|
198
372
|
const container = containerRef.current;
|
|
@@ -210,7 +384,15 @@ function useVirtualization({
|
|
|
210
384
|
container.scrollTop = offset;
|
|
211
385
|
}
|
|
212
386
|
},
|
|
213
|
-
[
|
|
387
|
+
[
|
|
388
|
+
containerRef,
|
|
389
|
+
totalRows,
|
|
390
|
+
rowHeight,
|
|
391
|
+
isFixedHeight,
|
|
392
|
+
getRowHeight,
|
|
393
|
+
hasPretextHeights,
|
|
394
|
+
pretextPrefixSums
|
|
395
|
+
]
|
|
214
396
|
);
|
|
215
397
|
const totalHeight = useMemo(() => {
|
|
216
398
|
if (totalRows === 0) return 0;
|
|
@@ -221,10 +403,18 @@ function useVirtualization({
|
|
|
221
403
|
total += getRowHeight(i);
|
|
222
404
|
}
|
|
223
405
|
return total;
|
|
224
|
-
}, [
|
|
406
|
+
}, [
|
|
407
|
+
totalRows,
|
|
408
|
+
rowHeight,
|
|
409
|
+
isFixedHeight,
|
|
410
|
+
getRowHeight,
|
|
411
|
+
hasPretextHeights,
|
|
412
|
+
pretextPrefixSums,
|
|
413
|
+
heightCacheVersion
|
|
414
|
+
]);
|
|
225
415
|
const { scrollTop, containerHeight } = scrollState;
|
|
226
416
|
if (totalRows === 0) {
|
|
227
|
-
return { ...EMPTY_RESULT, scrollTo };
|
|
417
|
+
return { ...EMPTY_RESULT, scrollTo, invalidateRowHeights };
|
|
228
418
|
}
|
|
229
419
|
if (containerHeight === 0) {
|
|
230
420
|
return {
|
|
@@ -232,7 +422,8 @@ function useVirtualization({
|
|
|
232
422
|
totalHeight,
|
|
233
423
|
startIndex: 0,
|
|
234
424
|
endIndex: 0,
|
|
235
|
-
scrollTo
|
|
425
|
+
scrollTo,
|
|
426
|
+
invalidateRowHeights
|
|
236
427
|
};
|
|
237
428
|
}
|
|
238
429
|
let startIndex = 0;
|
|
@@ -264,10 +455,7 @@ function useVirtualization({
|
|
|
264
455
|
} else if (isFixedHeight) {
|
|
265
456
|
const fixedH = rowHeight;
|
|
266
457
|
startIndex = Math.floor(scrollTop / fixedH);
|
|
267
|
-
endIndex = Math.min(
|
|
268
|
-
totalRows - 1,
|
|
269
|
-
Math.ceil((scrollTop + containerHeight) / fixedH) - 1
|
|
270
|
-
);
|
|
458
|
+
endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / fixedH) - 1);
|
|
271
459
|
} else {
|
|
272
460
|
let accum = 0;
|
|
273
461
|
let foundStart = false;
|
|
@@ -331,7 +519,164 @@ function useVirtualization({
|
|
|
331
519
|
totalHeight,
|
|
332
520
|
startIndex: overscanStart,
|
|
333
521
|
endIndex: overscanEnd,
|
|
334
|
-
scrollTo
|
|
522
|
+
scrollTo,
|
|
523
|
+
invalidateRowHeights
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function binarySearchOffsets(offsets, target) {
|
|
527
|
+
let low = 0;
|
|
528
|
+
let high = offsets.length - 1;
|
|
529
|
+
while (low < high) {
|
|
530
|
+
const mid = low + high >>> 1;
|
|
531
|
+
if (offsets[mid + 1] <= target) {
|
|
532
|
+
low = mid + 1;
|
|
533
|
+
} else {
|
|
534
|
+
high = mid;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return low;
|
|
538
|
+
}
|
|
539
|
+
function useColumnVirtualization({
|
|
540
|
+
containerRef,
|
|
541
|
+
columns,
|
|
542
|
+
overscan = 2,
|
|
543
|
+
enabled = true
|
|
544
|
+
}) {
|
|
545
|
+
const [scrollState, setScrollState] = useState({
|
|
546
|
+
scrollLeft: 0,
|
|
547
|
+
containerWidth: 0
|
|
548
|
+
});
|
|
549
|
+
const rafRef = useRef(null);
|
|
550
|
+
const sizes = useMemo(() => columns.map((column) => column.getSize()), [columns]);
|
|
551
|
+
const offsets = useMemo(() => {
|
|
552
|
+
const next = new Array(columns.length + 1);
|
|
553
|
+
next[0] = 0;
|
|
554
|
+
for (let i = 0; i < columns.length; i++) {
|
|
555
|
+
next[i + 1] = next[i] + (sizes[i] ?? 0);
|
|
556
|
+
}
|
|
557
|
+
return next;
|
|
558
|
+
}, [columns.length, sizes]);
|
|
559
|
+
const totalWidth = offsets[offsets.length - 1] ?? 0;
|
|
560
|
+
useEffect(() => {
|
|
561
|
+
const container = containerRef.current;
|
|
562
|
+
if (!container) return;
|
|
563
|
+
setScrollState({
|
|
564
|
+
scrollLeft: container.scrollLeft,
|
|
565
|
+
containerWidth: container.clientWidth
|
|
566
|
+
});
|
|
567
|
+
const handleScroll = () => {
|
|
568
|
+
if (rafRef.current !== null) return;
|
|
569
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
570
|
+
rafRef.current = null;
|
|
571
|
+
const el = containerRef.current;
|
|
572
|
+
if (!el) return;
|
|
573
|
+
setScrollState({
|
|
574
|
+
scrollLeft: el.scrollLeft,
|
|
575
|
+
containerWidth: el.clientWidth
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
};
|
|
579
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
580
|
+
let resizeObserver;
|
|
581
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
582
|
+
resizeObserver = new ResizeObserver(() => {
|
|
583
|
+
const el = containerRef.current;
|
|
584
|
+
if (!el) return;
|
|
585
|
+
setScrollState((prev) => {
|
|
586
|
+
const nextWidth = el.clientWidth;
|
|
587
|
+
if (prev.containerWidth === nextWidth && prev.scrollLeft === el.scrollLeft) {
|
|
588
|
+
return prev;
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
scrollLeft: el.scrollLeft,
|
|
592
|
+
containerWidth: nextWidth
|
|
593
|
+
};
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
resizeObserver.observe(container);
|
|
597
|
+
}
|
|
598
|
+
return () => {
|
|
599
|
+
container.removeEventListener("scroll", handleScroll);
|
|
600
|
+
if (rafRef.current !== null) {
|
|
601
|
+
cancelAnimationFrame(rafRef.current);
|
|
602
|
+
rafRef.current = null;
|
|
603
|
+
}
|
|
604
|
+
resizeObserver?.disconnect();
|
|
605
|
+
};
|
|
606
|
+
}, [containerRef]);
|
|
607
|
+
const scrollToIndex = useCallback(
|
|
608
|
+
(index) => {
|
|
609
|
+
const container = containerRef.current;
|
|
610
|
+
if (!container || columns.length === 0) return;
|
|
611
|
+
const clampedIndex = Math.max(0, Math.min(index, columns.length - 1));
|
|
612
|
+
container.scrollLeft = offsets[clampedIndex] ?? 0;
|
|
613
|
+
},
|
|
614
|
+
[columns.length, containerRef, offsets]
|
|
615
|
+
);
|
|
616
|
+
if (!enabled || columns.length === 0) {
|
|
617
|
+
return {
|
|
618
|
+
virtualColumns: columns.map((column, index) => ({
|
|
619
|
+
column,
|
|
620
|
+
index,
|
|
621
|
+
start: offsets[index] ?? 0,
|
|
622
|
+
size: sizes[index] ?? 0
|
|
623
|
+
})),
|
|
624
|
+
startOffset: 0,
|
|
625
|
+
endOffset: 0,
|
|
626
|
+
totalWidth,
|
|
627
|
+
visibleWidth: totalWidth,
|
|
628
|
+
startIndex: 0,
|
|
629
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
630
|
+
isVirtualized: false,
|
|
631
|
+
scrollToIndex
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
const { scrollLeft, containerWidth } = scrollState;
|
|
635
|
+
if (containerWidth <= 0 || totalWidth <= containerWidth) {
|
|
636
|
+
return {
|
|
637
|
+
virtualColumns: columns.map((column, index) => ({
|
|
638
|
+
column,
|
|
639
|
+
index,
|
|
640
|
+
start: offsets[index] ?? 0,
|
|
641
|
+
size: sizes[index] ?? 0
|
|
642
|
+
})),
|
|
643
|
+
startOffset: 0,
|
|
644
|
+
endOffset: 0,
|
|
645
|
+
totalWidth,
|
|
646
|
+
visibleWidth: totalWidth,
|
|
647
|
+
startIndex: 0,
|
|
648
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
649
|
+
isVirtualized: false,
|
|
650
|
+
scrollToIndex
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
const startIndex = binarySearchOffsets(offsets, scrollLeft);
|
|
654
|
+
const endBoundary = scrollLeft + containerWidth;
|
|
655
|
+
const endIndex = binarySearchOffsets(offsets, Math.max(scrollLeft, endBoundary - 1));
|
|
656
|
+
const overscanStart = Math.max(0, startIndex - overscan);
|
|
657
|
+
const overscanEnd = Math.min(columns.length - 1, endIndex + overscan);
|
|
658
|
+
const virtualColumns = [];
|
|
659
|
+
for (let i = overscanStart; i <= overscanEnd; i++) {
|
|
660
|
+
virtualColumns.push({
|
|
661
|
+
column: columns[i],
|
|
662
|
+
index: i,
|
|
663
|
+
start: offsets[i] ?? 0,
|
|
664
|
+
size: sizes[i] ?? 0
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
const startOffset = offsets[overscanStart] ?? 0;
|
|
668
|
+
const visibleWidth = (offsets[overscanEnd + 1] ?? totalWidth) - startOffset;
|
|
669
|
+
const endOffset = totalWidth - (offsets[overscanEnd + 1] ?? totalWidth);
|
|
670
|
+
return {
|
|
671
|
+
virtualColumns,
|
|
672
|
+
startOffset,
|
|
673
|
+
endOffset,
|
|
674
|
+
totalWidth,
|
|
675
|
+
visibleWidth,
|
|
676
|
+
startIndex: overscanStart,
|
|
677
|
+
endIndex: overscanEnd,
|
|
678
|
+
isVirtualized: true,
|
|
679
|
+
scrollToIndex
|
|
335
680
|
};
|
|
336
681
|
}
|
|
337
682
|
var pretextPromise = null;
|
|
@@ -384,7 +729,12 @@ function usePretextMeasurement({
|
|
|
384
729
|
}
|
|
385
730
|
prepareTimeRef.current = performance.now() - start;
|
|
386
731
|
return result;
|
|
387
|
-
}, [
|
|
732
|
+
}, [
|
|
733
|
+
pretext,
|
|
734
|
+
enabled,
|
|
735
|
+
data,
|
|
736
|
+
columns.map((c) => `${c.columnId}:${c.font}:${c.fixedHeight ? "F" : "T"}`).join("|")
|
|
737
|
+
]);
|
|
388
738
|
const measurement = useMemo(() => {
|
|
389
739
|
if (!pretext || !preparedCells) {
|
|
390
740
|
return { rowHeights: null, prefixSums: null, totalHeight: 0 };
|
|
@@ -422,6 +772,7 @@ function usePretextMeasurement({
|
|
|
422
772
|
return {
|
|
423
773
|
rowHeights,
|
|
424
774
|
prefixSums,
|
|
775
|
+
// Safe: prefixSums has length data.length + 1, so [data.length] always exists
|
|
425
776
|
totalHeight: prefixSums[data.length]
|
|
426
777
|
};
|
|
427
778
|
}, [pretext, preparedCells, columnWidthsKey, minRowHeight, data.length]);
|
|
@@ -686,18 +1037,10 @@ function CellDate({
|
|
|
686
1037
|
if (raw == null) return null;
|
|
687
1038
|
const date = raw instanceof Date ? raw : new Date(String(raw));
|
|
688
1039
|
if (isNaN(date.getTime())) return /* @__PURE__ */ jsx("span", { className: "yable-cell-date", children: String(raw) });
|
|
689
|
-
const formatter =
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
timeZone: "UTC"
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
if (typeof format === "object") {
|
|
697
|
-
return new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" });
|
|
698
|
-
}
|
|
699
|
-
return null;
|
|
700
|
-
}, [format, locale]);
|
|
1040
|
+
const formatter = typeof format === "string" && format !== "relative" ? new Intl.DateTimeFormat(locale, {
|
|
1041
|
+
...PRESETS[format],
|
|
1042
|
+
timeZone: "UTC"
|
|
1043
|
+
}) : typeof format === "object" ? new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" }) : null;
|
|
701
1044
|
const formatted = format === "relative" ? formatRelative(date) : formatter ? formatter.format(date) : date.toLocaleDateString(locale);
|
|
702
1045
|
return /* @__PURE__ */ jsx("span", { className: `yable-cell-date ${className ?? ""}`, title: date.toISOString(), children: formatted });
|
|
703
1046
|
}
|
|
@@ -708,8 +1051,14 @@ var measureRecipe9 = {
|
|
|
708
1051
|
padding: 20
|
|
709
1052
|
};
|
|
710
1053
|
function isSafeUrl(url) {
|
|
711
|
-
const normalized = String(url).
|
|
712
|
-
|
|
1054
|
+
const normalized = String(url).trim();
|
|
1055
|
+
if (/^[/#?]/.test(normalized)) return true;
|
|
1056
|
+
try {
|
|
1057
|
+
const parsed = new URL(normalized, "https://placeholder.invalid");
|
|
1058
|
+
return ["http:", "https:", "mailto:", "tel:"].includes(parsed.protocol);
|
|
1059
|
+
} catch {
|
|
1060
|
+
return false;
|
|
1061
|
+
}
|
|
713
1062
|
}
|
|
714
1063
|
function CellLink({
|
|
715
1064
|
context,
|
|
@@ -886,7 +1235,7 @@ function useTableContext() {
|
|
|
886
1235
|
const ctx = useContext(TableContext);
|
|
887
1236
|
if (!ctx) {
|
|
888
1237
|
throw new Error(
|
|
889
|
-
"[yable] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
1238
|
+
"[yable E001] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
890
1239
|
);
|
|
891
1240
|
}
|
|
892
1241
|
return ctx;
|
|
@@ -936,12 +1285,234 @@ function SortIndicator({ direction, index }) {
|
|
|
936
1285
|
}
|
|
937
1286
|
);
|
|
938
1287
|
}
|
|
1288
|
+
function formatValue(value) {
|
|
1289
|
+
if (value == null || value === "") return "(empty)";
|
|
1290
|
+
if (typeof value === "string") return value;
|
|
1291
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1292
|
+
if (value instanceof Date) return value.toISOString();
|
|
1293
|
+
return JSON.stringify(value);
|
|
1294
|
+
}
|
|
1295
|
+
function SetFilter({ column, className }) {
|
|
1296
|
+
const [open, setOpen] = useState(false);
|
|
1297
|
+
const filterValue = column.getFilterValue();
|
|
1298
|
+
const selectedValues = Array.isArray(filterValue) ? filterValue : filterValue == null || filterValue === "" ? [] : [filterValue];
|
|
1299
|
+
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
1300
|
+
const options = Array.from(facetedUniqueValues.entries()).map(([value, count]) => ({
|
|
1301
|
+
value,
|
|
1302
|
+
count,
|
|
1303
|
+
label: formatValue(value)
|
|
1304
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
1305
|
+
const selectedSet = new Set(selectedValues);
|
|
1306
|
+
const toggleValue = (value) => {
|
|
1307
|
+
const next = new Set(selectedSet);
|
|
1308
|
+
if (next.has(value)) {
|
|
1309
|
+
next.delete(value);
|
|
1310
|
+
} else {
|
|
1311
|
+
next.add(value);
|
|
1312
|
+
}
|
|
1313
|
+
const nextValues = Array.from(next);
|
|
1314
|
+
column.setFilterValue(nextValues.length > 0 ? nextValues : void 0);
|
|
1315
|
+
};
|
|
1316
|
+
const headerLabel = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1317
|
+
return /* @__PURE__ */ jsxs(
|
|
1318
|
+
"div",
|
|
1319
|
+
{
|
|
1320
|
+
className: ["yable-set-filter", className].filter(Boolean).join(" "),
|
|
1321
|
+
style: { position: "relative" },
|
|
1322
|
+
children: [
|
|
1323
|
+
/* @__PURE__ */ jsx(
|
|
1324
|
+
"button",
|
|
1325
|
+
{
|
|
1326
|
+
type: "button",
|
|
1327
|
+
className: "yable-set-filter-trigger",
|
|
1328
|
+
"aria-haspopup": "dialog",
|
|
1329
|
+
"aria-expanded": open,
|
|
1330
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1331
|
+
style: {
|
|
1332
|
+
width: "100%",
|
|
1333
|
+
minHeight: 28,
|
|
1334
|
+
padding: "4px 8px",
|
|
1335
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1336
|
+
borderRadius: 6,
|
|
1337
|
+
background: "transparent",
|
|
1338
|
+
font: "inherit",
|
|
1339
|
+
textAlign: "left",
|
|
1340
|
+
cursor: "pointer"
|
|
1341
|
+
},
|
|
1342
|
+
children: selectedValues.length > 0 ? `${selectedValues.length} selected` : `Filter ${headerLabel}`
|
|
1343
|
+
}
|
|
1344
|
+
),
|
|
1345
|
+
open && /* @__PURE__ */ jsxs(
|
|
1346
|
+
"div",
|
|
1347
|
+
{
|
|
1348
|
+
role: "dialog",
|
|
1349
|
+
"aria-label": `${headerLabel} set filter`,
|
|
1350
|
+
className: "yable-set-filter-popover",
|
|
1351
|
+
style: {
|
|
1352
|
+
position: "absolute",
|
|
1353
|
+
insetInlineStart: 0,
|
|
1354
|
+
top: "calc(100% + 4px)",
|
|
1355
|
+
zIndex: 20,
|
|
1356
|
+
width: 220,
|
|
1357
|
+
maxHeight: 240,
|
|
1358
|
+
overflow: "auto",
|
|
1359
|
+
padding: 8,
|
|
1360
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1361
|
+
borderRadius: 8,
|
|
1362
|
+
background: "var(--yable-color-bg, #fff)",
|
|
1363
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.12)"
|
|
1364
|
+
},
|
|
1365
|
+
children: [
|
|
1366
|
+
/* @__PURE__ */ jsxs(
|
|
1367
|
+
"div",
|
|
1368
|
+
{
|
|
1369
|
+
style: {
|
|
1370
|
+
display: "flex",
|
|
1371
|
+
alignItems: "center",
|
|
1372
|
+
justifyContent: "space-between",
|
|
1373
|
+
gap: 8,
|
|
1374
|
+
marginBottom: 8
|
|
1375
|
+
},
|
|
1376
|
+
children: [
|
|
1377
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: 12 }, children: headerLabel }),
|
|
1378
|
+
selectedValues.length > 0 && /* @__PURE__ */ jsx(
|
|
1379
|
+
"button",
|
|
1380
|
+
{
|
|
1381
|
+
type: "button",
|
|
1382
|
+
onClick: () => column.setFilterValue(void 0),
|
|
1383
|
+
style: {
|
|
1384
|
+
border: "none",
|
|
1385
|
+
background: "transparent",
|
|
1386
|
+
padding: 0,
|
|
1387
|
+
cursor: "pointer",
|
|
1388
|
+
fontSize: 12
|
|
1389
|
+
},
|
|
1390
|
+
children: "Clear"
|
|
1391
|
+
}
|
|
1392
|
+
)
|
|
1393
|
+
]
|
|
1394
|
+
}
|
|
1395
|
+
),
|
|
1396
|
+
/* @__PURE__ */ jsxs("div", { role: "group", "aria-label": `${headerLabel} options`, children: [
|
|
1397
|
+
options.length === 0 && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, opacity: 0.75 }, children: "No values" }),
|
|
1398
|
+
options.map((option) => {
|
|
1399
|
+
const checked = selectedSet.has(option.value);
|
|
1400
|
+
return /* @__PURE__ */ jsxs(
|
|
1401
|
+
"label",
|
|
1402
|
+
{
|
|
1403
|
+
style: {
|
|
1404
|
+
display: "flex",
|
|
1405
|
+
alignItems: "center",
|
|
1406
|
+
gap: 8,
|
|
1407
|
+
padding: "4px 0",
|
|
1408
|
+
fontSize: 12
|
|
1409
|
+
},
|
|
1410
|
+
children: [
|
|
1411
|
+
/* @__PURE__ */ jsx(
|
|
1412
|
+
"input",
|
|
1413
|
+
{
|
|
1414
|
+
type: "checkbox",
|
|
1415
|
+
checked,
|
|
1416
|
+
onChange: () => toggleValue(option.value)
|
|
1417
|
+
}
|
|
1418
|
+
),
|
|
1419
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: option.label }),
|
|
1420
|
+
/* @__PURE__ */ jsx("span", { style: { opacity: 0.6 }, children: option.count })
|
|
1421
|
+
]
|
|
1422
|
+
},
|
|
1423
|
+
`${option.label}-${option.count}`
|
|
1424
|
+
);
|
|
1425
|
+
})
|
|
1426
|
+
] })
|
|
1427
|
+
]
|
|
1428
|
+
}
|
|
1429
|
+
)
|
|
1430
|
+
]
|
|
1431
|
+
}
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
function isSetCompatibleValue(value) {
|
|
1435
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1436
|
+
}
|
|
1437
|
+
function inferFilterVariant(column) {
|
|
1438
|
+
const meta = column.columnDef.meta ?? {};
|
|
1439
|
+
if (meta.filterVariant) return meta.filterVariant;
|
|
1440
|
+
const uniqueValues = column.getFacetedUniqueValues();
|
|
1441
|
+
if (uniqueValues.size > 0 && uniqueValues.size <= 12) {
|
|
1442
|
+
const allValuesSupported = Array.from(uniqueValues.keys()).every(isSetCompatibleValue);
|
|
1443
|
+
if (allValuesSupported) return "set";
|
|
1444
|
+
}
|
|
1445
|
+
return "text";
|
|
1446
|
+
}
|
|
1447
|
+
function FloatingFilter({ column }) {
|
|
1448
|
+
const variant = inferFilterVariant(column);
|
|
1449
|
+
if (!column.getCanFilter()) {
|
|
1450
|
+
return /* @__PURE__ */ jsx("div", { style: { minHeight: 28 }, "aria-hidden": "true" });
|
|
1451
|
+
}
|
|
1452
|
+
if (variant === "set") {
|
|
1453
|
+
return /* @__PURE__ */ jsx(SetFilter, { column });
|
|
1454
|
+
}
|
|
1455
|
+
const filterValue = column.getFilterValue();
|
|
1456
|
+
const normalizedValue = typeof filterValue === "string" || typeof filterValue === "number" ? String(filterValue) : "";
|
|
1457
|
+
const label = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1458
|
+
return /* @__PURE__ */ jsx("label", { style: { display: "block" }, children: /* @__PURE__ */ jsx(
|
|
1459
|
+
"input",
|
|
1460
|
+
{
|
|
1461
|
+
"aria-label": `Filter ${label}`,
|
|
1462
|
+
className: "yable-floating-filter-input",
|
|
1463
|
+
value: normalizedValue,
|
|
1464
|
+
onChange: (event) => {
|
|
1465
|
+
const nextValue = event.target.value;
|
|
1466
|
+
column.setFilterValue(nextValue === "" ? void 0 : nextValue);
|
|
1467
|
+
},
|
|
1468
|
+
placeholder: `Filter ${label}`,
|
|
1469
|
+
style: {
|
|
1470
|
+
width: "100%",
|
|
1471
|
+
minHeight: 28,
|
|
1472
|
+
padding: "4px 8px",
|
|
1473
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1474
|
+
borderRadius: 6,
|
|
1475
|
+
background: "transparent",
|
|
1476
|
+
font: "inherit"
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
) });
|
|
1480
|
+
}
|
|
939
1481
|
var DRAG_MIME = "application/yable-column";
|
|
940
1482
|
function TableHeader({
|
|
941
|
-
table
|
|
1483
|
+
table,
|
|
1484
|
+
floatingFilters = false
|
|
942
1485
|
}) {
|
|
943
1486
|
const headerGroups = table.getHeaderGroups();
|
|
944
|
-
|
|
1487
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
1488
|
+
return /* @__PURE__ */ jsxs("thead", { className: "yable-thead", children: [
|
|
1489
|
+
headerGroups.map((headerGroup) => /* @__PURE__ */ jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(HeaderCell, { header, table }, header.id)) }, headerGroup.id)),
|
|
1490
|
+
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`)) })
|
|
1491
|
+
] });
|
|
1492
|
+
}
|
|
1493
|
+
function FloatingFilterCell({
|
|
1494
|
+
column
|
|
1495
|
+
}) {
|
|
1496
|
+
const style = useMemo(() => {
|
|
1497
|
+
const next = {
|
|
1498
|
+
width: column.getSize(),
|
|
1499
|
+
minWidth: column.columnDef.minSize,
|
|
1500
|
+
maxWidth: column.columnDef.maxSize,
|
|
1501
|
+
padding: 6,
|
|
1502
|
+
verticalAlign: "top"
|
|
1503
|
+
};
|
|
1504
|
+
const pinned = column.getIsPinned();
|
|
1505
|
+
if (pinned) {
|
|
1506
|
+
next.position = "sticky";
|
|
1507
|
+
if (pinned === "left") {
|
|
1508
|
+
next.left = column.getStart("left");
|
|
1509
|
+
} else {
|
|
1510
|
+
next.right = column.getStart("right");
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
return next;
|
|
1514
|
+
}, [column]);
|
|
1515
|
+
return /* @__PURE__ */ jsx("th", { className: "yable-th yable-th--filter", role: "columnheader", style, children: /* @__PURE__ */ jsx(FloatingFilter, { column }) });
|
|
945
1516
|
}
|
|
946
1517
|
function HeaderCell({
|
|
947
1518
|
header,
|
|
@@ -995,11 +1566,6 @@ function HeaderCell({
|
|
|
995
1566
|
const handleDragStart = useCallback(
|
|
996
1567
|
(e) => {
|
|
997
1568
|
if (!canReorder) return;
|
|
998
|
-
const target = e.target;
|
|
999
|
-
if (target && target.closest(".yable-resize-handle")) {
|
|
1000
|
-
e.preventDefault();
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
1569
|
e.stopPropagation();
|
|
1004
1570
|
e.dataTransfer.effectAllowed = "move";
|
|
1005
1571
|
try {
|
|
@@ -1007,8 +1573,9 @@ function HeaderCell({
|
|
|
1007
1573
|
e.dataTransfer.setData("text/plain", column.id);
|
|
1008
1574
|
} catch {
|
|
1009
1575
|
}
|
|
1576
|
+
table.setColumnDragActive(true);
|
|
1010
1577
|
},
|
|
1011
|
-
[canReorder, column.id]
|
|
1578
|
+
[canReorder, column.id, table]
|
|
1012
1579
|
);
|
|
1013
1580
|
const handleDragOver = useCallback(
|
|
1014
1581
|
(e) => {
|
|
@@ -1030,17 +1597,15 @@ function HeaderCell({
|
|
|
1030
1597
|
},
|
|
1031
1598
|
[canReorder]
|
|
1032
1599
|
);
|
|
1033
|
-
const handleDragLeave = useCallback(
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
if (next && e.currentTarget.contains(next)) return;
|
|
1037
|
-
setDragOver(null);
|
|
1038
|
-
},
|
|
1039
|
-
[]
|
|
1040
|
-
);
|
|
1041
|
-
const handleDragEnd = useCallback(() => {
|
|
1600
|
+
const handleDragLeave = useCallback((e) => {
|
|
1601
|
+
const next = e.relatedTarget;
|
|
1602
|
+
if (next && e.currentTarget.contains(next)) return;
|
|
1042
1603
|
setDragOver(null);
|
|
1043
1604
|
}, []);
|
|
1605
|
+
const handleDragEnd = useCallback(() => {
|
|
1606
|
+
setDragOver(null);
|
|
1607
|
+
table.setColumnDragActive(false);
|
|
1608
|
+
}, [table]);
|
|
1044
1609
|
const handleDrop = useCallback(
|
|
1045
1610
|
(e) => {
|
|
1046
1611
|
if (!canReorder) return;
|
|
@@ -1050,6 +1615,7 @@ function HeaderCell({
|
|
|
1050
1615
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
1051
1616
|
const insertAfter = e.clientX >= rect.left + rect.width / 2;
|
|
1052
1617
|
setDragOver(null);
|
|
1618
|
+
table.setColumnDragActive(false);
|
|
1053
1619
|
if (!sourceId || sourceId === column.id) return;
|
|
1054
1620
|
const state = table.getState();
|
|
1055
1621
|
const allLeafs = table.getAllLeafColumns();
|
|
@@ -1100,24 +1666,24 @@ function HeaderCell({
|
|
|
1100
1666
|
"aria-sort": sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : canSort ? "none" : void 0,
|
|
1101
1667
|
role: "columnheader",
|
|
1102
1668
|
colSpan: header.colSpan,
|
|
1103
|
-
draggable: canReorder || void 0,
|
|
1104
1669
|
onClick: handleHeaderClick,
|
|
1105
|
-
onDragStart: canReorder ? handleDragStart : void 0,
|
|
1106
1670
|
onDragOver: canReorder ? handleDragOver : void 0,
|
|
1107
1671
|
onDragLeave: canReorder ? handleDragLeave : void 0,
|
|
1108
|
-
onDragEnd: canReorder ? handleDragEnd : void 0,
|
|
1109
1672
|
onDrop: canReorder ? handleDrop : void 0,
|
|
1110
1673
|
children: [
|
|
1111
|
-
/* @__PURE__ */ jsxs(
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1674
|
+
/* @__PURE__ */ jsxs(
|
|
1675
|
+
"div",
|
|
1676
|
+
{
|
|
1677
|
+
className: "yable-th-content",
|
|
1678
|
+
draggable: canReorder || void 0,
|
|
1679
|
+
onDragStart: canReorder ? handleDragStart : void 0,
|
|
1680
|
+
onDragEnd: canReorder ? handleDragEnd : void 0,
|
|
1681
|
+
children: [
|
|
1682
|
+
/* @__PURE__ */ jsx("span", { children: headerContent }),
|
|
1683
|
+
canSort && /* @__PURE__ */ jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
|
|
1684
|
+
]
|
|
1685
|
+
}
|
|
1686
|
+
),
|
|
1121
1687
|
canResize && /* @__PURE__ */ jsx(
|
|
1122
1688
|
"div",
|
|
1123
1689
|
{
|
|
@@ -1125,9 +1691,7 @@ function HeaderCell({
|
|
|
1125
1691
|
"data-resizing": column.getIsResizing() || void 0,
|
|
1126
1692
|
onMouseDown: startResize,
|
|
1127
1693
|
onTouchStart: startResize,
|
|
1128
|
-
onClick: handleResizeClick
|
|
1129
|
-
draggable: false,
|
|
1130
|
-
onDragStart: (e) => e.preventDefault()
|
|
1694
|
+
onClick: handleResizeClick
|
|
1131
1695
|
}
|
|
1132
1696
|
)
|
|
1133
1697
|
]
|
|
@@ -1241,6 +1805,10 @@ function TableCell({
|
|
|
1241
1805
|
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
1242
1806
|
const cellErrorMessage = table.getCellErrorMessage(cell.row.id, column.id);
|
|
1243
1807
|
const cellConflictWith = table.getCellConflictWith(cell.row.id, column.id);
|
|
1808
|
+
const selectionRange = table.getCellSelectionRange();
|
|
1809
|
+
const selectionEdges = table.getCellSelectionEdges(rowIndex, columnIndex);
|
|
1810
|
+
const isCellSelected = selectionEdges !== null;
|
|
1811
|
+
const isMultiCellSelection = selectionRange !== null && (selectionRange.start.rowIndex !== selectionRange.end.rowIndex || selectionRange.start.columnIndex !== selectionRange.end.columnIndex);
|
|
1244
1812
|
const overrideValue = cellStatus !== "idle" ? table.getCellRenderValue(cell.row.id, column.id) : void 0;
|
|
1245
1813
|
let content;
|
|
1246
1814
|
const cellDef = column.columnDef.cell;
|
|
@@ -1264,23 +1832,17 @@ function TableCell({
|
|
|
1264
1832
|
}
|
|
1265
1833
|
const handleClick = useCallback(
|
|
1266
1834
|
(e) => {
|
|
1267
|
-
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1268
|
-
const clickTarget = e.target;
|
|
1269
|
-
if (!isInteractiveClickTarget(clickTarget)) {
|
|
1270
|
-
const currentTarget = e.currentTarget;
|
|
1271
|
-
currentTarget.focus({ preventScroll: true });
|
|
1272
|
-
}
|
|
1273
1835
|
table.events.emit("cell:click", {
|
|
1274
1836
|
cell,
|
|
1275
1837
|
row: cell.row,
|
|
1276
1838
|
column: cell.column,
|
|
1277
1839
|
event: e.nativeEvent
|
|
1278
1840
|
});
|
|
1279
|
-
if (canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing) {
|
|
1841
|
+
if (canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing && !isMultiCellSelection && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
1280
1842
|
table.startEditing(cell.row.id, column.id);
|
|
1281
1843
|
}
|
|
1282
1844
|
},
|
|
1283
|
-
[cell, column,
|
|
1845
|
+
[cell, column, isAlwaysEditable, isEditing, isMultiCellSelection, table]
|
|
1284
1846
|
);
|
|
1285
1847
|
const handleDoubleClick = useCallback(
|
|
1286
1848
|
(e) => {
|
|
@@ -1308,15 +1870,46 @@ function TableCell({
|
|
|
1308
1870
|
if (!keyboardNavigationEnabled) return;
|
|
1309
1871
|
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1310
1872
|
}, [columnIndex, keyboardNavigationEnabled, rowIndex, table]);
|
|
1873
|
+
const handleMouseDown = useCallback(
|
|
1874
|
+
(e) => {
|
|
1875
|
+
if (e.button !== 0) return;
|
|
1876
|
+
const clickTarget = e.target;
|
|
1877
|
+
if (isInteractiveClickTarget(clickTarget)) return;
|
|
1878
|
+
e.preventDefault();
|
|
1879
|
+
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1880
|
+
table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
|
|
1881
|
+
e.currentTarget.focus({ preventScroll: true });
|
|
1882
|
+
},
|
|
1883
|
+
[columnIndex, rowIndex, table]
|
|
1884
|
+
);
|
|
1885
|
+
const handleMouseEnter = useCallback(() => {
|
|
1886
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1887
|
+
table.updateCellRangeSelection({ rowIndex, columnIndex });
|
|
1888
|
+
}, [columnIndex, rowIndex, table]);
|
|
1889
|
+
const handleMouseUp = useCallback(() => {
|
|
1890
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1891
|
+
table.endCellRangeSelection();
|
|
1892
|
+
}, [table]);
|
|
1893
|
+
const cellClassNameDef = column.columnDef.cellClassName;
|
|
1894
|
+
const userClassName = typeof cellClassNameDef === "function" ? cellClassNameDef(cell.getContext()) : cellClassNameDef;
|
|
1895
|
+
const cellStyleDef = column.columnDef.cellStyle;
|
|
1896
|
+
const userStyle = typeof cellStyleDef === "function" ? cellStyleDef(cell.getContext()) : cellStyleDef;
|
|
1897
|
+
const mergedStyle = userStyle ? { ...style, ...userStyle } : style;
|
|
1311
1898
|
const classNames = [
|
|
1312
1899
|
"yable-td",
|
|
1313
|
-
isFocused && "yable-cell--focused"
|
|
1900
|
+
isFocused && "yable-cell--focused",
|
|
1901
|
+
isCellSelected && "yable-cell--selected",
|
|
1902
|
+
selectionEdges?.top && "yable-cell--selection-top",
|
|
1903
|
+
selectionEdges?.right && "yable-cell--selection-right",
|
|
1904
|
+
selectionEdges?.bottom && "yable-cell--selection-bottom",
|
|
1905
|
+
selectionEdges?.left && "yable-cell--selection-left",
|
|
1906
|
+
userClassName
|
|
1314
1907
|
].filter(Boolean).join(" ");
|
|
1315
1908
|
return /* @__PURE__ */ jsxs(
|
|
1316
1909
|
"td",
|
|
1317
1910
|
{
|
|
1318
1911
|
className: classNames,
|
|
1319
|
-
style,
|
|
1912
|
+
style: mergedStyle,
|
|
1320
1913
|
"data-editing": isEditing || void 0,
|
|
1321
1914
|
"data-focused": isFocused || void 0,
|
|
1322
1915
|
"data-pinned": pinned || void 0,
|
|
@@ -1324,10 +1917,14 @@ function TableCell({
|
|
|
1324
1917
|
"data-column-id": column.id,
|
|
1325
1918
|
"data-row-index": rowIndex,
|
|
1326
1919
|
"data-column-index": columnIndex,
|
|
1920
|
+
"data-cell-selected": isCellSelected || void 0,
|
|
1327
1921
|
"aria-rowindex": rowIndex + 1,
|
|
1328
1922
|
"aria-colindex": columnIndex + 1,
|
|
1329
1923
|
role: "gridcell",
|
|
1330
1924
|
tabIndex: keyboardNavigationEnabled ? isTabStop ? 0 : -1 : void 0,
|
|
1925
|
+
onMouseDown: handleMouseDown,
|
|
1926
|
+
onMouseEnter: handleMouseEnter,
|
|
1927
|
+
onMouseUp: handleMouseUp,
|
|
1331
1928
|
onClick: handleClick,
|
|
1332
1929
|
onDoubleClick: handleDoubleClick,
|
|
1333
1930
|
onContextMenu: handleContextMenu,
|
|
@@ -1454,12 +2051,17 @@ var CellErrorBoundary = class extends React3.Component {
|
|
|
1454
2051
|
};
|
|
1455
2052
|
function TableBody({
|
|
1456
2053
|
table,
|
|
1457
|
-
clickableRows
|
|
2054
|
+
clickableRows,
|
|
2055
|
+
colgroup
|
|
1458
2056
|
}) {
|
|
1459
2057
|
const rows = table.getRowModel().rows;
|
|
1460
2058
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1461
2059
|
const activeCell = table.getState().editing.activeCell;
|
|
1462
2060
|
const focusedCell = table.getFocusedCell();
|
|
2061
|
+
const cellSelection = table.getState().cellSelection ?? {
|
|
2062
|
+
range: null,
|
|
2063
|
+
isDragging: false
|
|
2064
|
+
};
|
|
1463
2065
|
const options = table.options;
|
|
1464
2066
|
const enableVirtualization = options.enableVirtualization ?? false;
|
|
1465
2067
|
const scrollContainerRef = useRef(null);
|
|
@@ -1468,6 +2070,19 @@ function TableBody({
|
|
|
1468
2070
|
const estimateRowHeight = options.estimateRowHeight;
|
|
1469
2071
|
const pretextHeights = options.pretextHeights ?? null;
|
|
1470
2072
|
const pretextPrefixSums = options.pretextPrefixSums ?? null;
|
|
2073
|
+
const columnSizing = table.getState().columnSizing;
|
|
2074
|
+
const columnSizingHash = useMemo(() => {
|
|
2075
|
+
const entries = Object.entries(columnSizing);
|
|
2076
|
+
if (entries.length === 0) return 0;
|
|
2077
|
+
let h = 0;
|
|
2078
|
+
for (const [key, value] of entries) {
|
|
2079
|
+
for (let i = 0; i < key.length; i++) {
|
|
2080
|
+
h = h * 31 + key.charCodeAt(i) | 0;
|
|
2081
|
+
}
|
|
2082
|
+
h = h * 31 + (value | 0) | 0;
|
|
2083
|
+
}
|
|
2084
|
+
return h;
|
|
2085
|
+
}, [columnSizing]);
|
|
1471
2086
|
const { virtualRows, totalHeight } = useVirtualization({
|
|
1472
2087
|
containerRef: scrollContainerRef,
|
|
1473
2088
|
totalRows: rows.length,
|
|
@@ -1475,8 +2090,21 @@ function TableBody({
|
|
|
1475
2090
|
overscan,
|
|
1476
2091
|
estimateRowHeight,
|
|
1477
2092
|
pretextHeights,
|
|
1478
|
-
pretextPrefixSums
|
|
2093
|
+
pretextPrefixSums,
|
|
2094
|
+
columnSizingHash
|
|
1479
2095
|
});
|
|
2096
|
+
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"}`;
|
|
2097
|
+
useEffect(() => {
|
|
2098
|
+
const handleWindowMouseUp = () => {
|
|
2099
|
+
if (table.getState().cellSelection?.isDragging) {
|
|
2100
|
+
table.endCellRangeSelection();
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
window.addEventListener("mouseup", handleWindowMouseUp);
|
|
2104
|
+
return () => {
|
|
2105
|
+
window.removeEventListener("mouseup", handleWindowMouseUp);
|
|
2106
|
+
};
|
|
2107
|
+
}, [table]);
|
|
1480
2108
|
if (!enableVirtualization) {
|
|
1481
2109
|
return /* @__PURE__ */ jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx(
|
|
1482
2110
|
MemoizedTableRow,
|
|
@@ -1490,6 +2118,7 @@ function TableBody({
|
|
|
1490
2118
|
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1491
2119
|
focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
|
|
1492
2120
|
hasFocusedCell: focusedCell !== null,
|
|
2121
|
+
cellSelectionKey,
|
|
1493
2122
|
clickable: clickableRows
|
|
1494
2123
|
},
|
|
1495
2124
|
row.id
|
|
@@ -1498,73 +2127,70 @@ function TableBody({
|
|
|
1498
2127
|
const hasPretextData = !!(pretextHeights && pretextPrefixSums);
|
|
1499
2128
|
const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
|
|
1500
2129
|
const containerHeight = hasPretextData ? Math.min(totalHeight, 800) : fixedRowHeight ? Math.min(totalHeight, fixedRowHeight * 20) : 600;
|
|
1501
|
-
return /* @__PURE__ */ jsx("tbody", { className: "yable-tbody", children: /* @__PURE__ */ jsx("tr", { style: { height: 0, padding: 0, border: "none" }, children: /* @__PURE__ */ jsx(
|
|
1502
|
-
"
|
|
2130
|
+
return /* @__PURE__ */ jsx("tbody", { className: "yable-tbody", children: /* @__PURE__ */ jsx("tr", { style: { height: 0, padding: 0, border: "none" }, children: /* @__PURE__ */ jsx("td", { style: { height: 0, padding: 0, border: "none" }, colSpan: visibleColumns.length, children: /* @__PURE__ */ jsx(
|
|
2131
|
+
"div",
|
|
1503
2132
|
{
|
|
1504
|
-
|
|
1505
|
-
|
|
2133
|
+
ref: scrollContainerRef,
|
|
2134
|
+
className: "yable-virtual-scroll-container",
|
|
2135
|
+
style: {
|
|
2136
|
+
overflowY: "auto",
|
|
2137
|
+
height: containerHeight,
|
|
2138
|
+
position: "relative"
|
|
2139
|
+
},
|
|
1506
2140
|
children: /* @__PURE__ */ jsx(
|
|
1507
2141
|
"div",
|
|
1508
2142
|
{
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
height: containerHeight,
|
|
1514
|
-
position: "relative"
|
|
1515
|
-
},
|
|
1516
|
-
children: /* @__PURE__ */ jsx(
|
|
1517
|
-
"div",
|
|
2143
|
+
className: "yable-virtual-spacer",
|
|
2144
|
+
style: { height: totalHeight, position: "relative" },
|
|
2145
|
+
children: /* @__PURE__ */ jsxs(
|
|
2146
|
+
"table",
|
|
1518
2147
|
{
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
}) })
|
|
1560
|
-
}
|
|
1561
|
-
)
|
|
2148
|
+
style: {
|
|
2149
|
+
position: "absolute",
|
|
2150
|
+
top: 0,
|
|
2151
|
+
left: 0,
|
|
2152
|
+
width: "100%",
|
|
2153
|
+
tableLayout: "fixed",
|
|
2154
|
+
borderCollapse: "collapse"
|
|
2155
|
+
},
|
|
2156
|
+
children: [
|
|
2157
|
+
colgroup,
|
|
2158
|
+
/* @__PURE__ */ jsx("tbody", { children: virtualRows.map((vRow) => {
|
|
2159
|
+
const row = rows[vRow.index];
|
|
2160
|
+
if (!row) return null;
|
|
2161
|
+
return /* @__PURE__ */ jsx(
|
|
2162
|
+
MemoizedTableRow,
|
|
2163
|
+
{
|
|
2164
|
+
row,
|
|
2165
|
+
table,
|
|
2166
|
+
rowIndex: vRow.index,
|
|
2167
|
+
visibleColumns,
|
|
2168
|
+
isSelected: row.getIsSelected(),
|
|
2169
|
+
isExpanded: row.getIsExpanded(),
|
|
2170
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
2171
|
+
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
2172
|
+
hasFocusedCell: focusedCell !== null,
|
|
2173
|
+
cellSelectionKey,
|
|
2174
|
+
clickable: clickableRows,
|
|
2175
|
+
virtualStyle: {
|
|
2176
|
+
position: "absolute",
|
|
2177
|
+
top: 0,
|
|
2178
|
+
left: 0,
|
|
2179
|
+
width: "100%",
|
|
2180
|
+
height: vRow.size,
|
|
2181
|
+
transform: `translateY(${vRow.start}px)`
|
|
2182
|
+
}
|
|
2183
|
+
},
|
|
2184
|
+
row.id
|
|
2185
|
+
);
|
|
2186
|
+
}) })
|
|
2187
|
+
]
|
|
1562
2188
|
}
|
|
1563
2189
|
)
|
|
1564
2190
|
}
|
|
1565
2191
|
)
|
|
1566
2192
|
}
|
|
1567
|
-
) }) });
|
|
2193
|
+
) }) }) });
|
|
1568
2194
|
}
|
|
1569
2195
|
function TableRowInner({
|
|
1570
2196
|
row,
|
|
@@ -1576,10 +2202,12 @@ function TableRowInner({
|
|
|
1576
2202
|
activeColumnId,
|
|
1577
2203
|
focusedColumnIndex,
|
|
1578
2204
|
hasFocusedCell,
|
|
2205
|
+
cellSelectionKey: _cellSelectionKey,
|
|
1579
2206
|
clickable,
|
|
1580
2207
|
virtualStyle
|
|
1581
2208
|
}) {
|
|
1582
|
-
const
|
|
2209
|
+
const allCells = row.getAllCells();
|
|
2210
|
+
const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
|
|
1583
2211
|
const handleClick = useCallback(
|
|
1584
2212
|
(e) => {
|
|
1585
2213
|
if (clickable) {
|
|
@@ -1609,6 +2237,8 @@ function TableRowInner({
|
|
|
1609
2237
|
},
|
|
1610
2238
|
[table.events, row]
|
|
1611
2239
|
);
|
|
2240
|
+
const selectionEnabled = Boolean(table.options.enableRowSelection);
|
|
2241
|
+
const expansionEnabled = Boolean(table.options.enableExpanding);
|
|
1612
2242
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1613
2243
|
/* @__PURE__ */ jsx(
|
|
1614
2244
|
"tr",
|
|
@@ -1620,6 +2250,8 @@ function TableRowInner({
|
|
|
1620
2250
|
"data-clickable": clickable || void 0,
|
|
1621
2251
|
"data-row-id": row.id,
|
|
1622
2252
|
"data-row-index": rowIndex,
|
|
2253
|
+
"aria-selected": selectionEnabled ? isSelected : void 0,
|
|
2254
|
+
"aria-expanded": expansionEnabled ? isExpanded : void 0,
|
|
1623
2255
|
onClick: handleClick,
|
|
1624
2256
|
onDoubleClick: handleDoubleClick,
|
|
1625
2257
|
onContextMenu: handleContextMenu,
|
|
@@ -1661,6 +2293,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1661
2293
|
if (prev.activeColumnId !== next.activeColumnId) return false;
|
|
1662
2294
|
if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
|
|
1663
2295
|
if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
|
|
2296
|
+
if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
|
|
1664
2297
|
if (prev.virtualStyle !== next.virtualStyle) {
|
|
1665
2298
|
if (!prev.virtualStyle || !next.virtualStyle) return false;
|
|
1666
2299
|
if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
|
|
@@ -1670,9 +2303,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1670
2303
|
return true;
|
|
1671
2304
|
}
|
|
1672
2305
|
var MemoizedTableRow = React3.memo(TableRowInner, areRowPropsEqual);
|
|
1673
|
-
function TableFooter({
|
|
1674
|
-
table
|
|
1675
|
-
}) {
|
|
2306
|
+
function TableFooter({ table }) {
|
|
1676
2307
|
const footerGroups = table.getFooterGroups();
|
|
1677
2308
|
if (!footerGroups.length) return null;
|
|
1678
2309
|
return /* @__PURE__ */ jsx("tfoot", { className: "yable-tfoot", children: footerGroups.map((footerGroup) => /* @__PURE__ */ jsx("tr", { className: "yable-tr", children: footerGroup.headers.map((header) => {
|
|
@@ -2435,11 +3066,11 @@ function ContextMenu({
|
|
|
2435
3066
|
}
|
|
2436
3067
|
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
2437
3068
|
e.preventDefault();
|
|
2438
|
-
const items2 = menuRef.current?.querySelectorAll(
|
|
2439
|
-
|
|
2440
|
-
const currentIndex = Array.from(items2).findIndex(
|
|
2441
|
-
(el) => el === document.activeElement
|
|
3069
|
+
const items2 = menuRef.current?.querySelectorAll(
|
|
3070
|
+
'[role="menuitem"]:not([aria-disabled="true"])'
|
|
2442
3071
|
);
|
|
3072
|
+
if (!items2 || items2.length === 0) return;
|
|
3073
|
+
const currentIndex = Array.from(items2).findIndex((el) => el === document.activeElement);
|
|
2443
3074
|
let nextIndex;
|
|
2444
3075
|
if (e.key === "ArrowDown") {
|
|
2445
3076
|
nextIndex = currentIndex < items2.length - 1 ? currentIndex + 1 : 0;
|
|
@@ -2484,11 +3115,7 @@ function ContextMenu({
|
|
|
2484
3115
|
navigator.clipboard?.readText().then((text) => {
|
|
2485
3116
|
const editing = table.getState().editing;
|
|
2486
3117
|
if (editing?.activeCell) {
|
|
2487
|
-
table.pasteFromClipboard(
|
|
2488
|
-
text,
|
|
2489
|
-
editing.activeCell.rowId,
|
|
2490
|
-
editing.activeCell.columnId
|
|
2491
|
-
);
|
|
3118
|
+
table.pasteFromClipboard(text, editing.activeCell.rowId, editing.activeCell.columnId);
|
|
2492
3119
|
}
|
|
2493
3120
|
}).catch(() => {
|
|
2494
3121
|
});
|
|
@@ -2828,13 +3455,19 @@ function isEditableTarget(element) {
|
|
|
2828
3455
|
}
|
|
2829
3456
|
return element.isContentEditable;
|
|
2830
3457
|
}
|
|
3458
|
+
function filterHeaderGroups(groups, visibleColumnIds) {
|
|
3459
|
+
return groups.map((group) => ({
|
|
3460
|
+
...group,
|
|
3461
|
+
headers: group.headers.filter((header) => visibleColumnIds.has(header.column.id))
|
|
3462
|
+
})).filter((group) => group.headers.length > 0);
|
|
3463
|
+
}
|
|
2831
3464
|
function Table({
|
|
2832
3465
|
table,
|
|
2833
|
-
stickyHeader,
|
|
2834
|
-
striped,
|
|
2835
|
-
bordered,
|
|
2836
|
-
compact,
|
|
2837
|
-
theme,
|
|
3466
|
+
stickyHeader: stickyHeaderProp,
|
|
3467
|
+
striped: stripedProp,
|
|
3468
|
+
bordered: borderedProp,
|
|
3469
|
+
compact: compactProp,
|
|
3470
|
+
theme: themeProp,
|
|
2838
3471
|
clickableRows,
|
|
2839
3472
|
footer,
|
|
2840
3473
|
loading,
|
|
@@ -2848,19 +3481,32 @@ function Table({
|
|
|
2848
3481
|
renderLoading,
|
|
2849
3482
|
children,
|
|
2850
3483
|
className,
|
|
2851
|
-
direction,
|
|
3484
|
+
direction: directionProp,
|
|
2852
3485
|
statusBar,
|
|
2853
3486
|
statusBarPanels,
|
|
2854
3487
|
sidebar,
|
|
2855
3488
|
sidebarPanels = ["columns", "filters"],
|
|
2856
3489
|
defaultSidebarPanel,
|
|
3490
|
+
floatingFilters,
|
|
3491
|
+
columnVirtualization,
|
|
3492
|
+
columnVirtualizationOverscan,
|
|
3493
|
+
ariaLabel: ariaLabelProp,
|
|
2857
3494
|
...rest
|
|
2858
3495
|
}) {
|
|
3496
|
+
const { tableProps: providerTableProps } = useYableDefaults();
|
|
3497
|
+
const stickyHeader = stickyHeaderProp ?? providerTableProps?.stickyHeader;
|
|
3498
|
+
const striped = stripedProp ?? providerTableProps?.striped;
|
|
3499
|
+
const bordered = borderedProp ?? providerTableProps?.bordered;
|
|
3500
|
+
const compact = compactProp ?? providerTableProps?.compact;
|
|
3501
|
+
const theme = themeProp ?? providerTableProps?.theme;
|
|
3502
|
+
const direction = directionProp ?? providerTableProps?.direction;
|
|
3503
|
+
const ariaLabel = ariaLabelProp ?? providerTableProps?.ariaLabel;
|
|
2859
3504
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
2860
3505
|
const [sidebarPanel, setSidebarPanel] = useState(
|
|
2861
3506
|
defaultSidebarPanel ?? "columns"
|
|
2862
3507
|
);
|
|
2863
3508
|
const containerRef = useRef(null);
|
|
3509
|
+
const horizontalScrollRef = useRef(null);
|
|
2864
3510
|
const isRtl = direction === "rtl";
|
|
2865
3511
|
const classNames = [
|
|
2866
3512
|
"yable",
|
|
@@ -2878,8 +3524,86 @@ function Table({
|
|
|
2878
3524
|
const hasGlobalFilter = Boolean(table.getState().globalFilter);
|
|
2879
3525
|
const hasColumnFilters = table.getState().columnFilters.length > 0;
|
|
2880
3526
|
const isFiltered = hasGlobalFilter || hasColumnFilters;
|
|
3527
|
+
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
3528
|
+
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
3529
|
+
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
3530
|
+
const canVirtualizeColumns = Boolean(columnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
3531
|
+
const columnVirtualState = useColumnVirtualization({
|
|
3532
|
+
containerRef: horizontalScrollRef,
|
|
3533
|
+
columns: allVisibleColumns,
|
|
3534
|
+
overscan: columnVirtualizationOverscan ?? 2,
|
|
3535
|
+
enabled: canVirtualizeColumns
|
|
3536
|
+
});
|
|
3537
|
+
const renderTable = useMemo(() => {
|
|
3538
|
+
if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
|
|
3539
|
+
return table;
|
|
3540
|
+
}
|
|
3541
|
+
const virtualColumns = columnVirtualState.virtualColumns.map((entry) => entry.column);
|
|
3542
|
+
const visibleColumnIds = new Set(virtualColumns.map((column) => column.id));
|
|
3543
|
+
const next = Object.create(table);
|
|
3544
|
+
next.getVisibleFlatColumns = () => virtualColumns;
|
|
3545
|
+
next.getVisibleLeafColumns = () => virtualColumns;
|
|
3546
|
+
next.getCenterVisibleLeafColumns = () => virtualColumns;
|
|
3547
|
+
next.getLeftVisibleLeafColumns = () => [];
|
|
3548
|
+
next.getRightVisibleLeafColumns = () => [];
|
|
3549
|
+
next.getHeaderGroups = () => filterHeaderGroups(table.getHeaderGroups(), visibleColumnIds);
|
|
3550
|
+
next.getCenterHeaderGroups = () => filterHeaderGroups(table.getCenterHeaderGroups(), visibleColumnIds);
|
|
3551
|
+
next.getFooterGroups = () => filterHeaderGroups(table.getFooterGroups(), visibleColumnIds);
|
|
3552
|
+
next.getCenterFooterGroups = () => filterHeaderGroups(table.getCenterFooterGroups(), visibleColumnIds);
|
|
3553
|
+
return next;
|
|
3554
|
+
}, [
|
|
3555
|
+
canVirtualizeColumns,
|
|
3556
|
+
columnVirtualState.isVirtualized,
|
|
3557
|
+
columnVirtualState.virtualColumns,
|
|
3558
|
+
table
|
|
3559
|
+
]);
|
|
3560
|
+
const showColumnVirtualizationShell = canVirtualizeColumns;
|
|
2881
3561
|
const contextMenu = useContextMenu();
|
|
2882
3562
|
useKeyboardNavigation(table, { containerRef });
|
|
3563
|
+
const [announcement, setAnnouncement] = useState("");
|
|
3564
|
+
const prevSortingRef = useRef(table.getState().sorting);
|
|
3565
|
+
const prevFilterCountRef = useRef(rows.length);
|
|
3566
|
+
const prevHasFiltersRef = useRef(isFiltered);
|
|
3567
|
+
const prevPaginationRef = useRef(table.getState().pagination);
|
|
3568
|
+
const isFirstRenderRef = useRef(true);
|
|
3569
|
+
useEffect(() => {
|
|
3570
|
+
if (isFirstRenderRef.current) {
|
|
3571
|
+
isFirstRenderRef.current = false;
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
const currentSorting = table.getState().sorting;
|
|
3575
|
+
const currentPagination = table.getState().pagination;
|
|
3576
|
+
const currentRowCount = rows.length;
|
|
3577
|
+
const currentIsFiltered = isFiltered;
|
|
3578
|
+
if (JSON.stringify(currentSorting) !== JSON.stringify(prevSortingRef.current)) {
|
|
3579
|
+
prevSortingRef.current = currentSorting;
|
|
3580
|
+
const firstSort = currentSorting[0];
|
|
3581
|
+
if (firstSort) {
|
|
3582
|
+
const column = table.getColumn(firstSort.id);
|
|
3583
|
+
const headerDef = column?.columnDef.header;
|
|
3584
|
+
const columnName = typeof headerDef === "string" ? headerDef : firstSort.id;
|
|
3585
|
+
const direction2 = firstSort.desc ? "descending" : "ascending";
|
|
3586
|
+
setAnnouncement(`Sorted by ${columnName} ${direction2}`);
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
if (currentRowCount !== prevFilterCountRef.current || currentIsFiltered !== prevHasFiltersRef.current) {
|
|
3591
|
+
prevFilterCountRef.current = currentRowCount;
|
|
3592
|
+
prevHasFiltersRef.current = currentIsFiltered;
|
|
3593
|
+
if (currentIsFiltered) {
|
|
3594
|
+
setAnnouncement(`${currentRowCount} rows after filtering`);
|
|
3595
|
+
return;
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
if (JSON.stringify(currentPagination) !== JSON.stringify(prevPaginationRef.current)) {
|
|
3599
|
+
prevPaginationRef.current = currentPagination;
|
|
3600
|
+
const pageCount = table.getPageCount();
|
|
3601
|
+
if (pageCount > 0) {
|
|
3602
|
+
setAnnouncement(`Page ${currentPagination.pageIndex + 1} of ${pageCount}`);
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
});
|
|
2883
3607
|
const handleContextMenu = useCallback(
|
|
2884
3608
|
(e) => {
|
|
2885
3609
|
e.preventDefault();
|
|
@@ -2887,6 +3611,46 @@ function Table({
|
|
|
2887
3611
|
},
|
|
2888
3612
|
[contextMenu, table]
|
|
2889
3613
|
);
|
|
3614
|
+
const enableRowVirtualization = renderTable.options.enableVirtualization ?? false;
|
|
3615
|
+
const visibleLeafColumns = renderTable.getVisibleLeafColumns();
|
|
3616
|
+
const columnSizing = renderTable.getState().columnSizing;
|
|
3617
|
+
const colgroup = useMemo(() => {
|
|
3618
|
+
if (visibleLeafColumns.length === 0) return null;
|
|
3619
|
+
return /* @__PURE__ */ jsx("colgroup", { children: visibleLeafColumns.map((col) => /* @__PURE__ */ jsx("col", { style: { width: col.getSize() } }, col.id)) });
|
|
3620
|
+
}, [visibleLeafColumns, columnSizing]);
|
|
3621
|
+
const outerTableStyle = useMemo(() => {
|
|
3622
|
+
if (columnVirtualState.isVirtualized) {
|
|
3623
|
+
return {
|
|
3624
|
+
width: columnVirtualState.visibleWidth,
|
|
3625
|
+
minWidth: columnVirtualState.visibleWidth,
|
|
3626
|
+
marginLeft: columnVirtualState.startOffset,
|
|
3627
|
+
tableLayout: "fixed"
|
|
3628
|
+
};
|
|
3629
|
+
}
|
|
3630
|
+
if (enableRowVirtualization) {
|
|
3631
|
+
return { tableLayout: "fixed" };
|
|
3632
|
+
}
|
|
3633
|
+
return void 0;
|
|
3634
|
+
}, [
|
|
3635
|
+
columnVirtualState.isVirtualized,
|
|
3636
|
+
columnVirtualState.visibleWidth,
|
|
3637
|
+
columnVirtualState.startOffset,
|
|
3638
|
+
enableRowVirtualization
|
|
3639
|
+
]);
|
|
3640
|
+
const tableNode = /* @__PURE__ */ jsxs(
|
|
3641
|
+
"table",
|
|
3642
|
+
{
|
|
3643
|
+
className: "yable-table",
|
|
3644
|
+
style: outerTableStyle,
|
|
3645
|
+
"data-column-virtualized": columnVirtualState.isVirtualized || void 0,
|
|
3646
|
+
children: [
|
|
3647
|
+
enableRowVirtualization && colgroup,
|
|
3648
|
+
/* @__PURE__ */ jsx(TableHeader, { table: renderTable, floatingFilters }),
|
|
3649
|
+
/* @__PURE__ */ jsx(TableBody, { table: renderTable, clickableRows, colgroup }),
|
|
3650
|
+
footer && /* @__PURE__ */ jsx(TableFooter, { table: renderTable })
|
|
3651
|
+
]
|
|
3652
|
+
}
|
|
3653
|
+
);
|
|
2890
3654
|
return /* @__PURE__ */ jsx(TableProvider, { value: table, children: /* @__PURE__ */ jsxs(
|
|
2891
3655
|
"div",
|
|
2892
3656
|
{
|
|
@@ -2895,23 +3659,40 @@ function Table({
|
|
|
2895
3659
|
"data-theme": theme,
|
|
2896
3660
|
dir: direction,
|
|
2897
3661
|
role: "grid",
|
|
3662
|
+
"aria-label": ariaLabel ?? "Data table",
|
|
2898
3663
|
"aria-rowcount": table.getRowModel().rows.length,
|
|
2899
3664
|
"aria-colcount": table.getVisibleLeafColumns().length,
|
|
2900
3665
|
onContextMenu: handleContextMenu,
|
|
2901
3666
|
...rest,
|
|
2902
3667
|
children: [
|
|
2903
3668
|
/* @__PURE__ */ jsxs("div", { className: "yable-main", children: [
|
|
2904
|
-
/* @__PURE__ */
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3669
|
+
showColumnVirtualizationShell ? /* @__PURE__ */ jsx(
|
|
3670
|
+
"div",
|
|
3671
|
+
{
|
|
3672
|
+
ref: horizontalScrollRef,
|
|
3673
|
+
className: "yable-horizontal-scroll-container",
|
|
3674
|
+
style: {
|
|
3675
|
+
overflowX: "auto",
|
|
3676
|
+
overflowY: "visible",
|
|
3677
|
+
maxWidth: "100%",
|
|
3678
|
+
position: "relative"
|
|
3679
|
+
},
|
|
3680
|
+
children: /* @__PURE__ */ jsx(
|
|
3681
|
+
"div",
|
|
3682
|
+
{
|
|
3683
|
+
className: "yable-horizontal-scroll-inner",
|
|
3684
|
+
style: {
|
|
3685
|
+
width: Math.max(columnVirtualState.totalWidth, columnVirtualState.visibleWidth),
|
|
3686
|
+
minWidth: Math.max(
|
|
3687
|
+
columnVirtualState.totalWidth,
|
|
3688
|
+
columnVirtualState.visibleWidth
|
|
3689
|
+
)
|
|
3690
|
+
},
|
|
3691
|
+
children: tableNode
|
|
3692
|
+
}
|
|
3693
|
+
)
|
|
3694
|
+
}
|
|
3695
|
+
) : tableNode,
|
|
2915
3696
|
/* @__PURE__ */ jsx(
|
|
2916
3697
|
LoadingOverlay,
|
|
2917
3698
|
{
|
|
@@ -2952,6 +3733,24 @@ function Table({
|
|
|
2952
3733
|
onClose: contextMenu.close,
|
|
2953
3734
|
table
|
|
2954
3735
|
}
|
|
3736
|
+
),
|
|
3737
|
+
/* @__PURE__ */ jsx(
|
|
3738
|
+
"div",
|
|
3739
|
+
{
|
|
3740
|
+
role: "status",
|
|
3741
|
+
"aria-live": "polite",
|
|
3742
|
+
"aria-atomic": "true",
|
|
3743
|
+
style: {
|
|
3744
|
+
position: "absolute",
|
|
3745
|
+
width: "1px",
|
|
3746
|
+
height: "1px",
|
|
3747
|
+
overflow: "hidden",
|
|
3748
|
+
clip: "rect(0,0,0,0)",
|
|
3749
|
+
whiteSpace: "nowrap",
|
|
3750
|
+
border: 0
|
|
3751
|
+
},
|
|
3752
|
+
children: announcement
|
|
3753
|
+
}
|
|
2955
3754
|
)
|
|
2956
3755
|
]
|
|
2957
3756
|
}
|
|
@@ -3417,14 +4216,7 @@ function formatDateValue(value, type) {
|
|
|
3417
4216
|
return String(value);
|
|
3418
4217
|
}
|
|
3419
4218
|
function useClipboard(table, options = {}) {
|
|
3420
|
-
const {
|
|
3421
|
-
enabled = true,
|
|
3422
|
-
containerRef,
|
|
3423
|
-
onCopy,
|
|
3424
|
-
onCut,
|
|
3425
|
-
onPaste,
|
|
3426
|
-
...clipboardOptions
|
|
3427
|
-
} = options;
|
|
4219
|
+
const { enabled = true, containerRef, onCopy, onCut, onPaste, ...clipboardOptions } = options;
|
|
3428
4220
|
const handleCopy = useCallback(
|
|
3429
4221
|
(e) => {
|
|
3430
4222
|
if (isEditableTarget2(e.target)) return;
|
|
@@ -3462,20 +4254,29 @@ function useClipboard(table, options = {}) {
|
|
|
3462
4254
|
targetRowId = state.editing.activeCell.rowId;
|
|
3463
4255
|
targetColumnId = state.editing.activeCell.columnId;
|
|
3464
4256
|
} else {
|
|
3465
|
-
const
|
|
3466
|
-
|
|
3467
|
-
);
|
|
3468
|
-
if (
|
|
3469
|
-
|
|
4257
|
+
const selectedRange = table.getCellSelectionRange();
|
|
4258
|
+
const rows = table.getRowModel().rows;
|
|
4259
|
+
const columns = table.getVisibleLeafColumns();
|
|
4260
|
+
if (selectedRange) {
|
|
4261
|
+
const startRowIndex = Math.min(selectedRange.start.rowIndex, selectedRange.end.rowIndex);
|
|
4262
|
+
const startColumnIndex = Math.min(
|
|
4263
|
+
selectedRange.start.columnIndex,
|
|
4264
|
+
selectedRange.end.columnIndex
|
|
4265
|
+
);
|
|
4266
|
+
targetRowId = rows[startRowIndex]?.id;
|
|
4267
|
+
targetColumnId = columns[startColumnIndex]?.id;
|
|
3470
4268
|
} else {
|
|
3471
|
-
const
|
|
3472
|
-
|
|
4269
|
+
const selectedRowIds = Object.keys(state.rowSelection || {}).filter(
|
|
4270
|
+
(id) => state.rowSelection[id]
|
|
4271
|
+
);
|
|
4272
|
+
if (selectedRowIds.length > 0) {
|
|
4273
|
+
targetRowId = selectedRowIds[0];
|
|
4274
|
+
} else if (rows.length > 0) {
|
|
3473
4275
|
targetRowId = rows[0].id;
|
|
3474
4276
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
targetColumnId = columns[0].id;
|
|
4277
|
+
if (columns.length > 0) {
|
|
4278
|
+
targetColumnId = columns[0].id;
|
|
4279
|
+
}
|
|
3479
4280
|
}
|
|
3480
4281
|
}
|
|
3481
4282
|
if (targetRowId && targetColumnId) {
|
|
@@ -4765,7 +5566,7 @@ function sanitizeCSS(css) {
|
|
|
4765
5566
|
sanitized = sanitized.replace(/javascript\s*:/gi, "/* javascript: removed */");
|
|
4766
5567
|
return sanitized;
|
|
4767
5568
|
}
|
|
4768
|
-
function usePrintLayout(
|
|
5569
|
+
function usePrintLayout(_table, options = {}) {
|
|
4769
5570
|
const { title, additionalCSS } = options;
|
|
4770
5571
|
const isPrintingRef = useRef(false);
|
|
4771
5572
|
const preparePrint = useCallback(() => {
|
|
@@ -4802,7 +5603,7 @@ function usePrintLayout(table, options = {}) {
|
|
|
4802
5603
|
requestAnimationFrame(() => {
|
|
4803
5604
|
window.print();
|
|
4804
5605
|
});
|
|
4805
|
-
}, [
|
|
5606
|
+
}, [title, additionalCSS]);
|
|
4806
5607
|
return {
|
|
4807
5608
|
preparePrint,
|
|
4808
5609
|
isPrinting: isPrintingRef.current
|
|
@@ -4853,7 +5654,234 @@ function useTheme(options = {}) {
|
|
|
4853
5654
|
containerRef
|
|
4854
5655
|
};
|
|
4855
5656
|
}
|
|
5657
|
+
function selectColumn(options = {}) {
|
|
5658
|
+
const { id = "_select", size = 40, headerAriaLabel = "Select all rows" } = options;
|
|
5659
|
+
return {
|
|
5660
|
+
id,
|
|
5661
|
+
header: ({ table }) => /* @__PURE__ */ jsx(
|
|
5662
|
+
"input",
|
|
5663
|
+
{
|
|
5664
|
+
type: "checkbox",
|
|
5665
|
+
checked: table.getIsAllPageRowsSelected(),
|
|
5666
|
+
ref: (el) => {
|
|
5667
|
+
if (el)
|
|
5668
|
+
el.indeterminate = table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected();
|
|
5669
|
+
},
|
|
5670
|
+
onChange: () => table.toggleAllPageRowsSelected(),
|
|
5671
|
+
"aria-label": headerAriaLabel
|
|
5672
|
+
}
|
|
5673
|
+
),
|
|
5674
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
5675
|
+
"input",
|
|
5676
|
+
{
|
|
5677
|
+
type: "checkbox",
|
|
5678
|
+
checked: row.getIsSelected(),
|
|
5679
|
+
disabled: !row.getCanSelect(),
|
|
5680
|
+
onChange: row.getToggleSelectedHandler(),
|
|
5681
|
+
"aria-label": `Select row`
|
|
5682
|
+
}
|
|
5683
|
+
),
|
|
5684
|
+
size,
|
|
5685
|
+
enableSorting: false,
|
|
5686
|
+
enableColumnFilter: false,
|
|
5687
|
+
enableResizing: false,
|
|
5688
|
+
enableReorder: false,
|
|
5689
|
+
enableHiding: false,
|
|
5690
|
+
lockVisible: true
|
|
5691
|
+
};
|
|
5692
|
+
}
|
|
5693
|
+
|
|
5694
|
+
// src/presets/rowNumberColumn.tsx
|
|
5695
|
+
function rowNumberColumn(options = {}) {
|
|
5696
|
+
const { id = "_rowNumber", header = "#", size = 50, startFrom = 1 } = options;
|
|
5697
|
+
return {
|
|
5698
|
+
id,
|
|
5699
|
+
header,
|
|
5700
|
+
cell: ({ row }) => row.index + startFrom,
|
|
5701
|
+
size,
|
|
5702
|
+
enableSorting: false,
|
|
5703
|
+
enableColumnFilter: false,
|
|
5704
|
+
enableResizing: false,
|
|
5705
|
+
enableReorder: false,
|
|
5706
|
+
lockVisible: true
|
|
5707
|
+
};
|
|
5708
|
+
}
|
|
5709
|
+
function actionsColumn(options) {
|
|
5710
|
+
const { id = "_actions", header = "", size = 100, actions } = options;
|
|
5711
|
+
return {
|
|
5712
|
+
id,
|
|
5713
|
+
header,
|
|
5714
|
+
cell: (ctx) => {
|
|
5715
|
+
const items = typeof actions === "function" ? actions(ctx.row) : actions;
|
|
5716
|
+
return /* @__PURE__ */ jsx("div", { className: "yable-cell-actions", children: items.filter((a) => !a.hidden || !a.hidden(ctx.row)).map((action, i) => /* @__PURE__ */ jsx(
|
|
5717
|
+
"button",
|
|
5718
|
+
{
|
|
5719
|
+
type: "button",
|
|
5720
|
+
className: "yable-action-btn",
|
|
5721
|
+
disabled: action.disabled?.(ctx.row),
|
|
5722
|
+
onClick: (e) => {
|
|
5723
|
+
e.stopPropagation();
|
|
5724
|
+
action.onClick(ctx.row);
|
|
5725
|
+
},
|
|
5726
|
+
title: action.label,
|
|
5727
|
+
children: action.icon ?? action.label
|
|
5728
|
+
},
|
|
5729
|
+
i
|
|
5730
|
+
)) });
|
|
5731
|
+
},
|
|
5732
|
+
size,
|
|
5733
|
+
enableSorting: false,
|
|
5734
|
+
enableColumnFilter: false,
|
|
5735
|
+
enableResizing: false,
|
|
5736
|
+
enableReorder: false
|
|
5737
|
+
};
|
|
5738
|
+
}
|
|
5739
|
+
function expandColumn(options = {}) {
|
|
5740
|
+
const { id = "_expand", size = 40 } = options;
|
|
5741
|
+
return {
|
|
5742
|
+
id,
|
|
5743
|
+
header: () => null,
|
|
5744
|
+
cell: ({ row }) => {
|
|
5745
|
+
if (!row.getCanExpand()) return null;
|
|
5746
|
+
return /* @__PURE__ */ jsx(
|
|
5747
|
+
"button",
|
|
5748
|
+
{
|
|
5749
|
+
type: "button",
|
|
5750
|
+
className: "yable-expand-btn",
|
|
5751
|
+
onClick: (e) => {
|
|
5752
|
+
e.stopPropagation();
|
|
5753
|
+
row.toggleExpanded();
|
|
5754
|
+
},
|
|
5755
|
+
"aria-expanded": row.getIsExpanded(),
|
|
5756
|
+
"aria-label": row.getIsExpanded() ? "Collapse row" : "Expand row",
|
|
5757
|
+
children: /* @__PURE__ */ jsx(
|
|
5758
|
+
"span",
|
|
5759
|
+
{
|
|
5760
|
+
className: "yable-expand-icon",
|
|
5761
|
+
style: {
|
|
5762
|
+
display: "inline-block",
|
|
5763
|
+
transform: row.getIsExpanded() ? "rotate(90deg)" : "rotate(0deg)",
|
|
5764
|
+
transition: "transform 150ms ease"
|
|
5765
|
+
},
|
|
5766
|
+
children: "\u25B6"
|
|
5767
|
+
}
|
|
5768
|
+
)
|
|
5769
|
+
}
|
|
5770
|
+
);
|
|
5771
|
+
},
|
|
5772
|
+
size,
|
|
5773
|
+
enableSorting: false,
|
|
5774
|
+
enableColumnFilter: false,
|
|
5775
|
+
enableResizing: false,
|
|
5776
|
+
enableReorder: false,
|
|
5777
|
+
lockVisible: true
|
|
5778
|
+
};
|
|
5779
|
+
}
|
|
5780
|
+
function CellStack({ children, gap = 2 }) {
|
|
5781
|
+
return /* @__PURE__ */ jsx(
|
|
5782
|
+
"div",
|
|
5783
|
+
{
|
|
5784
|
+
className: "yable-cell-stack",
|
|
5785
|
+
style: {
|
|
5786
|
+
display: "flex",
|
|
5787
|
+
flexDirection: "column",
|
|
5788
|
+
gap
|
|
5789
|
+
},
|
|
5790
|
+
children
|
|
5791
|
+
}
|
|
5792
|
+
);
|
|
5793
|
+
}
|
|
5794
|
+
function CellRow({ children, gap = 6, align = "center", justify = "start" }) {
|
|
5795
|
+
const justifyMap = {
|
|
5796
|
+
start: "flex-start",
|
|
5797
|
+
center: "center",
|
|
5798
|
+
end: "flex-end",
|
|
5799
|
+
between: "space-between"
|
|
5800
|
+
};
|
|
5801
|
+
return /* @__PURE__ */ jsx(
|
|
5802
|
+
"div",
|
|
5803
|
+
{
|
|
5804
|
+
className: "yable-cell-row",
|
|
5805
|
+
style: {
|
|
5806
|
+
display: "flex",
|
|
5807
|
+
flexDirection: "row",
|
|
5808
|
+
alignItems: align === "baseline" ? "baseline" : align === "start" ? "flex-start" : align === "end" ? "flex-end" : "center",
|
|
5809
|
+
justifyContent: justifyMap[justify] || "flex-start",
|
|
5810
|
+
gap
|
|
5811
|
+
},
|
|
5812
|
+
children
|
|
5813
|
+
}
|
|
5814
|
+
);
|
|
5815
|
+
}
|
|
5816
|
+
function CellWithIcon({ icon, children, gap = 6, iconSize }) {
|
|
5817
|
+
return /* @__PURE__ */ jsxs(
|
|
5818
|
+
"div",
|
|
5819
|
+
{
|
|
5820
|
+
className: "yable-cell-with-icon",
|
|
5821
|
+
style: {
|
|
5822
|
+
display: "flex",
|
|
5823
|
+
flexDirection: "row",
|
|
5824
|
+
alignItems: "center",
|
|
5825
|
+
gap
|
|
5826
|
+
},
|
|
5827
|
+
children: [
|
|
5828
|
+
/* @__PURE__ */ jsx(
|
|
5829
|
+
"span",
|
|
5830
|
+
{
|
|
5831
|
+
className: "yable-cell-icon",
|
|
5832
|
+
style: {
|
|
5833
|
+
display: "inline-flex",
|
|
5834
|
+
alignItems: "center",
|
|
5835
|
+
justifyContent: "center",
|
|
5836
|
+
flexShrink: 0,
|
|
5837
|
+
...iconSize ? { width: iconSize, height: iconSize } : {}
|
|
5838
|
+
},
|
|
5839
|
+
children: icon
|
|
5840
|
+
}
|
|
5841
|
+
),
|
|
5842
|
+
/* @__PURE__ */ jsx("span", { className: "yable-cell-icon-content", style: { minWidth: 0 }, children })
|
|
5843
|
+
]
|
|
5844
|
+
}
|
|
5845
|
+
);
|
|
5846
|
+
}
|
|
5847
|
+
function CellText({
|
|
5848
|
+
children,
|
|
5849
|
+
variant = "primary",
|
|
5850
|
+
bold,
|
|
5851
|
+
truncate,
|
|
5852
|
+
size = "md"
|
|
5853
|
+
}) {
|
|
5854
|
+
const fontSizeMap = { sm: "0.75rem", md: "0.875rem", lg: "1rem" };
|
|
5855
|
+
return /* @__PURE__ */ jsx(
|
|
5856
|
+
"span",
|
|
5857
|
+
{
|
|
5858
|
+
className: `yable-cell-text yable-cell-text--${variant}`,
|
|
5859
|
+
style: {
|
|
5860
|
+
fontSize: fontSizeMap[size],
|
|
5861
|
+
fontWeight: bold ? 600 : void 0,
|
|
5862
|
+
color: variant === "secondary" ? "var(--yable-text-secondary, #6b7280)" : variant === "muted" ? "var(--yable-text-muted, #9ca3af)" : void 0,
|
|
5863
|
+
...truncate ? {
|
|
5864
|
+
overflow: "hidden",
|
|
5865
|
+
textOverflow: "ellipsis",
|
|
5866
|
+
whiteSpace: "nowrap"
|
|
5867
|
+
} : {}
|
|
5868
|
+
},
|
|
5869
|
+
children
|
|
5870
|
+
}
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
|
|
5874
|
+
// src/utils/mergeEditChanges.ts
|
|
5875
|
+
function mergeEditChanges(data, changes, getRowId = (_, i) => String(i)) {
|
|
5876
|
+
const changeKeys = Object.keys(changes);
|
|
5877
|
+
if (changeKeys.length === 0) return data;
|
|
5878
|
+
return data.map((row, i) => {
|
|
5879
|
+
const id = getRowId(row, i);
|
|
5880
|
+
const patch = changes[id];
|
|
5881
|
+
return patch ? { ...row, ...patch } : row;
|
|
5882
|
+
});
|
|
5883
|
+
}
|
|
4856
5884
|
|
|
4857
|
-
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, GlobalFilter, LoadingOverlay, MasterDetail, NoRowsOverlay, Pagination, PivotConfigPanel, PrintLayout, Sidebar, SortIndicator, StatusBar, StatusBarPanelComponent, Table, TableBody, TableCell, TableFooter, TableHeader, TableProvider, Tooltip, TreeToggle, getMeasureRecipeForCellType, getRegisteredCellTypes, resolveMeasureRecipe, useAutoMeasurements, useCellFlash, useClipboard, useContextMenu, useFillHandle, useKeyboardNavigation, usePretextMeasurement, usePrintLayout, useRowAnimation, useRowDrag, useTable, useTableContext, useTableRowHeights, useTheme, useTooltip, useVirtualization };
|
|
5885
|
+
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, expandColumn, getMeasureRecipeForCellType, getRegisteredCellTypes, mergeEditChanges, resolveMeasureRecipe, rowNumberColumn, selectColumn, useAutoMeasurements, useCellFlash, useClipboard, useColumnVirtualization, useContextMenu, useFillHandle, useKeyboardNavigation, usePretextMeasurement, usePrintLayout, useRowAnimation, useRowDrag, useTable, useTableContext, useTablePersistence, useTableRowHeights, useTheme, useTooltip, useVirtualization, useYableDefaults };
|
|
4858
5886
|
//# sourceMappingURL=index.js.map
|
|
4859
5887
|
//# sourceMappingURL=index.js.map
|