@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.cjs
CHANGED
|
@@ -10,6 +10,37 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
10
10
|
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
11
11
|
|
|
12
12
|
// src/index.ts
|
|
13
|
+
var YableContext = React3.createContext({});
|
|
14
|
+
function useYableDefaults() {
|
|
15
|
+
return React3.useContext(YableContext);
|
|
16
|
+
}
|
|
17
|
+
function YableProvider({
|
|
18
|
+
children,
|
|
19
|
+
defaultColumnDef,
|
|
20
|
+
striped,
|
|
21
|
+
stickyHeader,
|
|
22
|
+
bordered,
|
|
23
|
+
compact,
|
|
24
|
+
theme,
|
|
25
|
+
direction,
|
|
26
|
+
ariaLabel
|
|
27
|
+
}) {
|
|
28
|
+
const tableProps = {};
|
|
29
|
+
if (striped !== void 0) tableProps.striped = striped;
|
|
30
|
+
if (stickyHeader !== void 0) tableProps.stickyHeader = stickyHeader;
|
|
31
|
+
if (bordered !== void 0) tableProps.bordered = bordered;
|
|
32
|
+
if (compact !== void 0) tableProps.compact = compact;
|
|
33
|
+
if (theme !== void 0) tableProps.theme = theme;
|
|
34
|
+
if (direction !== void 0) tableProps.direction = direction;
|
|
35
|
+
if (ariaLabel !== void 0) tableProps.ariaLabel = ariaLabel;
|
|
36
|
+
const value = {
|
|
37
|
+
tableProps: Object.keys(tableProps).length > 0 ? tableProps : void 0,
|
|
38
|
+
defaultColumnDef
|
|
39
|
+
};
|
|
40
|
+
return /* @__PURE__ */ jsxRuntime.jsx(YableContext.Provider, { value, children });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/useTable.ts
|
|
13
44
|
function shallowEqual(a, b) {
|
|
14
45
|
if (a === b) return true;
|
|
15
46
|
const keysA = Object.keys(a);
|
|
@@ -22,6 +53,17 @@ function shallowEqual(a, b) {
|
|
|
22
53
|
return true;
|
|
23
54
|
}
|
|
24
55
|
function useTable(options) {
|
|
56
|
+
const providerDefaults = useYableDefaults();
|
|
57
|
+
const optionsWithDefaults = React3.useMemo(() => {
|
|
58
|
+
if (!providerDefaults.defaultColumnDef) return options;
|
|
59
|
+
return {
|
|
60
|
+
...options,
|
|
61
|
+
defaultColumnDef: {
|
|
62
|
+
...providerDefaults.defaultColumnDef,
|
|
63
|
+
...options.defaultColumnDef
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [options, providerDefaults.defaultColumnDef]);
|
|
25
67
|
const [state, setState] = React3.useState(() => ({
|
|
26
68
|
sorting: [],
|
|
27
69
|
columnFilters: [],
|
|
@@ -61,14 +103,14 @@ function useTable(options) {
|
|
|
61
103
|
}));
|
|
62
104
|
const stateRef = React3.useRef(state);
|
|
63
105
|
stateRef.current = state;
|
|
64
|
-
const prevOptionsRef = React3.useRef(
|
|
106
|
+
const prevOptionsRef = React3.useRef(optionsWithDefaults);
|
|
65
107
|
const stableOptions = React3.useMemo(() => {
|
|
66
|
-
if (shallowEqual(prevOptionsRef.current,
|
|
108
|
+
if (shallowEqual(prevOptionsRef.current, optionsWithDefaults)) {
|
|
67
109
|
return prevOptionsRef.current;
|
|
68
110
|
}
|
|
69
|
-
prevOptionsRef.current =
|
|
70
|
-
return
|
|
71
|
-
}, [
|
|
111
|
+
prevOptionsRef.current = optionsWithDefaults;
|
|
112
|
+
return optionsWithDefaults;
|
|
113
|
+
}, [optionsWithDefaults]);
|
|
72
114
|
const onStateChangeRef = React3.useRef(options.onStateChange);
|
|
73
115
|
onStateChangeRef.current = options.onStateChange;
|
|
74
116
|
const resolvedState = React3.useMemo(
|
|
@@ -78,17 +120,14 @@ function useTable(options) {
|
|
|
78
120
|
}),
|
|
79
121
|
[state, stableOptions.state]
|
|
80
122
|
);
|
|
81
|
-
const onStateChange = React3.useCallback(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
[]
|
|
91
|
-
);
|
|
123
|
+
const onStateChange = React3.useCallback((updater) => {
|
|
124
|
+
const latest = onStateChangeRef.current;
|
|
125
|
+
if (latest) {
|
|
126
|
+
latest(updater);
|
|
127
|
+
} else {
|
|
128
|
+
setState((prev) => yableCore.functionalUpdate(updater, prev));
|
|
129
|
+
}
|
|
130
|
+
}, []);
|
|
92
131
|
const resolvedOptions = React3.useMemo(
|
|
93
132
|
() => ({
|
|
94
133
|
...stableOptions,
|
|
@@ -101,12 +140,14 @@ function useTable(options) {
|
|
|
101
140
|
if (!tableRef.current) {
|
|
102
141
|
tableRef.current = yableCore.createTable(resolvedOptions);
|
|
103
142
|
} else {
|
|
104
|
-
tableRef.current.setOptions(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
143
|
+
tableRef.current.setOptions(
|
|
144
|
+
(prev) => ({
|
|
145
|
+
...prev,
|
|
146
|
+
...resolvedOptions,
|
|
147
|
+
state: resolvedState,
|
|
148
|
+
onStateChange
|
|
149
|
+
})
|
|
150
|
+
);
|
|
110
151
|
}
|
|
111
152
|
React3.useEffect(() => {
|
|
112
153
|
return () => {
|
|
@@ -117,6 +158,122 @@ function useTable(options) {
|
|
|
117
158
|
}, []);
|
|
118
159
|
return tableRef.current;
|
|
119
160
|
}
|
|
161
|
+
var DEFAULT_PERSISTED_KEYS = [
|
|
162
|
+
"columnVisibility",
|
|
163
|
+
"columnOrder",
|
|
164
|
+
"columnSizing",
|
|
165
|
+
"columnPinning"
|
|
166
|
+
];
|
|
167
|
+
function resolveStorage(custom) {
|
|
168
|
+
if (custom) return custom;
|
|
169
|
+
if (typeof window !== "undefined") {
|
|
170
|
+
try {
|
|
171
|
+
return window.localStorage;
|
|
172
|
+
} catch {
|
|
173
|
+
return void 0;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return void 0;
|
|
177
|
+
}
|
|
178
|
+
function pick(obj, keys) {
|
|
179
|
+
const result = {};
|
|
180
|
+
for (const k of keys) {
|
|
181
|
+
if (k in obj) {
|
|
182
|
+
result[k] = obj[k];
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
function readState(storage, key, version, persistedKeys) {
|
|
188
|
+
if (!storage) return {};
|
|
189
|
+
try {
|
|
190
|
+
const raw = storage.getItem(key);
|
|
191
|
+
if (!raw) return {};
|
|
192
|
+
const envelope = JSON.parse(raw);
|
|
193
|
+
if (envelope.version !== version) {
|
|
194
|
+
storage.removeItem(key);
|
|
195
|
+
return {};
|
|
196
|
+
}
|
|
197
|
+
return pick(envelope.state, persistedKeys);
|
|
198
|
+
} catch {
|
|
199
|
+
if (typeof console !== "undefined") {
|
|
200
|
+
console.warn(`[yable] Failed to read persisted state for key "${key}"`);
|
|
201
|
+
}
|
|
202
|
+
return {};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function writeState(storage, key, version, state) {
|
|
206
|
+
if (!storage) return;
|
|
207
|
+
try {
|
|
208
|
+
const envelope = { version, state };
|
|
209
|
+
storage.setItem(key, JSON.stringify(envelope));
|
|
210
|
+
} catch {
|
|
211
|
+
if (typeof console !== "undefined") {
|
|
212
|
+
console.warn(`[yable] Failed to persist state for key "${key}" (storage may be full)`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function useTablePersistence(options) {
|
|
217
|
+
const {
|
|
218
|
+
key,
|
|
219
|
+
persistedKeys = DEFAULT_PERSISTED_KEYS,
|
|
220
|
+
debounce: debounceMs = 100,
|
|
221
|
+
version = 0,
|
|
222
|
+
storage: customStorage
|
|
223
|
+
} = options;
|
|
224
|
+
const storage = React3.useMemo(() => resolveStorage(customStorage), [customStorage]);
|
|
225
|
+
const initialState = React3.useMemo(
|
|
226
|
+
() => readState(storage, key, version, persistedKeys),
|
|
227
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally read only on mount
|
|
228
|
+
[]
|
|
229
|
+
);
|
|
230
|
+
const [state, setState] = React3.useState(initialState);
|
|
231
|
+
const timerRef = React3.useRef(null);
|
|
232
|
+
const keyRef = React3.useRef(key);
|
|
233
|
+
keyRef.current = key;
|
|
234
|
+
const versionRef = React3.useRef(version);
|
|
235
|
+
versionRef.current = version;
|
|
236
|
+
const persistedKeysRef = React3.useRef(persistedKeys);
|
|
237
|
+
persistedKeysRef.current = persistedKeys;
|
|
238
|
+
const debounceRef = React3.useRef(debounceMs);
|
|
239
|
+
debounceRef.current = debounceMs;
|
|
240
|
+
const storageRef = React3.useRef(storage);
|
|
241
|
+
storageRef.current = storage;
|
|
242
|
+
const onStateChange = React3.useCallback((updater) => {
|
|
243
|
+
setState((prev) => {
|
|
244
|
+
const next = yableCore.functionalUpdate(updater, prev);
|
|
245
|
+
if (timerRef.current !== null) {
|
|
246
|
+
clearTimeout(timerRef.current);
|
|
247
|
+
}
|
|
248
|
+
timerRef.current = setTimeout(() => {
|
|
249
|
+
const sliced = pick(
|
|
250
|
+
next,
|
|
251
|
+
persistedKeysRef.current
|
|
252
|
+
);
|
|
253
|
+
writeState(storageRef.current, keyRef.current, versionRef.current, sliced);
|
|
254
|
+
timerRef.current = null;
|
|
255
|
+
}, debounceRef.current);
|
|
256
|
+
return next;
|
|
257
|
+
});
|
|
258
|
+
}, []);
|
|
259
|
+
React3.useEffect(() => {
|
|
260
|
+
return () => {
|
|
261
|
+
if (timerRef.current !== null) {
|
|
262
|
+
clearTimeout(timerRef.current);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}, []);
|
|
266
|
+
const clearPersistedState = React3.useCallback(() => {
|
|
267
|
+
const s = storageRef.current;
|
|
268
|
+
if (s) {
|
|
269
|
+
try {
|
|
270
|
+
s.removeItem(keyRef.current);
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}, []);
|
|
275
|
+
return { initialState, state, onStateChange, clearPersistedState };
|
|
276
|
+
}
|
|
120
277
|
var EMPTY_RESULT = {
|
|
121
278
|
virtualRows: [],
|
|
122
279
|
totalHeight: 0,
|
|
@@ -130,11 +287,14 @@ function useVirtualization({
|
|
|
130
287
|
overscan = 5,
|
|
131
288
|
estimateRowHeight: _estimateRowHeight,
|
|
132
289
|
pretextHeights,
|
|
133
|
-
pretextPrefixSums
|
|
290
|
+
pretextPrefixSums,
|
|
291
|
+
columnSizingHash
|
|
134
292
|
}) {
|
|
135
293
|
const hasPretextHeights = !!(pretextHeights && pretextPrefixSums && pretextHeights.length >= totalRows);
|
|
136
294
|
const isFixedHeight = typeof rowHeight === "number" && !hasPretextHeights;
|
|
137
295
|
const heightCacheRef = React3.useRef(/* @__PURE__ */ new Map());
|
|
296
|
+
const heightCacheVersionRef = React3.useRef(0);
|
|
297
|
+
const [heightCacheVersion, setHeightCacheVersion] = React3.useState(0);
|
|
138
298
|
const getRowHeight = React3.useCallback(
|
|
139
299
|
(index) => {
|
|
140
300
|
if (hasPretextHeights) return pretextHeights[index];
|
|
@@ -145,7 +305,9 @@ function useVirtualization({
|
|
|
145
305
|
heightCacheRef.current.set(index, height);
|
|
146
306
|
return height;
|
|
147
307
|
},
|
|
148
|
-
|
|
308
|
+
// heightCacheVersion forces a new callback identity after cache invalidation
|
|
309
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
310
|
+
[rowHeight, isFixedHeight, hasPretextHeights, pretextHeights, heightCacheVersion]
|
|
149
311
|
);
|
|
150
312
|
const [scrollState, setScrollState] = React3.useState({ scrollTop: 0, containerHeight: 0 });
|
|
151
313
|
const rafRef = React3.useRef(null);
|
|
@@ -198,6 +360,18 @@ function useVirtualization({
|
|
|
198
360
|
heightCacheRef.current.clear();
|
|
199
361
|
}
|
|
200
362
|
}, [totalRows, isFixedHeight]);
|
|
363
|
+
React3.useEffect(() => {
|
|
364
|
+
if (!isFixedHeight && columnSizingHash !== void 0) {
|
|
365
|
+
heightCacheRef.current.clear();
|
|
366
|
+
heightCacheVersionRef.current += 1;
|
|
367
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
368
|
+
}
|
|
369
|
+
}, [columnSizingHash]);
|
|
370
|
+
const invalidateRowHeights = React3.useCallback(() => {
|
|
371
|
+
heightCacheRef.current.clear();
|
|
372
|
+
heightCacheVersionRef.current += 1;
|
|
373
|
+
setHeightCacheVersion(heightCacheVersionRef.current);
|
|
374
|
+
}, []);
|
|
201
375
|
const scrollTo = React3.useCallback(
|
|
202
376
|
(index) => {
|
|
203
377
|
const container = containerRef.current;
|
|
@@ -215,7 +389,15 @@ function useVirtualization({
|
|
|
215
389
|
container.scrollTop = offset;
|
|
216
390
|
}
|
|
217
391
|
},
|
|
218
|
-
[
|
|
392
|
+
[
|
|
393
|
+
containerRef,
|
|
394
|
+
totalRows,
|
|
395
|
+
rowHeight,
|
|
396
|
+
isFixedHeight,
|
|
397
|
+
getRowHeight,
|
|
398
|
+
hasPretextHeights,
|
|
399
|
+
pretextPrefixSums
|
|
400
|
+
]
|
|
219
401
|
);
|
|
220
402
|
const totalHeight = React3.useMemo(() => {
|
|
221
403
|
if (totalRows === 0) return 0;
|
|
@@ -226,10 +408,18 @@ function useVirtualization({
|
|
|
226
408
|
total += getRowHeight(i);
|
|
227
409
|
}
|
|
228
410
|
return total;
|
|
229
|
-
}, [
|
|
411
|
+
}, [
|
|
412
|
+
totalRows,
|
|
413
|
+
rowHeight,
|
|
414
|
+
isFixedHeight,
|
|
415
|
+
getRowHeight,
|
|
416
|
+
hasPretextHeights,
|
|
417
|
+
pretextPrefixSums,
|
|
418
|
+
heightCacheVersion
|
|
419
|
+
]);
|
|
230
420
|
const { scrollTop, containerHeight } = scrollState;
|
|
231
421
|
if (totalRows === 0) {
|
|
232
|
-
return { ...EMPTY_RESULT, scrollTo };
|
|
422
|
+
return { ...EMPTY_RESULT, scrollTo, invalidateRowHeights };
|
|
233
423
|
}
|
|
234
424
|
if (containerHeight === 0) {
|
|
235
425
|
return {
|
|
@@ -237,7 +427,8 @@ function useVirtualization({
|
|
|
237
427
|
totalHeight,
|
|
238
428
|
startIndex: 0,
|
|
239
429
|
endIndex: 0,
|
|
240
|
-
scrollTo
|
|
430
|
+
scrollTo,
|
|
431
|
+
invalidateRowHeights
|
|
241
432
|
};
|
|
242
433
|
}
|
|
243
434
|
let startIndex = 0;
|
|
@@ -269,10 +460,7 @@ function useVirtualization({
|
|
|
269
460
|
} else if (isFixedHeight) {
|
|
270
461
|
const fixedH = rowHeight;
|
|
271
462
|
startIndex = Math.floor(scrollTop / fixedH);
|
|
272
|
-
endIndex = Math.min(
|
|
273
|
-
totalRows - 1,
|
|
274
|
-
Math.ceil((scrollTop + containerHeight) / fixedH) - 1
|
|
275
|
-
);
|
|
463
|
+
endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / fixedH) - 1);
|
|
276
464
|
} else {
|
|
277
465
|
let accum = 0;
|
|
278
466
|
let foundStart = false;
|
|
@@ -336,7 +524,164 @@ function useVirtualization({
|
|
|
336
524
|
totalHeight,
|
|
337
525
|
startIndex: overscanStart,
|
|
338
526
|
endIndex: overscanEnd,
|
|
339
|
-
scrollTo
|
|
527
|
+
scrollTo,
|
|
528
|
+
invalidateRowHeights
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function binarySearchOffsets(offsets, target) {
|
|
532
|
+
let low = 0;
|
|
533
|
+
let high = offsets.length - 1;
|
|
534
|
+
while (low < high) {
|
|
535
|
+
const mid = low + high >>> 1;
|
|
536
|
+
if (offsets[mid + 1] <= target) {
|
|
537
|
+
low = mid + 1;
|
|
538
|
+
} else {
|
|
539
|
+
high = mid;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return low;
|
|
543
|
+
}
|
|
544
|
+
function useColumnVirtualization({
|
|
545
|
+
containerRef,
|
|
546
|
+
columns,
|
|
547
|
+
overscan = 2,
|
|
548
|
+
enabled = true
|
|
549
|
+
}) {
|
|
550
|
+
const [scrollState, setScrollState] = React3.useState({
|
|
551
|
+
scrollLeft: 0,
|
|
552
|
+
containerWidth: 0
|
|
553
|
+
});
|
|
554
|
+
const rafRef = React3.useRef(null);
|
|
555
|
+
const sizes = React3.useMemo(() => columns.map((column) => column.getSize()), [columns]);
|
|
556
|
+
const offsets = React3.useMemo(() => {
|
|
557
|
+
const next = new Array(columns.length + 1);
|
|
558
|
+
next[0] = 0;
|
|
559
|
+
for (let i = 0; i < columns.length; i++) {
|
|
560
|
+
next[i + 1] = next[i] + (sizes[i] ?? 0);
|
|
561
|
+
}
|
|
562
|
+
return next;
|
|
563
|
+
}, [columns.length, sizes]);
|
|
564
|
+
const totalWidth = offsets[offsets.length - 1] ?? 0;
|
|
565
|
+
React3.useEffect(() => {
|
|
566
|
+
const container = containerRef.current;
|
|
567
|
+
if (!container) return;
|
|
568
|
+
setScrollState({
|
|
569
|
+
scrollLeft: container.scrollLeft,
|
|
570
|
+
containerWidth: container.clientWidth
|
|
571
|
+
});
|
|
572
|
+
const handleScroll = () => {
|
|
573
|
+
if (rafRef.current !== null) return;
|
|
574
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
575
|
+
rafRef.current = null;
|
|
576
|
+
const el = containerRef.current;
|
|
577
|
+
if (!el) return;
|
|
578
|
+
setScrollState({
|
|
579
|
+
scrollLeft: el.scrollLeft,
|
|
580
|
+
containerWidth: el.clientWidth
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
};
|
|
584
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
585
|
+
let resizeObserver;
|
|
586
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
587
|
+
resizeObserver = new ResizeObserver(() => {
|
|
588
|
+
const el = containerRef.current;
|
|
589
|
+
if (!el) return;
|
|
590
|
+
setScrollState((prev) => {
|
|
591
|
+
const nextWidth = el.clientWidth;
|
|
592
|
+
if (prev.containerWidth === nextWidth && prev.scrollLeft === el.scrollLeft) {
|
|
593
|
+
return prev;
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
scrollLeft: el.scrollLeft,
|
|
597
|
+
containerWidth: nextWidth
|
|
598
|
+
};
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
resizeObserver.observe(container);
|
|
602
|
+
}
|
|
603
|
+
return () => {
|
|
604
|
+
container.removeEventListener("scroll", handleScroll);
|
|
605
|
+
if (rafRef.current !== null) {
|
|
606
|
+
cancelAnimationFrame(rafRef.current);
|
|
607
|
+
rafRef.current = null;
|
|
608
|
+
}
|
|
609
|
+
resizeObserver?.disconnect();
|
|
610
|
+
};
|
|
611
|
+
}, [containerRef]);
|
|
612
|
+
const scrollToIndex = React3.useCallback(
|
|
613
|
+
(index) => {
|
|
614
|
+
const container = containerRef.current;
|
|
615
|
+
if (!container || columns.length === 0) return;
|
|
616
|
+
const clampedIndex = Math.max(0, Math.min(index, columns.length - 1));
|
|
617
|
+
container.scrollLeft = offsets[clampedIndex] ?? 0;
|
|
618
|
+
},
|
|
619
|
+
[columns.length, containerRef, offsets]
|
|
620
|
+
);
|
|
621
|
+
if (!enabled || columns.length === 0) {
|
|
622
|
+
return {
|
|
623
|
+
virtualColumns: columns.map((column, index) => ({
|
|
624
|
+
column,
|
|
625
|
+
index,
|
|
626
|
+
start: offsets[index] ?? 0,
|
|
627
|
+
size: sizes[index] ?? 0
|
|
628
|
+
})),
|
|
629
|
+
startOffset: 0,
|
|
630
|
+
endOffset: 0,
|
|
631
|
+
totalWidth,
|
|
632
|
+
visibleWidth: totalWidth,
|
|
633
|
+
startIndex: 0,
|
|
634
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
635
|
+
isVirtualized: false,
|
|
636
|
+
scrollToIndex
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
const { scrollLeft, containerWidth } = scrollState;
|
|
640
|
+
if (containerWidth <= 0 || totalWidth <= containerWidth) {
|
|
641
|
+
return {
|
|
642
|
+
virtualColumns: columns.map((column, index) => ({
|
|
643
|
+
column,
|
|
644
|
+
index,
|
|
645
|
+
start: offsets[index] ?? 0,
|
|
646
|
+
size: sizes[index] ?? 0
|
|
647
|
+
})),
|
|
648
|
+
startOffset: 0,
|
|
649
|
+
endOffset: 0,
|
|
650
|
+
totalWidth,
|
|
651
|
+
visibleWidth: totalWidth,
|
|
652
|
+
startIndex: 0,
|
|
653
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
654
|
+
isVirtualized: false,
|
|
655
|
+
scrollToIndex
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
const startIndex = binarySearchOffsets(offsets, scrollLeft);
|
|
659
|
+
const endBoundary = scrollLeft + containerWidth;
|
|
660
|
+
const endIndex = binarySearchOffsets(offsets, Math.max(scrollLeft, endBoundary - 1));
|
|
661
|
+
const overscanStart = Math.max(0, startIndex - overscan);
|
|
662
|
+
const overscanEnd = Math.min(columns.length - 1, endIndex + overscan);
|
|
663
|
+
const virtualColumns = [];
|
|
664
|
+
for (let i = overscanStart; i <= overscanEnd; i++) {
|
|
665
|
+
virtualColumns.push({
|
|
666
|
+
column: columns[i],
|
|
667
|
+
index: i,
|
|
668
|
+
start: offsets[i] ?? 0,
|
|
669
|
+
size: sizes[i] ?? 0
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
const startOffset = offsets[overscanStart] ?? 0;
|
|
673
|
+
const visibleWidth = (offsets[overscanEnd + 1] ?? totalWidth) - startOffset;
|
|
674
|
+
const endOffset = totalWidth - (offsets[overscanEnd + 1] ?? totalWidth);
|
|
675
|
+
return {
|
|
676
|
+
virtualColumns,
|
|
677
|
+
startOffset,
|
|
678
|
+
endOffset,
|
|
679
|
+
totalWidth,
|
|
680
|
+
visibleWidth,
|
|
681
|
+
startIndex: overscanStart,
|
|
682
|
+
endIndex: overscanEnd,
|
|
683
|
+
isVirtualized: true,
|
|
684
|
+
scrollToIndex
|
|
340
685
|
};
|
|
341
686
|
}
|
|
342
687
|
var pretextPromise = null;
|
|
@@ -389,7 +734,12 @@ function usePretextMeasurement({
|
|
|
389
734
|
}
|
|
390
735
|
prepareTimeRef.current = performance.now() - start;
|
|
391
736
|
return result;
|
|
392
|
-
}, [
|
|
737
|
+
}, [
|
|
738
|
+
pretext,
|
|
739
|
+
enabled,
|
|
740
|
+
data,
|
|
741
|
+
columns.map((c) => `${c.columnId}:${c.font}:${c.fixedHeight ? "F" : "T"}`).join("|")
|
|
742
|
+
]);
|
|
393
743
|
const measurement = React3.useMemo(() => {
|
|
394
744
|
if (!pretext || !preparedCells) {
|
|
395
745
|
return { rowHeights: null, prefixSums: null, totalHeight: 0 };
|
|
@@ -427,6 +777,7 @@ function usePretextMeasurement({
|
|
|
427
777
|
return {
|
|
428
778
|
rowHeights,
|
|
429
779
|
prefixSums,
|
|
780
|
+
// Safe: prefixSums has length data.length + 1, so [data.length] always exists
|
|
430
781
|
totalHeight: prefixSums[data.length]
|
|
431
782
|
};
|
|
432
783
|
}, [pretext, preparedCells, columnWidthsKey, minRowHeight, data.length]);
|
|
@@ -691,18 +1042,10 @@ function CellDate({
|
|
|
691
1042
|
if (raw == null) return null;
|
|
692
1043
|
const date = raw instanceof Date ? raw : new Date(String(raw));
|
|
693
1044
|
if (isNaN(date.getTime())) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "yable-cell-date", children: String(raw) });
|
|
694
|
-
const formatter =
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
timeZone: "UTC"
|
|
699
|
-
});
|
|
700
|
-
}
|
|
701
|
-
if (typeof format === "object") {
|
|
702
|
-
return new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" });
|
|
703
|
-
}
|
|
704
|
-
return null;
|
|
705
|
-
}, [format, locale]);
|
|
1045
|
+
const formatter = typeof format === "string" && format !== "relative" ? new Intl.DateTimeFormat(locale, {
|
|
1046
|
+
...PRESETS[format],
|
|
1047
|
+
timeZone: "UTC"
|
|
1048
|
+
}) : typeof format === "object" ? new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" }) : null;
|
|
706
1049
|
const formatted = format === "relative" ? formatRelative(date) : formatter ? formatter.format(date) : date.toLocaleDateString(locale);
|
|
707
1050
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `yable-cell-date ${className ?? ""}`, title: date.toISOString(), children: formatted });
|
|
708
1051
|
}
|
|
@@ -713,8 +1056,14 @@ var measureRecipe9 = {
|
|
|
713
1056
|
padding: 20
|
|
714
1057
|
};
|
|
715
1058
|
function isSafeUrl(url) {
|
|
716
|
-
const normalized = String(url).
|
|
717
|
-
|
|
1059
|
+
const normalized = String(url).trim();
|
|
1060
|
+
if (/^[/#?]/.test(normalized)) return true;
|
|
1061
|
+
try {
|
|
1062
|
+
const parsed = new URL(normalized, "https://placeholder.invalid");
|
|
1063
|
+
return ["http:", "https:", "mailto:", "tel:"].includes(parsed.protocol);
|
|
1064
|
+
} catch {
|
|
1065
|
+
return false;
|
|
1066
|
+
}
|
|
718
1067
|
}
|
|
719
1068
|
function CellLink({
|
|
720
1069
|
context,
|
|
@@ -891,7 +1240,7 @@ function useTableContext() {
|
|
|
891
1240
|
const ctx = React3.useContext(TableContext);
|
|
892
1241
|
if (!ctx) {
|
|
893
1242
|
throw new Error(
|
|
894
|
-
"[yable] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
1243
|
+
"[yable E001] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
895
1244
|
);
|
|
896
1245
|
}
|
|
897
1246
|
return ctx;
|
|
@@ -941,12 +1290,234 @@ function SortIndicator({ direction, index }) {
|
|
|
941
1290
|
}
|
|
942
1291
|
);
|
|
943
1292
|
}
|
|
1293
|
+
function formatValue(value) {
|
|
1294
|
+
if (value == null || value === "") return "(empty)";
|
|
1295
|
+
if (typeof value === "string") return value;
|
|
1296
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1297
|
+
if (value instanceof Date) return value.toISOString();
|
|
1298
|
+
return JSON.stringify(value);
|
|
1299
|
+
}
|
|
1300
|
+
function SetFilter({ column, className }) {
|
|
1301
|
+
const [open, setOpen] = React3.useState(false);
|
|
1302
|
+
const filterValue = column.getFilterValue();
|
|
1303
|
+
const selectedValues = Array.isArray(filterValue) ? filterValue : filterValue == null || filterValue === "" ? [] : [filterValue];
|
|
1304
|
+
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
1305
|
+
const options = Array.from(facetedUniqueValues.entries()).map(([value, count]) => ({
|
|
1306
|
+
value,
|
|
1307
|
+
count,
|
|
1308
|
+
label: formatValue(value)
|
|
1309
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
1310
|
+
const selectedSet = new Set(selectedValues);
|
|
1311
|
+
const toggleValue = (value) => {
|
|
1312
|
+
const next = new Set(selectedSet);
|
|
1313
|
+
if (next.has(value)) {
|
|
1314
|
+
next.delete(value);
|
|
1315
|
+
} else {
|
|
1316
|
+
next.add(value);
|
|
1317
|
+
}
|
|
1318
|
+
const nextValues = Array.from(next);
|
|
1319
|
+
column.setFilterValue(nextValues.length > 0 ? nextValues : void 0);
|
|
1320
|
+
};
|
|
1321
|
+
const headerLabel = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1322
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1323
|
+
"div",
|
|
1324
|
+
{
|
|
1325
|
+
className: ["yable-set-filter", className].filter(Boolean).join(" "),
|
|
1326
|
+
style: { position: "relative" },
|
|
1327
|
+
children: [
|
|
1328
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1329
|
+
"button",
|
|
1330
|
+
{
|
|
1331
|
+
type: "button",
|
|
1332
|
+
className: "yable-set-filter-trigger",
|
|
1333
|
+
"aria-haspopup": "dialog",
|
|
1334
|
+
"aria-expanded": open,
|
|
1335
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1336
|
+
style: {
|
|
1337
|
+
width: "100%",
|
|
1338
|
+
minHeight: 28,
|
|
1339
|
+
padding: "4px 8px",
|
|
1340
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1341
|
+
borderRadius: 6,
|
|
1342
|
+
background: "transparent",
|
|
1343
|
+
font: "inherit",
|
|
1344
|
+
textAlign: "left",
|
|
1345
|
+
cursor: "pointer"
|
|
1346
|
+
},
|
|
1347
|
+
children: selectedValues.length > 0 ? `${selectedValues.length} selected` : `Filter ${headerLabel}`
|
|
1348
|
+
}
|
|
1349
|
+
),
|
|
1350
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1351
|
+
"div",
|
|
1352
|
+
{
|
|
1353
|
+
role: "dialog",
|
|
1354
|
+
"aria-label": `${headerLabel} set filter`,
|
|
1355
|
+
className: "yable-set-filter-popover",
|
|
1356
|
+
style: {
|
|
1357
|
+
position: "absolute",
|
|
1358
|
+
insetInlineStart: 0,
|
|
1359
|
+
top: "calc(100% + 4px)",
|
|
1360
|
+
zIndex: 20,
|
|
1361
|
+
width: 220,
|
|
1362
|
+
maxHeight: 240,
|
|
1363
|
+
overflow: "auto",
|
|
1364
|
+
padding: 8,
|
|
1365
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1366
|
+
borderRadius: 8,
|
|
1367
|
+
background: "var(--yable-color-bg, #fff)",
|
|
1368
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.12)"
|
|
1369
|
+
},
|
|
1370
|
+
children: [
|
|
1371
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1372
|
+
"div",
|
|
1373
|
+
{
|
|
1374
|
+
style: {
|
|
1375
|
+
display: "flex",
|
|
1376
|
+
alignItems: "center",
|
|
1377
|
+
justifyContent: "space-between",
|
|
1378
|
+
gap: 8,
|
|
1379
|
+
marginBottom: 8
|
|
1380
|
+
},
|
|
1381
|
+
children: [
|
|
1382
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: 12 }, children: headerLabel }),
|
|
1383
|
+
selectedValues.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1384
|
+
"button",
|
|
1385
|
+
{
|
|
1386
|
+
type: "button",
|
|
1387
|
+
onClick: () => column.setFilterValue(void 0),
|
|
1388
|
+
style: {
|
|
1389
|
+
border: "none",
|
|
1390
|
+
background: "transparent",
|
|
1391
|
+
padding: 0,
|
|
1392
|
+
cursor: "pointer",
|
|
1393
|
+
fontSize: 12
|
|
1394
|
+
},
|
|
1395
|
+
children: "Clear"
|
|
1396
|
+
}
|
|
1397
|
+
)
|
|
1398
|
+
]
|
|
1399
|
+
}
|
|
1400
|
+
),
|
|
1401
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": `${headerLabel} options`, children: [
|
|
1402
|
+
options.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, opacity: 0.75 }, children: "No values" }),
|
|
1403
|
+
options.map((option) => {
|
|
1404
|
+
const checked = selectedSet.has(option.value);
|
|
1405
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1406
|
+
"label",
|
|
1407
|
+
{
|
|
1408
|
+
style: {
|
|
1409
|
+
display: "flex",
|
|
1410
|
+
alignItems: "center",
|
|
1411
|
+
gap: 8,
|
|
1412
|
+
padding: "4px 0",
|
|
1413
|
+
fontSize: 12
|
|
1414
|
+
},
|
|
1415
|
+
children: [
|
|
1416
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1417
|
+
"input",
|
|
1418
|
+
{
|
|
1419
|
+
type: "checkbox",
|
|
1420
|
+
checked,
|
|
1421
|
+
onChange: () => toggleValue(option.value)
|
|
1422
|
+
}
|
|
1423
|
+
),
|
|
1424
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: option.label }),
|
|
1425
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { opacity: 0.6 }, children: option.count })
|
|
1426
|
+
]
|
|
1427
|
+
},
|
|
1428
|
+
`${option.label}-${option.count}`
|
|
1429
|
+
);
|
|
1430
|
+
})
|
|
1431
|
+
] })
|
|
1432
|
+
]
|
|
1433
|
+
}
|
|
1434
|
+
)
|
|
1435
|
+
]
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
function isSetCompatibleValue(value) {
|
|
1440
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1441
|
+
}
|
|
1442
|
+
function inferFilterVariant(column) {
|
|
1443
|
+
const meta = column.columnDef.meta ?? {};
|
|
1444
|
+
if (meta.filterVariant) return meta.filterVariant;
|
|
1445
|
+
const uniqueValues = column.getFacetedUniqueValues();
|
|
1446
|
+
if (uniqueValues.size > 0 && uniqueValues.size <= 12) {
|
|
1447
|
+
const allValuesSupported = Array.from(uniqueValues.keys()).every(isSetCompatibleValue);
|
|
1448
|
+
if (allValuesSupported) return "set";
|
|
1449
|
+
}
|
|
1450
|
+
return "text";
|
|
1451
|
+
}
|
|
1452
|
+
function FloatingFilter({ column }) {
|
|
1453
|
+
const variant = inferFilterVariant(column);
|
|
1454
|
+
if (!column.getCanFilter()) {
|
|
1455
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minHeight: 28 }, "aria-hidden": "true" });
|
|
1456
|
+
}
|
|
1457
|
+
if (variant === "set") {
|
|
1458
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SetFilter, { column });
|
|
1459
|
+
}
|
|
1460
|
+
const filterValue = column.getFilterValue();
|
|
1461
|
+
const normalizedValue = typeof filterValue === "string" || typeof filterValue === "number" ? String(filterValue) : "";
|
|
1462
|
+
const label = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1463
|
+
return /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1464
|
+
"input",
|
|
1465
|
+
{
|
|
1466
|
+
"aria-label": `Filter ${label}`,
|
|
1467
|
+
className: "yable-floating-filter-input",
|
|
1468
|
+
value: normalizedValue,
|
|
1469
|
+
onChange: (event) => {
|
|
1470
|
+
const nextValue = event.target.value;
|
|
1471
|
+
column.setFilterValue(nextValue === "" ? void 0 : nextValue);
|
|
1472
|
+
},
|
|
1473
|
+
placeholder: `Filter ${label}`,
|
|
1474
|
+
style: {
|
|
1475
|
+
width: "100%",
|
|
1476
|
+
minHeight: 28,
|
|
1477
|
+
padding: "4px 8px",
|
|
1478
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1479
|
+
borderRadius: 6,
|
|
1480
|
+
background: "transparent",
|
|
1481
|
+
font: "inherit"
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
) });
|
|
1485
|
+
}
|
|
944
1486
|
var DRAG_MIME = "application/yable-column";
|
|
945
1487
|
function TableHeader({
|
|
946
|
-
table
|
|
1488
|
+
table,
|
|
1489
|
+
floatingFilters = false
|
|
947
1490
|
}) {
|
|
948
1491
|
const headerGroups = table.getHeaderGroups();
|
|
949
|
-
|
|
1492
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
1493
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("thead", { className: "yable-thead", children: [
|
|
1494
|
+
headerGroups.map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsxRuntime.jsx(HeaderCell, { header, table }, header.id)) }, headerGroup.id)),
|
|
1495
|
+
floatingFilters && visibleColumns.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row yable-header-row--filters", children: visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(FloatingFilterCell, { column }, `${column.id}-filter`)) })
|
|
1496
|
+
] });
|
|
1497
|
+
}
|
|
1498
|
+
function FloatingFilterCell({
|
|
1499
|
+
column
|
|
1500
|
+
}) {
|
|
1501
|
+
const style = React3.useMemo(() => {
|
|
1502
|
+
const next = {
|
|
1503
|
+
width: column.getSize(),
|
|
1504
|
+
minWidth: column.columnDef.minSize,
|
|
1505
|
+
maxWidth: column.columnDef.maxSize,
|
|
1506
|
+
padding: 6,
|
|
1507
|
+
verticalAlign: "top"
|
|
1508
|
+
};
|
|
1509
|
+
const pinned = column.getIsPinned();
|
|
1510
|
+
if (pinned) {
|
|
1511
|
+
next.position = "sticky";
|
|
1512
|
+
if (pinned === "left") {
|
|
1513
|
+
next.left = column.getStart("left");
|
|
1514
|
+
} else {
|
|
1515
|
+
next.right = column.getStart("right");
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
return next;
|
|
1519
|
+
}, [column]);
|
|
1520
|
+
return /* @__PURE__ */ jsxRuntime.jsx("th", { className: "yable-th yable-th--filter", role: "columnheader", style, children: /* @__PURE__ */ jsxRuntime.jsx(FloatingFilter, { column }) });
|
|
950
1521
|
}
|
|
951
1522
|
function HeaderCell({
|
|
952
1523
|
header,
|
|
@@ -1000,11 +1571,6 @@ function HeaderCell({
|
|
|
1000
1571
|
const handleDragStart = React3.useCallback(
|
|
1001
1572
|
(e) => {
|
|
1002
1573
|
if (!canReorder) return;
|
|
1003
|
-
const target = e.target;
|
|
1004
|
-
if (target && target.closest(".yable-resize-handle")) {
|
|
1005
|
-
e.preventDefault();
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
1574
|
e.stopPropagation();
|
|
1009
1575
|
e.dataTransfer.effectAllowed = "move";
|
|
1010
1576
|
try {
|
|
@@ -1012,8 +1578,9 @@ function HeaderCell({
|
|
|
1012
1578
|
e.dataTransfer.setData("text/plain", column.id);
|
|
1013
1579
|
} catch {
|
|
1014
1580
|
}
|
|
1581
|
+
table.setColumnDragActive(true);
|
|
1015
1582
|
},
|
|
1016
|
-
[canReorder, column.id]
|
|
1583
|
+
[canReorder, column.id, table]
|
|
1017
1584
|
);
|
|
1018
1585
|
const handleDragOver = React3.useCallback(
|
|
1019
1586
|
(e) => {
|
|
@@ -1035,17 +1602,15 @@ function HeaderCell({
|
|
|
1035
1602
|
},
|
|
1036
1603
|
[canReorder]
|
|
1037
1604
|
);
|
|
1038
|
-
const handleDragLeave = React3.useCallback(
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (next && e.currentTarget.contains(next)) return;
|
|
1042
|
-
setDragOver(null);
|
|
1043
|
-
},
|
|
1044
|
-
[]
|
|
1045
|
-
);
|
|
1046
|
-
const handleDragEnd = React3.useCallback(() => {
|
|
1605
|
+
const handleDragLeave = React3.useCallback((e) => {
|
|
1606
|
+
const next = e.relatedTarget;
|
|
1607
|
+
if (next && e.currentTarget.contains(next)) return;
|
|
1047
1608
|
setDragOver(null);
|
|
1048
1609
|
}, []);
|
|
1610
|
+
const handleDragEnd = React3.useCallback(() => {
|
|
1611
|
+
setDragOver(null);
|
|
1612
|
+
table.setColumnDragActive(false);
|
|
1613
|
+
}, [table]);
|
|
1049
1614
|
const handleDrop = React3.useCallback(
|
|
1050
1615
|
(e) => {
|
|
1051
1616
|
if (!canReorder) return;
|
|
@@ -1055,6 +1620,7 @@ function HeaderCell({
|
|
|
1055
1620
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
1056
1621
|
const insertAfter = e.clientX >= rect.left + rect.width / 2;
|
|
1057
1622
|
setDragOver(null);
|
|
1623
|
+
table.setColumnDragActive(false);
|
|
1058
1624
|
if (!sourceId || sourceId === column.id) return;
|
|
1059
1625
|
const state = table.getState();
|
|
1060
1626
|
const allLeafs = table.getAllLeafColumns();
|
|
@@ -1105,24 +1671,24 @@ function HeaderCell({
|
|
|
1105
1671
|
"aria-sort": sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : canSort ? "none" : void 0,
|
|
1106
1672
|
role: "columnheader",
|
|
1107
1673
|
colSpan: header.colSpan,
|
|
1108
|
-
draggable: canReorder || void 0,
|
|
1109
1674
|
onClick: handleHeaderClick,
|
|
1110
|
-
onDragStart: canReorder ? handleDragStart : void 0,
|
|
1111
1675
|
onDragOver: canReorder ? handleDragOver : void 0,
|
|
1112
1676
|
onDragLeave: canReorder ? handleDragLeave : void 0,
|
|
1113
|
-
onDragEnd: canReorder ? handleDragEnd : void 0,
|
|
1114
1677
|
onDrop: canReorder ? handleDrop : void 0,
|
|
1115
1678
|
children: [
|
|
1116
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1679
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1680
|
+
"div",
|
|
1681
|
+
{
|
|
1682
|
+
className: "yable-th-content",
|
|
1683
|
+
draggable: canReorder || void 0,
|
|
1684
|
+
onDragStart: canReorder ? handleDragStart : void 0,
|
|
1685
|
+
onDragEnd: canReorder ? handleDragEnd : void 0,
|
|
1686
|
+
children: [
|
|
1687
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: headerContent }),
|
|
1688
|
+
canSort && /* @__PURE__ */ jsxRuntime.jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
|
|
1689
|
+
]
|
|
1690
|
+
}
|
|
1691
|
+
),
|
|
1126
1692
|
canResize && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1127
1693
|
"div",
|
|
1128
1694
|
{
|
|
@@ -1130,9 +1696,7 @@ function HeaderCell({
|
|
|
1130
1696
|
"data-resizing": column.getIsResizing() || void 0,
|
|
1131
1697
|
onMouseDown: startResize,
|
|
1132
1698
|
onTouchStart: startResize,
|
|
1133
|
-
onClick: handleResizeClick
|
|
1134
|
-
draggable: false,
|
|
1135
|
-
onDragStart: (e) => e.preventDefault()
|
|
1699
|
+
onClick: handleResizeClick
|
|
1136
1700
|
}
|
|
1137
1701
|
)
|
|
1138
1702
|
]
|
|
@@ -1246,6 +1810,10 @@ function TableCell({
|
|
|
1246
1810
|
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
1247
1811
|
const cellErrorMessage = table.getCellErrorMessage(cell.row.id, column.id);
|
|
1248
1812
|
const cellConflictWith = table.getCellConflictWith(cell.row.id, column.id);
|
|
1813
|
+
const selectionRange = table.getCellSelectionRange();
|
|
1814
|
+
const selectionEdges = table.getCellSelectionEdges(rowIndex, columnIndex);
|
|
1815
|
+
const isCellSelected = selectionEdges !== null;
|
|
1816
|
+
const isMultiCellSelection = selectionRange !== null && (selectionRange.start.rowIndex !== selectionRange.end.rowIndex || selectionRange.start.columnIndex !== selectionRange.end.columnIndex);
|
|
1249
1817
|
const overrideValue = cellStatus !== "idle" ? table.getCellRenderValue(cell.row.id, column.id) : void 0;
|
|
1250
1818
|
let content;
|
|
1251
1819
|
const cellDef = column.columnDef.cell;
|
|
@@ -1269,23 +1837,17 @@ function TableCell({
|
|
|
1269
1837
|
}
|
|
1270
1838
|
const handleClick = React3.useCallback(
|
|
1271
1839
|
(e) => {
|
|
1272
|
-
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1273
|
-
const clickTarget = e.target;
|
|
1274
|
-
if (!isInteractiveClickTarget(clickTarget)) {
|
|
1275
|
-
const currentTarget = e.currentTarget;
|
|
1276
|
-
currentTarget.focus({ preventScroll: true });
|
|
1277
|
-
}
|
|
1278
1840
|
table.events.emit("cell:click", {
|
|
1279
1841
|
cell,
|
|
1280
1842
|
row: cell.row,
|
|
1281
1843
|
column: cell.column,
|
|
1282
1844
|
event: e.nativeEvent
|
|
1283
1845
|
});
|
|
1284
|
-
if (yableCore.canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing) {
|
|
1846
|
+
if (yableCore.canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing && !isMultiCellSelection && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
1285
1847
|
table.startEditing(cell.row.id, column.id);
|
|
1286
1848
|
}
|
|
1287
1849
|
},
|
|
1288
|
-
[cell, column,
|
|
1850
|
+
[cell, column, isAlwaysEditable, isEditing, isMultiCellSelection, table]
|
|
1289
1851
|
);
|
|
1290
1852
|
const handleDoubleClick = React3.useCallback(
|
|
1291
1853
|
(e) => {
|
|
@@ -1313,15 +1875,46 @@ function TableCell({
|
|
|
1313
1875
|
if (!keyboardNavigationEnabled) return;
|
|
1314
1876
|
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1315
1877
|
}, [columnIndex, keyboardNavigationEnabled, rowIndex, table]);
|
|
1878
|
+
const handleMouseDown = React3.useCallback(
|
|
1879
|
+
(e) => {
|
|
1880
|
+
if (e.button !== 0) return;
|
|
1881
|
+
const clickTarget = e.target;
|
|
1882
|
+
if (isInteractiveClickTarget(clickTarget)) return;
|
|
1883
|
+
e.preventDefault();
|
|
1884
|
+
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1885
|
+
table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
|
|
1886
|
+
e.currentTarget.focus({ preventScroll: true });
|
|
1887
|
+
},
|
|
1888
|
+
[columnIndex, rowIndex, table]
|
|
1889
|
+
);
|
|
1890
|
+
const handleMouseEnter = React3.useCallback(() => {
|
|
1891
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1892
|
+
table.updateCellRangeSelection({ rowIndex, columnIndex });
|
|
1893
|
+
}, [columnIndex, rowIndex, table]);
|
|
1894
|
+
const handleMouseUp = React3.useCallback(() => {
|
|
1895
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1896
|
+
table.endCellRangeSelection();
|
|
1897
|
+
}, [table]);
|
|
1898
|
+
const cellClassNameDef = column.columnDef.cellClassName;
|
|
1899
|
+
const userClassName = typeof cellClassNameDef === "function" ? cellClassNameDef(cell.getContext()) : cellClassNameDef;
|
|
1900
|
+
const cellStyleDef = column.columnDef.cellStyle;
|
|
1901
|
+
const userStyle = typeof cellStyleDef === "function" ? cellStyleDef(cell.getContext()) : cellStyleDef;
|
|
1902
|
+
const mergedStyle = userStyle ? { ...style, ...userStyle } : style;
|
|
1316
1903
|
const classNames = [
|
|
1317
1904
|
"yable-td",
|
|
1318
|
-
isFocused && "yable-cell--focused"
|
|
1905
|
+
isFocused && "yable-cell--focused",
|
|
1906
|
+
isCellSelected && "yable-cell--selected",
|
|
1907
|
+
selectionEdges?.top && "yable-cell--selection-top",
|
|
1908
|
+
selectionEdges?.right && "yable-cell--selection-right",
|
|
1909
|
+
selectionEdges?.bottom && "yable-cell--selection-bottom",
|
|
1910
|
+
selectionEdges?.left && "yable-cell--selection-left",
|
|
1911
|
+
userClassName
|
|
1319
1912
|
].filter(Boolean).join(" ");
|
|
1320
1913
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1321
1914
|
"td",
|
|
1322
1915
|
{
|
|
1323
1916
|
className: classNames,
|
|
1324
|
-
style,
|
|
1917
|
+
style: mergedStyle,
|
|
1325
1918
|
"data-editing": isEditing || void 0,
|
|
1326
1919
|
"data-focused": isFocused || void 0,
|
|
1327
1920
|
"data-pinned": pinned || void 0,
|
|
@@ -1329,10 +1922,14 @@ function TableCell({
|
|
|
1329
1922
|
"data-column-id": column.id,
|
|
1330
1923
|
"data-row-index": rowIndex,
|
|
1331
1924
|
"data-column-index": columnIndex,
|
|
1925
|
+
"data-cell-selected": isCellSelected || void 0,
|
|
1332
1926
|
"aria-rowindex": rowIndex + 1,
|
|
1333
1927
|
"aria-colindex": columnIndex + 1,
|
|
1334
1928
|
role: "gridcell",
|
|
1335
1929
|
tabIndex: keyboardNavigationEnabled ? isTabStop ? 0 : -1 : void 0,
|
|
1930
|
+
onMouseDown: handleMouseDown,
|
|
1931
|
+
onMouseEnter: handleMouseEnter,
|
|
1932
|
+
onMouseUp: handleMouseUp,
|
|
1336
1933
|
onClick: handleClick,
|
|
1337
1934
|
onDoubleClick: handleDoubleClick,
|
|
1338
1935
|
onContextMenu: handleContextMenu,
|
|
@@ -1459,12 +2056,17 @@ var CellErrorBoundary = class extends React3__default.default.Component {
|
|
|
1459
2056
|
};
|
|
1460
2057
|
function TableBody({
|
|
1461
2058
|
table,
|
|
1462
|
-
clickableRows
|
|
2059
|
+
clickableRows,
|
|
2060
|
+
colgroup
|
|
1463
2061
|
}) {
|
|
1464
2062
|
const rows = table.getRowModel().rows;
|
|
1465
2063
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1466
2064
|
const activeCell = table.getState().editing.activeCell;
|
|
1467
2065
|
const focusedCell = table.getFocusedCell();
|
|
2066
|
+
const cellSelection = table.getState().cellSelection ?? {
|
|
2067
|
+
range: null,
|
|
2068
|
+
isDragging: false
|
|
2069
|
+
};
|
|
1468
2070
|
const options = table.options;
|
|
1469
2071
|
const enableVirtualization = options.enableVirtualization ?? false;
|
|
1470
2072
|
const scrollContainerRef = React3.useRef(null);
|
|
@@ -1473,6 +2075,19 @@ function TableBody({
|
|
|
1473
2075
|
const estimateRowHeight = options.estimateRowHeight;
|
|
1474
2076
|
const pretextHeights = options.pretextHeights ?? null;
|
|
1475
2077
|
const pretextPrefixSums = options.pretextPrefixSums ?? null;
|
|
2078
|
+
const columnSizing = table.getState().columnSizing;
|
|
2079
|
+
const columnSizingHash = React3.useMemo(() => {
|
|
2080
|
+
const entries = Object.entries(columnSizing);
|
|
2081
|
+
if (entries.length === 0) return 0;
|
|
2082
|
+
let h = 0;
|
|
2083
|
+
for (const [key, value] of entries) {
|
|
2084
|
+
for (let i = 0; i < key.length; i++) {
|
|
2085
|
+
h = h * 31 + key.charCodeAt(i) | 0;
|
|
2086
|
+
}
|
|
2087
|
+
h = h * 31 + (value | 0) | 0;
|
|
2088
|
+
}
|
|
2089
|
+
return h;
|
|
2090
|
+
}, [columnSizing]);
|
|
1476
2091
|
const { virtualRows, totalHeight } = useVirtualization({
|
|
1477
2092
|
containerRef: scrollContainerRef,
|
|
1478
2093
|
totalRows: rows.length,
|
|
@@ -1480,8 +2095,21 @@ function TableBody({
|
|
|
1480
2095
|
overscan,
|
|
1481
2096
|
estimateRowHeight,
|
|
1482
2097
|
pretextHeights,
|
|
1483
|
-
pretextPrefixSums
|
|
2098
|
+
pretextPrefixSums,
|
|
2099
|
+
columnSizingHash
|
|
1484
2100
|
});
|
|
2101
|
+
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"}`;
|
|
2102
|
+
React3.useEffect(() => {
|
|
2103
|
+
const handleWindowMouseUp = () => {
|
|
2104
|
+
if (table.getState().cellSelection?.isDragging) {
|
|
2105
|
+
table.endCellRangeSelection();
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
window.addEventListener("mouseup", handleWindowMouseUp);
|
|
2109
|
+
return () => {
|
|
2110
|
+
window.removeEventListener("mouseup", handleWindowMouseUp);
|
|
2111
|
+
};
|
|
2112
|
+
}, [table]);
|
|
1485
2113
|
if (!enableVirtualization) {
|
|
1486
2114
|
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1487
2115
|
MemoizedTableRow,
|
|
@@ -1495,6 +2123,7 @@ function TableBody({
|
|
|
1495
2123
|
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1496
2124
|
focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
|
|
1497
2125
|
hasFocusedCell: focusedCell !== null,
|
|
2126
|
+
cellSelectionKey,
|
|
1498
2127
|
clickable: clickableRows
|
|
1499
2128
|
},
|
|
1500
2129
|
row.id
|
|
@@ -1503,73 +2132,70 @@ function TableBody({
|
|
|
1503
2132
|
const hasPretextData = !!(pretextHeights && pretextPrefixSums);
|
|
1504
2133
|
const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
|
|
1505
2134
|
const containerHeight = hasPretextData ? Math.min(totalHeight, 800) : fixedRowHeight ? Math.min(totalHeight, fixedRowHeight * 20) : 600;
|
|
1506
|
-
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { style: { height: 0, padding: 0, border: "none" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1507
|
-
"
|
|
2135
|
+
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { style: { height: 0, padding: 0, border: "none" }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: 0, padding: 0, border: "none" }, colSpan: visibleColumns.length, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2136
|
+
"div",
|
|
1508
2137
|
{
|
|
1509
|
-
|
|
1510
|
-
|
|
2138
|
+
ref: scrollContainerRef,
|
|
2139
|
+
className: "yable-virtual-scroll-container",
|
|
2140
|
+
style: {
|
|
2141
|
+
overflowY: "auto",
|
|
2142
|
+
height: containerHeight,
|
|
2143
|
+
position: "relative"
|
|
2144
|
+
},
|
|
1511
2145
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1512
2146
|
"div",
|
|
1513
2147
|
{
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
height: containerHeight,
|
|
1519
|
-
position: "relative"
|
|
1520
|
-
},
|
|
1521
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1522
|
-
"div",
|
|
2148
|
+
className: "yable-virtual-spacer",
|
|
2149
|
+
style: { height: totalHeight, position: "relative" },
|
|
2150
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2151
|
+
"table",
|
|
1523
2152
|
{
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
}) })
|
|
1565
|
-
}
|
|
1566
|
-
)
|
|
2153
|
+
style: {
|
|
2154
|
+
position: "absolute",
|
|
2155
|
+
top: 0,
|
|
2156
|
+
left: 0,
|
|
2157
|
+
width: "100%",
|
|
2158
|
+
tableLayout: "fixed",
|
|
2159
|
+
borderCollapse: "collapse"
|
|
2160
|
+
},
|
|
2161
|
+
children: [
|
|
2162
|
+
colgroup,
|
|
2163
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: virtualRows.map((vRow) => {
|
|
2164
|
+
const row = rows[vRow.index];
|
|
2165
|
+
if (!row) return null;
|
|
2166
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2167
|
+
MemoizedTableRow,
|
|
2168
|
+
{
|
|
2169
|
+
row,
|
|
2170
|
+
table,
|
|
2171
|
+
rowIndex: vRow.index,
|
|
2172
|
+
visibleColumns,
|
|
2173
|
+
isSelected: row.getIsSelected(),
|
|
2174
|
+
isExpanded: row.getIsExpanded(),
|
|
2175
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
2176
|
+
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
2177
|
+
hasFocusedCell: focusedCell !== null,
|
|
2178
|
+
cellSelectionKey,
|
|
2179
|
+
clickable: clickableRows,
|
|
2180
|
+
virtualStyle: {
|
|
2181
|
+
position: "absolute",
|
|
2182
|
+
top: 0,
|
|
2183
|
+
left: 0,
|
|
2184
|
+
width: "100%",
|
|
2185
|
+
height: vRow.size,
|
|
2186
|
+
transform: `translateY(${vRow.start}px)`
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
row.id
|
|
2190
|
+
);
|
|
2191
|
+
}) })
|
|
2192
|
+
]
|
|
1567
2193
|
}
|
|
1568
2194
|
)
|
|
1569
2195
|
}
|
|
1570
2196
|
)
|
|
1571
2197
|
}
|
|
1572
|
-
) }) });
|
|
2198
|
+
) }) }) });
|
|
1573
2199
|
}
|
|
1574
2200
|
function TableRowInner({
|
|
1575
2201
|
row,
|
|
@@ -1581,10 +2207,12 @@ function TableRowInner({
|
|
|
1581
2207
|
activeColumnId,
|
|
1582
2208
|
focusedColumnIndex,
|
|
1583
2209
|
hasFocusedCell,
|
|
2210
|
+
cellSelectionKey: _cellSelectionKey,
|
|
1584
2211
|
clickable,
|
|
1585
2212
|
virtualStyle
|
|
1586
2213
|
}) {
|
|
1587
|
-
const
|
|
2214
|
+
const allCells = row.getAllCells();
|
|
2215
|
+
const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
|
|
1588
2216
|
const handleClick = React3.useCallback(
|
|
1589
2217
|
(e) => {
|
|
1590
2218
|
if (clickable) {
|
|
@@ -1614,6 +2242,8 @@ function TableRowInner({
|
|
|
1614
2242
|
},
|
|
1615
2243
|
[table.events, row]
|
|
1616
2244
|
);
|
|
2245
|
+
const selectionEnabled = Boolean(table.options.enableRowSelection);
|
|
2246
|
+
const expansionEnabled = Boolean(table.options.enableExpanding);
|
|
1617
2247
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1618
2248
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1619
2249
|
"tr",
|
|
@@ -1625,6 +2255,8 @@ function TableRowInner({
|
|
|
1625
2255
|
"data-clickable": clickable || void 0,
|
|
1626
2256
|
"data-row-id": row.id,
|
|
1627
2257
|
"data-row-index": rowIndex,
|
|
2258
|
+
"aria-selected": selectionEnabled ? isSelected : void 0,
|
|
2259
|
+
"aria-expanded": expansionEnabled ? isExpanded : void 0,
|
|
1628
2260
|
onClick: handleClick,
|
|
1629
2261
|
onDoubleClick: handleDoubleClick,
|
|
1630
2262
|
onContextMenu: handleContextMenu,
|
|
@@ -1666,6 +2298,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1666
2298
|
if (prev.activeColumnId !== next.activeColumnId) return false;
|
|
1667
2299
|
if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
|
|
1668
2300
|
if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
|
|
2301
|
+
if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
|
|
1669
2302
|
if (prev.virtualStyle !== next.virtualStyle) {
|
|
1670
2303
|
if (!prev.virtualStyle || !next.virtualStyle) return false;
|
|
1671
2304
|
if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
|
|
@@ -1675,9 +2308,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1675
2308
|
return true;
|
|
1676
2309
|
}
|
|
1677
2310
|
var MemoizedTableRow = React3__default.default.memo(TableRowInner, areRowPropsEqual);
|
|
1678
|
-
function TableFooter({
|
|
1679
|
-
table
|
|
1680
|
-
}) {
|
|
2311
|
+
function TableFooter({ table }) {
|
|
1681
2312
|
const footerGroups = table.getFooterGroups();
|
|
1682
2313
|
if (!footerGroups.length) return null;
|
|
1683
2314
|
return /* @__PURE__ */ jsxRuntime.jsx("tfoot", { className: "yable-tfoot", children: footerGroups.map((footerGroup) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-tr", children: footerGroup.headers.map((header) => {
|
|
@@ -2440,11 +3071,11 @@ function ContextMenu({
|
|
|
2440
3071
|
}
|
|
2441
3072
|
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
2442
3073
|
e.preventDefault();
|
|
2443
|
-
const items2 = menuRef.current?.querySelectorAll(
|
|
2444
|
-
|
|
2445
|
-
const currentIndex = Array.from(items2).findIndex(
|
|
2446
|
-
(el) => el === document.activeElement
|
|
3074
|
+
const items2 = menuRef.current?.querySelectorAll(
|
|
3075
|
+
'[role="menuitem"]:not([aria-disabled="true"])'
|
|
2447
3076
|
);
|
|
3077
|
+
if (!items2 || items2.length === 0) return;
|
|
3078
|
+
const currentIndex = Array.from(items2).findIndex((el) => el === document.activeElement);
|
|
2448
3079
|
let nextIndex;
|
|
2449
3080
|
if (e.key === "ArrowDown") {
|
|
2450
3081
|
nextIndex = currentIndex < items2.length - 1 ? currentIndex + 1 : 0;
|
|
@@ -2489,11 +3120,7 @@ function ContextMenu({
|
|
|
2489
3120
|
navigator.clipboard?.readText().then((text) => {
|
|
2490
3121
|
const editing = table.getState().editing;
|
|
2491
3122
|
if (editing?.activeCell) {
|
|
2492
|
-
table.pasteFromClipboard(
|
|
2493
|
-
text,
|
|
2494
|
-
editing.activeCell.rowId,
|
|
2495
|
-
editing.activeCell.columnId
|
|
2496
|
-
);
|
|
3123
|
+
table.pasteFromClipboard(text, editing.activeCell.rowId, editing.activeCell.columnId);
|
|
2497
3124
|
}
|
|
2498
3125
|
}).catch(() => {
|
|
2499
3126
|
});
|
|
@@ -2833,13 +3460,19 @@ function isEditableTarget(element) {
|
|
|
2833
3460
|
}
|
|
2834
3461
|
return element.isContentEditable;
|
|
2835
3462
|
}
|
|
3463
|
+
function filterHeaderGroups(groups, visibleColumnIds) {
|
|
3464
|
+
return groups.map((group) => ({
|
|
3465
|
+
...group,
|
|
3466
|
+
headers: group.headers.filter((header) => visibleColumnIds.has(header.column.id))
|
|
3467
|
+
})).filter((group) => group.headers.length > 0);
|
|
3468
|
+
}
|
|
2836
3469
|
function Table({
|
|
2837
3470
|
table,
|
|
2838
|
-
stickyHeader,
|
|
2839
|
-
striped,
|
|
2840
|
-
bordered,
|
|
2841
|
-
compact,
|
|
2842
|
-
theme,
|
|
3471
|
+
stickyHeader: stickyHeaderProp,
|
|
3472
|
+
striped: stripedProp,
|
|
3473
|
+
bordered: borderedProp,
|
|
3474
|
+
compact: compactProp,
|
|
3475
|
+
theme: themeProp,
|
|
2843
3476
|
clickableRows,
|
|
2844
3477
|
footer,
|
|
2845
3478
|
loading,
|
|
@@ -2853,19 +3486,32 @@ function Table({
|
|
|
2853
3486
|
renderLoading,
|
|
2854
3487
|
children,
|
|
2855
3488
|
className,
|
|
2856
|
-
direction,
|
|
3489
|
+
direction: directionProp,
|
|
2857
3490
|
statusBar,
|
|
2858
3491
|
statusBarPanels,
|
|
2859
3492
|
sidebar,
|
|
2860
3493
|
sidebarPanels = ["columns", "filters"],
|
|
2861
3494
|
defaultSidebarPanel,
|
|
3495
|
+
floatingFilters,
|
|
3496
|
+
columnVirtualization,
|
|
3497
|
+
columnVirtualizationOverscan,
|
|
3498
|
+
ariaLabel: ariaLabelProp,
|
|
2862
3499
|
...rest
|
|
2863
3500
|
}) {
|
|
3501
|
+
const { tableProps: providerTableProps } = useYableDefaults();
|
|
3502
|
+
const stickyHeader = stickyHeaderProp ?? providerTableProps?.stickyHeader;
|
|
3503
|
+
const striped = stripedProp ?? providerTableProps?.striped;
|
|
3504
|
+
const bordered = borderedProp ?? providerTableProps?.bordered;
|
|
3505
|
+
const compact = compactProp ?? providerTableProps?.compact;
|
|
3506
|
+
const theme = themeProp ?? providerTableProps?.theme;
|
|
3507
|
+
const direction = directionProp ?? providerTableProps?.direction;
|
|
3508
|
+
const ariaLabel = ariaLabelProp ?? providerTableProps?.ariaLabel;
|
|
2864
3509
|
const [sidebarOpen, setSidebarOpen] = React3.useState(false);
|
|
2865
3510
|
const [sidebarPanel, setSidebarPanel] = React3.useState(
|
|
2866
3511
|
defaultSidebarPanel ?? "columns"
|
|
2867
3512
|
);
|
|
2868
3513
|
const containerRef = React3.useRef(null);
|
|
3514
|
+
const horizontalScrollRef = React3.useRef(null);
|
|
2869
3515
|
const isRtl = direction === "rtl";
|
|
2870
3516
|
const classNames = [
|
|
2871
3517
|
"yable",
|
|
@@ -2883,8 +3529,86 @@ function Table({
|
|
|
2883
3529
|
const hasGlobalFilter = Boolean(table.getState().globalFilter);
|
|
2884
3530
|
const hasColumnFilters = table.getState().columnFilters.length > 0;
|
|
2885
3531
|
const isFiltered = hasGlobalFilter || hasColumnFilters;
|
|
3532
|
+
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
3533
|
+
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
3534
|
+
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
3535
|
+
const canVirtualizeColumns = Boolean(columnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
3536
|
+
const columnVirtualState = useColumnVirtualization({
|
|
3537
|
+
containerRef: horizontalScrollRef,
|
|
3538
|
+
columns: allVisibleColumns,
|
|
3539
|
+
overscan: columnVirtualizationOverscan ?? 2,
|
|
3540
|
+
enabled: canVirtualizeColumns
|
|
3541
|
+
});
|
|
3542
|
+
const renderTable = React3.useMemo(() => {
|
|
3543
|
+
if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
|
|
3544
|
+
return table;
|
|
3545
|
+
}
|
|
3546
|
+
const virtualColumns = columnVirtualState.virtualColumns.map((entry) => entry.column);
|
|
3547
|
+
const visibleColumnIds = new Set(virtualColumns.map((column) => column.id));
|
|
3548
|
+
const next = Object.create(table);
|
|
3549
|
+
next.getVisibleFlatColumns = () => virtualColumns;
|
|
3550
|
+
next.getVisibleLeafColumns = () => virtualColumns;
|
|
3551
|
+
next.getCenterVisibleLeafColumns = () => virtualColumns;
|
|
3552
|
+
next.getLeftVisibleLeafColumns = () => [];
|
|
3553
|
+
next.getRightVisibleLeafColumns = () => [];
|
|
3554
|
+
next.getHeaderGroups = () => filterHeaderGroups(table.getHeaderGroups(), visibleColumnIds);
|
|
3555
|
+
next.getCenterHeaderGroups = () => filterHeaderGroups(table.getCenterHeaderGroups(), visibleColumnIds);
|
|
3556
|
+
next.getFooterGroups = () => filterHeaderGroups(table.getFooterGroups(), visibleColumnIds);
|
|
3557
|
+
next.getCenterFooterGroups = () => filterHeaderGroups(table.getCenterFooterGroups(), visibleColumnIds);
|
|
3558
|
+
return next;
|
|
3559
|
+
}, [
|
|
3560
|
+
canVirtualizeColumns,
|
|
3561
|
+
columnVirtualState.isVirtualized,
|
|
3562
|
+
columnVirtualState.virtualColumns,
|
|
3563
|
+
table
|
|
3564
|
+
]);
|
|
3565
|
+
const showColumnVirtualizationShell = canVirtualizeColumns;
|
|
2886
3566
|
const contextMenu = useContextMenu();
|
|
2887
3567
|
useKeyboardNavigation(table, { containerRef });
|
|
3568
|
+
const [announcement, setAnnouncement] = React3.useState("");
|
|
3569
|
+
const prevSortingRef = React3.useRef(table.getState().sorting);
|
|
3570
|
+
const prevFilterCountRef = React3.useRef(rows.length);
|
|
3571
|
+
const prevHasFiltersRef = React3.useRef(isFiltered);
|
|
3572
|
+
const prevPaginationRef = React3.useRef(table.getState().pagination);
|
|
3573
|
+
const isFirstRenderRef = React3.useRef(true);
|
|
3574
|
+
React3.useEffect(() => {
|
|
3575
|
+
if (isFirstRenderRef.current) {
|
|
3576
|
+
isFirstRenderRef.current = false;
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
const currentSorting = table.getState().sorting;
|
|
3580
|
+
const currentPagination = table.getState().pagination;
|
|
3581
|
+
const currentRowCount = rows.length;
|
|
3582
|
+
const currentIsFiltered = isFiltered;
|
|
3583
|
+
if (JSON.stringify(currentSorting) !== JSON.stringify(prevSortingRef.current)) {
|
|
3584
|
+
prevSortingRef.current = currentSorting;
|
|
3585
|
+
const firstSort = currentSorting[0];
|
|
3586
|
+
if (firstSort) {
|
|
3587
|
+
const column = table.getColumn(firstSort.id);
|
|
3588
|
+
const headerDef = column?.columnDef.header;
|
|
3589
|
+
const columnName = typeof headerDef === "string" ? headerDef : firstSort.id;
|
|
3590
|
+
const direction2 = firstSort.desc ? "descending" : "ascending";
|
|
3591
|
+
setAnnouncement(`Sorted by ${columnName} ${direction2}`);
|
|
3592
|
+
return;
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
if (currentRowCount !== prevFilterCountRef.current || currentIsFiltered !== prevHasFiltersRef.current) {
|
|
3596
|
+
prevFilterCountRef.current = currentRowCount;
|
|
3597
|
+
prevHasFiltersRef.current = currentIsFiltered;
|
|
3598
|
+
if (currentIsFiltered) {
|
|
3599
|
+
setAnnouncement(`${currentRowCount} rows after filtering`);
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
if (JSON.stringify(currentPagination) !== JSON.stringify(prevPaginationRef.current)) {
|
|
3604
|
+
prevPaginationRef.current = currentPagination;
|
|
3605
|
+
const pageCount = table.getPageCount();
|
|
3606
|
+
if (pageCount > 0) {
|
|
3607
|
+
setAnnouncement(`Page ${currentPagination.pageIndex + 1} of ${pageCount}`);
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
});
|
|
2888
3612
|
const handleContextMenu = React3.useCallback(
|
|
2889
3613
|
(e) => {
|
|
2890
3614
|
e.preventDefault();
|
|
@@ -2892,6 +3616,46 @@ function Table({
|
|
|
2892
3616
|
},
|
|
2893
3617
|
[contextMenu, table]
|
|
2894
3618
|
);
|
|
3619
|
+
const enableRowVirtualization = renderTable.options.enableVirtualization ?? false;
|
|
3620
|
+
const visibleLeafColumns = renderTable.getVisibleLeafColumns();
|
|
3621
|
+
const columnSizing = renderTable.getState().columnSizing;
|
|
3622
|
+
const colgroup = React3.useMemo(() => {
|
|
3623
|
+
if (visibleLeafColumns.length === 0) return null;
|
|
3624
|
+
return /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: visibleLeafColumns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: col.getSize() } }, col.id)) });
|
|
3625
|
+
}, [visibleLeafColumns, columnSizing]);
|
|
3626
|
+
const outerTableStyle = React3.useMemo(() => {
|
|
3627
|
+
if (columnVirtualState.isVirtualized) {
|
|
3628
|
+
return {
|
|
3629
|
+
width: columnVirtualState.visibleWidth,
|
|
3630
|
+
minWidth: columnVirtualState.visibleWidth,
|
|
3631
|
+
marginLeft: columnVirtualState.startOffset,
|
|
3632
|
+
tableLayout: "fixed"
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
if (enableRowVirtualization) {
|
|
3636
|
+
return { tableLayout: "fixed" };
|
|
3637
|
+
}
|
|
3638
|
+
return void 0;
|
|
3639
|
+
}, [
|
|
3640
|
+
columnVirtualState.isVirtualized,
|
|
3641
|
+
columnVirtualState.visibleWidth,
|
|
3642
|
+
columnVirtualState.startOffset,
|
|
3643
|
+
enableRowVirtualization
|
|
3644
|
+
]);
|
|
3645
|
+
const tableNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3646
|
+
"table",
|
|
3647
|
+
{
|
|
3648
|
+
className: "yable-table",
|
|
3649
|
+
style: outerTableStyle,
|
|
3650
|
+
"data-column-virtualized": columnVirtualState.isVirtualized || void 0,
|
|
3651
|
+
children: [
|
|
3652
|
+
enableRowVirtualization && colgroup,
|
|
3653
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHeader, { table: renderTable, floatingFilters }),
|
|
3654
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableBody, { table: renderTable, clickableRows, colgroup }),
|
|
3655
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx(TableFooter, { table: renderTable })
|
|
3656
|
+
]
|
|
3657
|
+
}
|
|
3658
|
+
);
|
|
2895
3659
|
return /* @__PURE__ */ jsxRuntime.jsx(TableProvider, { value: table, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2896
3660
|
"div",
|
|
2897
3661
|
{
|
|
@@ -2900,23 +3664,40 @@ function Table({
|
|
|
2900
3664
|
"data-theme": theme,
|
|
2901
3665
|
dir: direction,
|
|
2902
3666
|
role: "grid",
|
|
3667
|
+
"aria-label": ariaLabel ?? "Data table",
|
|
2903
3668
|
"aria-rowcount": table.getRowModel().rows.length,
|
|
2904
3669
|
"aria-colcount": table.getVisibleLeafColumns().length,
|
|
2905
3670
|
onContextMenu: handleContextMenu,
|
|
2906
3671
|
...rest,
|
|
2907
3672
|
children: [
|
|
2908
3673
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "yable-main", children: [
|
|
2909
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
3674
|
+
showColumnVirtualizationShell ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3675
|
+
"div",
|
|
3676
|
+
{
|
|
3677
|
+
ref: horizontalScrollRef,
|
|
3678
|
+
className: "yable-horizontal-scroll-container",
|
|
3679
|
+
style: {
|
|
3680
|
+
overflowX: "auto",
|
|
3681
|
+
overflowY: "visible",
|
|
3682
|
+
maxWidth: "100%",
|
|
3683
|
+
position: "relative"
|
|
3684
|
+
},
|
|
3685
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3686
|
+
"div",
|
|
3687
|
+
{
|
|
3688
|
+
className: "yable-horizontal-scroll-inner",
|
|
3689
|
+
style: {
|
|
3690
|
+
width: Math.max(columnVirtualState.totalWidth, columnVirtualState.visibleWidth),
|
|
3691
|
+
minWidth: Math.max(
|
|
3692
|
+
columnVirtualState.totalWidth,
|
|
3693
|
+
columnVirtualState.visibleWidth
|
|
3694
|
+
)
|
|
3695
|
+
},
|
|
3696
|
+
children: tableNode
|
|
3697
|
+
}
|
|
3698
|
+
)
|
|
3699
|
+
}
|
|
3700
|
+
) : tableNode,
|
|
2920
3701
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2921
3702
|
LoadingOverlay,
|
|
2922
3703
|
{
|
|
@@ -2957,6 +3738,24 @@ function Table({
|
|
|
2957
3738
|
onClose: contextMenu.close,
|
|
2958
3739
|
table
|
|
2959
3740
|
}
|
|
3741
|
+
),
|
|
3742
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3743
|
+
"div",
|
|
3744
|
+
{
|
|
3745
|
+
role: "status",
|
|
3746
|
+
"aria-live": "polite",
|
|
3747
|
+
"aria-atomic": "true",
|
|
3748
|
+
style: {
|
|
3749
|
+
position: "absolute",
|
|
3750
|
+
width: "1px",
|
|
3751
|
+
height: "1px",
|
|
3752
|
+
overflow: "hidden",
|
|
3753
|
+
clip: "rect(0,0,0,0)",
|
|
3754
|
+
whiteSpace: "nowrap",
|
|
3755
|
+
border: 0
|
|
3756
|
+
},
|
|
3757
|
+
children: announcement
|
|
3758
|
+
}
|
|
2960
3759
|
)
|
|
2961
3760
|
]
|
|
2962
3761
|
}
|
|
@@ -3422,14 +4221,7 @@ function formatDateValue(value, type) {
|
|
|
3422
4221
|
return String(value);
|
|
3423
4222
|
}
|
|
3424
4223
|
function useClipboard(table, options = {}) {
|
|
3425
|
-
const {
|
|
3426
|
-
enabled = true,
|
|
3427
|
-
containerRef,
|
|
3428
|
-
onCopy,
|
|
3429
|
-
onCut,
|
|
3430
|
-
onPaste,
|
|
3431
|
-
...clipboardOptions
|
|
3432
|
-
} = options;
|
|
4224
|
+
const { enabled = true, containerRef, onCopy, onCut, onPaste, ...clipboardOptions } = options;
|
|
3433
4225
|
const handleCopy = React3.useCallback(
|
|
3434
4226
|
(e) => {
|
|
3435
4227
|
if (isEditableTarget2(e.target)) return;
|
|
@@ -3467,20 +4259,29 @@ function useClipboard(table, options = {}) {
|
|
|
3467
4259
|
targetRowId = state.editing.activeCell.rowId;
|
|
3468
4260
|
targetColumnId = state.editing.activeCell.columnId;
|
|
3469
4261
|
} else {
|
|
3470
|
-
const
|
|
3471
|
-
|
|
3472
|
-
);
|
|
3473
|
-
if (
|
|
3474
|
-
|
|
4262
|
+
const selectedRange = table.getCellSelectionRange();
|
|
4263
|
+
const rows = table.getRowModel().rows;
|
|
4264
|
+
const columns = table.getVisibleLeafColumns();
|
|
4265
|
+
if (selectedRange) {
|
|
4266
|
+
const startRowIndex = Math.min(selectedRange.start.rowIndex, selectedRange.end.rowIndex);
|
|
4267
|
+
const startColumnIndex = Math.min(
|
|
4268
|
+
selectedRange.start.columnIndex,
|
|
4269
|
+
selectedRange.end.columnIndex
|
|
4270
|
+
);
|
|
4271
|
+
targetRowId = rows[startRowIndex]?.id;
|
|
4272
|
+
targetColumnId = columns[startColumnIndex]?.id;
|
|
3475
4273
|
} else {
|
|
3476
|
-
const
|
|
3477
|
-
|
|
4274
|
+
const selectedRowIds = Object.keys(state.rowSelection || {}).filter(
|
|
4275
|
+
(id) => state.rowSelection[id]
|
|
4276
|
+
);
|
|
4277
|
+
if (selectedRowIds.length > 0) {
|
|
4278
|
+
targetRowId = selectedRowIds[0];
|
|
4279
|
+
} else if (rows.length > 0) {
|
|
3478
4280
|
targetRowId = rows[0].id;
|
|
3479
4281
|
}
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
targetColumnId = columns[0].id;
|
|
4282
|
+
if (columns.length > 0) {
|
|
4283
|
+
targetColumnId = columns[0].id;
|
|
4284
|
+
}
|
|
3484
4285
|
}
|
|
3485
4286
|
}
|
|
3486
4287
|
if (targetRowId && targetColumnId) {
|
|
@@ -4770,7 +5571,7 @@ function sanitizeCSS(css) {
|
|
|
4770
5571
|
sanitized = sanitized.replace(/javascript\s*:/gi, "/* javascript: removed */");
|
|
4771
5572
|
return sanitized;
|
|
4772
5573
|
}
|
|
4773
|
-
function usePrintLayout(
|
|
5574
|
+
function usePrintLayout(_table, options = {}) {
|
|
4774
5575
|
const { title, additionalCSS } = options;
|
|
4775
5576
|
const isPrintingRef = React3.useRef(false);
|
|
4776
5577
|
const preparePrint = React3.useCallback(() => {
|
|
@@ -4807,7 +5608,7 @@ function usePrintLayout(table, options = {}) {
|
|
|
4807
5608
|
requestAnimationFrame(() => {
|
|
4808
5609
|
window.print();
|
|
4809
5610
|
});
|
|
4810
|
-
}, [
|
|
5611
|
+
}, [title, additionalCSS]);
|
|
4811
5612
|
return {
|
|
4812
5613
|
preparePrint,
|
|
4813
5614
|
isPrinting: isPrintingRef.current
|
|
@@ -4858,6 +5659,233 @@ function useTheme(options = {}) {
|
|
|
4858
5659
|
containerRef
|
|
4859
5660
|
};
|
|
4860
5661
|
}
|
|
5662
|
+
function selectColumn(options = {}) {
|
|
5663
|
+
const { id = "_select", size = 40, headerAriaLabel = "Select all rows" } = options;
|
|
5664
|
+
return {
|
|
5665
|
+
id,
|
|
5666
|
+
header: ({ table }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5667
|
+
"input",
|
|
5668
|
+
{
|
|
5669
|
+
type: "checkbox",
|
|
5670
|
+
checked: table.getIsAllPageRowsSelected(),
|
|
5671
|
+
ref: (el) => {
|
|
5672
|
+
if (el)
|
|
5673
|
+
el.indeterminate = table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected();
|
|
5674
|
+
},
|
|
5675
|
+
onChange: () => table.toggleAllPageRowsSelected(),
|
|
5676
|
+
"aria-label": headerAriaLabel
|
|
5677
|
+
}
|
|
5678
|
+
),
|
|
5679
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5680
|
+
"input",
|
|
5681
|
+
{
|
|
5682
|
+
type: "checkbox",
|
|
5683
|
+
checked: row.getIsSelected(),
|
|
5684
|
+
disabled: !row.getCanSelect(),
|
|
5685
|
+
onChange: row.getToggleSelectedHandler(),
|
|
5686
|
+
"aria-label": `Select row`
|
|
5687
|
+
}
|
|
5688
|
+
),
|
|
5689
|
+
size,
|
|
5690
|
+
enableSorting: false,
|
|
5691
|
+
enableColumnFilter: false,
|
|
5692
|
+
enableResizing: false,
|
|
5693
|
+
enableReorder: false,
|
|
5694
|
+
enableHiding: false,
|
|
5695
|
+
lockVisible: true
|
|
5696
|
+
};
|
|
5697
|
+
}
|
|
5698
|
+
|
|
5699
|
+
// src/presets/rowNumberColumn.tsx
|
|
5700
|
+
function rowNumberColumn(options = {}) {
|
|
5701
|
+
const { id = "_rowNumber", header = "#", size = 50, startFrom = 1 } = options;
|
|
5702
|
+
return {
|
|
5703
|
+
id,
|
|
5704
|
+
header,
|
|
5705
|
+
cell: ({ row }) => row.index + startFrom,
|
|
5706
|
+
size,
|
|
5707
|
+
enableSorting: false,
|
|
5708
|
+
enableColumnFilter: false,
|
|
5709
|
+
enableResizing: false,
|
|
5710
|
+
enableReorder: false,
|
|
5711
|
+
lockVisible: true
|
|
5712
|
+
};
|
|
5713
|
+
}
|
|
5714
|
+
function actionsColumn(options) {
|
|
5715
|
+
const { id = "_actions", header = "", size = 100, actions } = options;
|
|
5716
|
+
return {
|
|
5717
|
+
id,
|
|
5718
|
+
header,
|
|
5719
|
+
cell: (ctx) => {
|
|
5720
|
+
const items = typeof actions === "function" ? actions(ctx.row) : actions;
|
|
5721
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-cell-actions", children: items.filter((a) => !a.hidden || !a.hidden(ctx.row)).map((action, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5722
|
+
"button",
|
|
5723
|
+
{
|
|
5724
|
+
type: "button",
|
|
5725
|
+
className: "yable-action-btn",
|
|
5726
|
+
disabled: action.disabled?.(ctx.row),
|
|
5727
|
+
onClick: (e) => {
|
|
5728
|
+
e.stopPropagation();
|
|
5729
|
+
action.onClick(ctx.row);
|
|
5730
|
+
},
|
|
5731
|
+
title: action.label,
|
|
5732
|
+
children: action.icon ?? action.label
|
|
5733
|
+
},
|
|
5734
|
+
i
|
|
5735
|
+
)) });
|
|
5736
|
+
},
|
|
5737
|
+
size,
|
|
5738
|
+
enableSorting: false,
|
|
5739
|
+
enableColumnFilter: false,
|
|
5740
|
+
enableResizing: false,
|
|
5741
|
+
enableReorder: false
|
|
5742
|
+
};
|
|
5743
|
+
}
|
|
5744
|
+
function expandColumn(options = {}) {
|
|
5745
|
+
const { id = "_expand", size = 40 } = options;
|
|
5746
|
+
return {
|
|
5747
|
+
id,
|
|
5748
|
+
header: () => null,
|
|
5749
|
+
cell: ({ row }) => {
|
|
5750
|
+
if (!row.getCanExpand()) return null;
|
|
5751
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5752
|
+
"button",
|
|
5753
|
+
{
|
|
5754
|
+
type: "button",
|
|
5755
|
+
className: "yable-expand-btn",
|
|
5756
|
+
onClick: (e) => {
|
|
5757
|
+
e.stopPropagation();
|
|
5758
|
+
row.toggleExpanded();
|
|
5759
|
+
},
|
|
5760
|
+
"aria-expanded": row.getIsExpanded(),
|
|
5761
|
+
"aria-label": row.getIsExpanded() ? "Collapse row" : "Expand row",
|
|
5762
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5763
|
+
"span",
|
|
5764
|
+
{
|
|
5765
|
+
className: "yable-expand-icon",
|
|
5766
|
+
style: {
|
|
5767
|
+
display: "inline-block",
|
|
5768
|
+
transform: row.getIsExpanded() ? "rotate(90deg)" : "rotate(0deg)",
|
|
5769
|
+
transition: "transform 150ms ease"
|
|
5770
|
+
},
|
|
5771
|
+
children: "\u25B6"
|
|
5772
|
+
}
|
|
5773
|
+
)
|
|
5774
|
+
}
|
|
5775
|
+
);
|
|
5776
|
+
},
|
|
5777
|
+
size,
|
|
5778
|
+
enableSorting: false,
|
|
5779
|
+
enableColumnFilter: false,
|
|
5780
|
+
enableResizing: false,
|
|
5781
|
+
enableReorder: false,
|
|
5782
|
+
lockVisible: true
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
function CellStack({ children, gap = 2 }) {
|
|
5786
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5787
|
+
"div",
|
|
5788
|
+
{
|
|
5789
|
+
className: "yable-cell-stack",
|
|
5790
|
+
style: {
|
|
5791
|
+
display: "flex",
|
|
5792
|
+
flexDirection: "column",
|
|
5793
|
+
gap
|
|
5794
|
+
},
|
|
5795
|
+
children
|
|
5796
|
+
}
|
|
5797
|
+
);
|
|
5798
|
+
}
|
|
5799
|
+
function CellRow({ children, gap = 6, align = "center", justify = "start" }) {
|
|
5800
|
+
const justifyMap = {
|
|
5801
|
+
start: "flex-start",
|
|
5802
|
+
center: "center",
|
|
5803
|
+
end: "flex-end",
|
|
5804
|
+
between: "space-between"
|
|
5805
|
+
};
|
|
5806
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5807
|
+
"div",
|
|
5808
|
+
{
|
|
5809
|
+
className: "yable-cell-row",
|
|
5810
|
+
style: {
|
|
5811
|
+
display: "flex",
|
|
5812
|
+
flexDirection: "row",
|
|
5813
|
+
alignItems: align === "baseline" ? "baseline" : align === "start" ? "flex-start" : align === "end" ? "flex-end" : "center",
|
|
5814
|
+
justifyContent: justifyMap[justify] || "flex-start",
|
|
5815
|
+
gap
|
|
5816
|
+
},
|
|
5817
|
+
children
|
|
5818
|
+
}
|
|
5819
|
+
);
|
|
5820
|
+
}
|
|
5821
|
+
function CellWithIcon({ icon, children, gap = 6, iconSize }) {
|
|
5822
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5823
|
+
"div",
|
|
5824
|
+
{
|
|
5825
|
+
className: "yable-cell-with-icon",
|
|
5826
|
+
style: {
|
|
5827
|
+
display: "flex",
|
|
5828
|
+
flexDirection: "row",
|
|
5829
|
+
alignItems: "center",
|
|
5830
|
+
gap
|
|
5831
|
+
},
|
|
5832
|
+
children: [
|
|
5833
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5834
|
+
"span",
|
|
5835
|
+
{
|
|
5836
|
+
className: "yable-cell-icon",
|
|
5837
|
+
style: {
|
|
5838
|
+
display: "inline-flex",
|
|
5839
|
+
alignItems: "center",
|
|
5840
|
+
justifyContent: "center",
|
|
5841
|
+
flexShrink: 0,
|
|
5842
|
+
...iconSize ? { width: iconSize, height: iconSize } : {}
|
|
5843
|
+
},
|
|
5844
|
+
children: icon
|
|
5845
|
+
}
|
|
5846
|
+
),
|
|
5847
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "yable-cell-icon-content", style: { minWidth: 0 }, children })
|
|
5848
|
+
]
|
|
5849
|
+
}
|
|
5850
|
+
);
|
|
5851
|
+
}
|
|
5852
|
+
function CellText({
|
|
5853
|
+
children,
|
|
5854
|
+
variant = "primary",
|
|
5855
|
+
bold,
|
|
5856
|
+
truncate,
|
|
5857
|
+
size = "md"
|
|
5858
|
+
}) {
|
|
5859
|
+
const fontSizeMap = { sm: "0.75rem", md: "0.875rem", lg: "1rem" };
|
|
5860
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5861
|
+
"span",
|
|
5862
|
+
{
|
|
5863
|
+
className: `yable-cell-text yable-cell-text--${variant}`,
|
|
5864
|
+
style: {
|
|
5865
|
+
fontSize: fontSizeMap[size],
|
|
5866
|
+
fontWeight: bold ? 600 : void 0,
|
|
5867
|
+
color: variant === "secondary" ? "var(--yable-text-secondary, #6b7280)" : variant === "muted" ? "var(--yable-text-muted, #9ca3af)" : void 0,
|
|
5868
|
+
...truncate ? {
|
|
5869
|
+
overflow: "hidden",
|
|
5870
|
+
textOverflow: "ellipsis",
|
|
5871
|
+
whiteSpace: "nowrap"
|
|
5872
|
+
} : {}
|
|
5873
|
+
},
|
|
5874
|
+
children
|
|
5875
|
+
}
|
|
5876
|
+
);
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5879
|
+
// src/utils/mergeEditChanges.ts
|
|
5880
|
+
function mergeEditChanges(data, changes, getRowId = (_, i) => String(i)) {
|
|
5881
|
+
const changeKeys = Object.keys(changes);
|
|
5882
|
+
if (changeKeys.length === 0) return data;
|
|
5883
|
+
return data.map((row, i) => {
|
|
5884
|
+
const id = getRowId(row, i);
|
|
5885
|
+
const patch = changes[id];
|
|
5886
|
+
return patch ? { ...row, ...patch } : row;
|
|
5887
|
+
});
|
|
5888
|
+
}
|
|
4861
5889
|
|
|
4862
5890
|
Object.defineProperty(exports, "CommitError", {
|
|
4863
5891
|
enumerable: true,
|
|
@@ -4951,10 +5979,14 @@ exports.CellLink = CellLink;
|
|
|
4951
5979
|
exports.CellNumeric = CellNumeric;
|
|
4952
5980
|
exports.CellProgress = CellProgress;
|
|
4953
5981
|
exports.CellRating = CellRating;
|
|
5982
|
+
exports.CellRow = CellRow;
|
|
4954
5983
|
exports.CellSelect = CellSelect;
|
|
5984
|
+
exports.CellStack = CellStack;
|
|
4955
5985
|
exports.CellStatus = CellStatus;
|
|
4956
5986
|
exports.CellStatusBadge = CellStatusBadge;
|
|
5987
|
+
exports.CellText = CellText;
|
|
4957
5988
|
exports.CellToggle = CellToggle;
|
|
5989
|
+
exports.CellWithIcon = CellWithIcon;
|
|
4958
5990
|
exports.ColumnsPanel = ColumnsPanel;
|
|
4959
5991
|
exports.ContextMenu = ContextMenu;
|
|
4960
5992
|
exports.ContextMenuItem = ContextMenuItem;
|
|
@@ -4965,6 +5997,7 @@ exports.ExpandIcon = ExpandIcon;
|
|
|
4965
5997
|
exports.FillHandle = FillHandle;
|
|
4966
5998
|
exports.FiltersPanel = FiltersPanel;
|
|
4967
5999
|
exports.FlashCell = FlashCell;
|
|
6000
|
+
exports.FloatingFilter = FloatingFilter;
|
|
4968
6001
|
exports.GlobalFilter = GlobalFilter;
|
|
4969
6002
|
exports.LoadingOverlay = LoadingOverlay;
|
|
4970
6003
|
exports.MasterDetail = MasterDetail;
|
|
@@ -4972,6 +6005,7 @@ exports.NoRowsOverlay = NoRowsOverlay;
|
|
|
4972
6005
|
exports.Pagination = Pagination;
|
|
4973
6006
|
exports.PivotConfigPanel = PivotConfigPanel;
|
|
4974
6007
|
exports.PrintLayout = PrintLayout;
|
|
6008
|
+
exports.SetFilter = SetFilter;
|
|
4975
6009
|
exports.Sidebar = Sidebar;
|
|
4976
6010
|
exports.SortIndicator = SortIndicator;
|
|
4977
6011
|
exports.StatusBar = StatusBar;
|
|
@@ -4984,12 +6018,19 @@ exports.TableHeader = TableHeader;
|
|
|
4984
6018
|
exports.TableProvider = TableProvider;
|
|
4985
6019
|
exports.Tooltip = Tooltip;
|
|
4986
6020
|
exports.TreeToggle = TreeToggle;
|
|
6021
|
+
exports.YableProvider = YableProvider;
|
|
6022
|
+
exports.actionsColumn = actionsColumn;
|
|
6023
|
+
exports.expandColumn = expandColumn;
|
|
4987
6024
|
exports.getMeasureRecipeForCellType = getMeasureRecipeForCellType;
|
|
4988
6025
|
exports.getRegisteredCellTypes = getRegisteredCellTypes;
|
|
6026
|
+
exports.mergeEditChanges = mergeEditChanges;
|
|
4989
6027
|
exports.resolveMeasureRecipe = resolveMeasureRecipe;
|
|
6028
|
+
exports.rowNumberColumn = rowNumberColumn;
|
|
6029
|
+
exports.selectColumn = selectColumn;
|
|
4990
6030
|
exports.useAutoMeasurements = useAutoMeasurements;
|
|
4991
6031
|
exports.useCellFlash = useCellFlash;
|
|
4992
6032
|
exports.useClipboard = useClipboard;
|
|
6033
|
+
exports.useColumnVirtualization = useColumnVirtualization;
|
|
4993
6034
|
exports.useContextMenu = useContextMenu;
|
|
4994
6035
|
exports.useFillHandle = useFillHandle;
|
|
4995
6036
|
exports.useKeyboardNavigation = useKeyboardNavigation;
|
|
@@ -4999,9 +6040,11 @@ exports.useRowAnimation = useRowAnimation;
|
|
|
4999
6040
|
exports.useRowDrag = useRowDrag;
|
|
5000
6041
|
exports.useTable = useTable;
|
|
5001
6042
|
exports.useTableContext = useTableContext;
|
|
6043
|
+
exports.useTablePersistence = useTablePersistence;
|
|
5002
6044
|
exports.useTableRowHeights = useTableRowHeights;
|
|
5003
6045
|
exports.useTheme = useTheme;
|
|
5004
6046
|
exports.useTooltip = useTooltip;
|
|
5005
6047
|
exports.useVirtualization = useVirtualization;
|
|
6048
|
+
exports.useYableDefaults = useYableDefaults;
|
|
5006
6049
|
//# sourceMappingURL=index.cjs.map
|
|
5007
6050
|
//# sourceMappingURL=index.cjs.map
|