@zvndev/yable-react 0.2.0 → 0.3.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 +712 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -7
- package/dist/index.d.ts +52 -7
- package/dist/index.js +710 -152
- package/dist/index.js.map +1 -1
- package/package.json +34 -16
package/dist/index.js
CHANGED
|
@@ -210,7 +210,15 @@ function useVirtualization({
|
|
|
210
210
|
container.scrollTop = offset;
|
|
211
211
|
}
|
|
212
212
|
},
|
|
213
|
-
[
|
|
213
|
+
[
|
|
214
|
+
containerRef,
|
|
215
|
+
totalRows,
|
|
216
|
+
rowHeight,
|
|
217
|
+
isFixedHeight,
|
|
218
|
+
getRowHeight,
|
|
219
|
+
hasPretextHeights,
|
|
220
|
+
pretextPrefixSums
|
|
221
|
+
]
|
|
214
222
|
);
|
|
215
223
|
const totalHeight = useMemo(() => {
|
|
216
224
|
if (totalRows === 0) return 0;
|
|
@@ -264,10 +272,7 @@ function useVirtualization({
|
|
|
264
272
|
} else if (isFixedHeight) {
|
|
265
273
|
const fixedH = rowHeight;
|
|
266
274
|
startIndex = Math.floor(scrollTop / fixedH);
|
|
267
|
-
endIndex = Math.min(
|
|
268
|
-
totalRows - 1,
|
|
269
|
-
Math.ceil((scrollTop + containerHeight) / fixedH) - 1
|
|
270
|
-
);
|
|
275
|
+
endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / fixedH) - 1);
|
|
271
276
|
} else {
|
|
272
277
|
let accum = 0;
|
|
273
278
|
let foundStart = false;
|
|
@@ -334,6 +339,162 @@ function useVirtualization({
|
|
|
334
339
|
scrollTo
|
|
335
340
|
};
|
|
336
341
|
}
|
|
342
|
+
function binarySearchOffsets(offsets, target) {
|
|
343
|
+
let low = 0;
|
|
344
|
+
let high = offsets.length - 1;
|
|
345
|
+
while (low < high) {
|
|
346
|
+
const mid = low + high >>> 1;
|
|
347
|
+
if (offsets[mid + 1] <= target) {
|
|
348
|
+
low = mid + 1;
|
|
349
|
+
} else {
|
|
350
|
+
high = mid;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return low;
|
|
354
|
+
}
|
|
355
|
+
function useColumnVirtualization({
|
|
356
|
+
containerRef,
|
|
357
|
+
columns,
|
|
358
|
+
overscan = 2,
|
|
359
|
+
enabled = true
|
|
360
|
+
}) {
|
|
361
|
+
const [scrollState, setScrollState] = useState({
|
|
362
|
+
scrollLeft: 0,
|
|
363
|
+
containerWidth: 0
|
|
364
|
+
});
|
|
365
|
+
const rafRef = useRef(null);
|
|
366
|
+
const sizes = useMemo(() => columns.map((column) => column.getSize()), [columns]);
|
|
367
|
+
const offsets = useMemo(() => {
|
|
368
|
+
const next = new Array(columns.length + 1);
|
|
369
|
+
next[0] = 0;
|
|
370
|
+
for (let i = 0; i < columns.length; i++) {
|
|
371
|
+
next[i + 1] = next[i] + (sizes[i] ?? 0);
|
|
372
|
+
}
|
|
373
|
+
return next;
|
|
374
|
+
}, [columns.length, sizes]);
|
|
375
|
+
const totalWidth = offsets[offsets.length - 1] ?? 0;
|
|
376
|
+
useEffect(() => {
|
|
377
|
+
const container = containerRef.current;
|
|
378
|
+
if (!container) return;
|
|
379
|
+
setScrollState({
|
|
380
|
+
scrollLeft: container.scrollLeft,
|
|
381
|
+
containerWidth: container.clientWidth
|
|
382
|
+
});
|
|
383
|
+
const handleScroll = () => {
|
|
384
|
+
if (rafRef.current !== null) return;
|
|
385
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
386
|
+
rafRef.current = null;
|
|
387
|
+
const el = containerRef.current;
|
|
388
|
+
if (!el) return;
|
|
389
|
+
setScrollState({
|
|
390
|
+
scrollLeft: el.scrollLeft,
|
|
391
|
+
containerWidth: el.clientWidth
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
396
|
+
let resizeObserver;
|
|
397
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
398
|
+
resizeObserver = new ResizeObserver(() => {
|
|
399
|
+
const el = containerRef.current;
|
|
400
|
+
if (!el) return;
|
|
401
|
+
setScrollState((prev) => {
|
|
402
|
+
const nextWidth = el.clientWidth;
|
|
403
|
+
if (prev.containerWidth === nextWidth && prev.scrollLeft === el.scrollLeft) {
|
|
404
|
+
return prev;
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
scrollLeft: el.scrollLeft,
|
|
408
|
+
containerWidth: nextWidth
|
|
409
|
+
};
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
resizeObserver.observe(container);
|
|
413
|
+
}
|
|
414
|
+
return () => {
|
|
415
|
+
container.removeEventListener("scroll", handleScroll);
|
|
416
|
+
if (rafRef.current !== null) {
|
|
417
|
+
cancelAnimationFrame(rafRef.current);
|
|
418
|
+
rafRef.current = null;
|
|
419
|
+
}
|
|
420
|
+
resizeObserver?.disconnect();
|
|
421
|
+
};
|
|
422
|
+
}, [containerRef]);
|
|
423
|
+
const scrollToIndex = useCallback(
|
|
424
|
+
(index) => {
|
|
425
|
+
const container = containerRef.current;
|
|
426
|
+
if (!container || columns.length === 0) return;
|
|
427
|
+
const clampedIndex = Math.max(0, Math.min(index, columns.length - 1));
|
|
428
|
+
container.scrollLeft = offsets[clampedIndex] ?? 0;
|
|
429
|
+
},
|
|
430
|
+
[columns.length, containerRef, offsets]
|
|
431
|
+
);
|
|
432
|
+
if (!enabled || columns.length === 0) {
|
|
433
|
+
return {
|
|
434
|
+
virtualColumns: columns.map((column, index) => ({
|
|
435
|
+
column,
|
|
436
|
+
index,
|
|
437
|
+
start: offsets[index] ?? 0,
|
|
438
|
+
size: sizes[index] ?? 0
|
|
439
|
+
})),
|
|
440
|
+
startOffset: 0,
|
|
441
|
+
endOffset: 0,
|
|
442
|
+
totalWidth,
|
|
443
|
+
visibleWidth: totalWidth,
|
|
444
|
+
startIndex: 0,
|
|
445
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
446
|
+
isVirtualized: false,
|
|
447
|
+
scrollToIndex
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const { scrollLeft, containerWidth } = scrollState;
|
|
451
|
+
if (containerWidth <= 0 || totalWidth <= containerWidth) {
|
|
452
|
+
return {
|
|
453
|
+
virtualColumns: columns.map((column, index) => ({
|
|
454
|
+
column,
|
|
455
|
+
index,
|
|
456
|
+
start: offsets[index] ?? 0,
|
|
457
|
+
size: sizes[index] ?? 0
|
|
458
|
+
})),
|
|
459
|
+
startOffset: 0,
|
|
460
|
+
endOffset: 0,
|
|
461
|
+
totalWidth,
|
|
462
|
+
visibleWidth: totalWidth,
|
|
463
|
+
startIndex: 0,
|
|
464
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
465
|
+
isVirtualized: false,
|
|
466
|
+
scrollToIndex
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
const startIndex = binarySearchOffsets(offsets, scrollLeft);
|
|
470
|
+
const endBoundary = scrollLeft + containerWidth;
|
|
471
|
+
const endIndex = binarySearchOffsets(offsets, Math.max(scrollLeft, endBoundary - 1));
|
|
472
|
+
const overscanStart = Math.max(0, startIndex - overscan);
|
|
473
|
+
const overscanEnd = Math.min(columns.length - 1, endIndex + overscan);
|
|
474
|
+
const virtualColumns = [];
|
|
475
|
+
for (let i = overscanStart; i <= overscanEnd; i++) {
|
|
476
|
+
virtualColumns.push({
|
|
477
|
+
column: columns[i],
|
|
478
|
+
index: i,
|
|
479
|
+
start: offsets[i] ?? 0,
|
|
480
|
+
size: sizes[i] ?? 0
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const startOffset = offsets[overscanStart] ?? 0;
|
|
484
|
+
const visibleWidth = (offsets[overscanEnd + 1] ?? totalWidth) - startOffset;
|
|
485
|
+
const endOffset = totalWidth - (offsets[overscanEnd + 1] ?? totalWidth);
|
|
486
|
+
return {
|
|
487
|
+
virtualColumns,
|
|
488
|
+
startOffset,
|
|
489
|
+
endOffset,
|
|
490
|
+
totalWidth,
|
|
491
|
+
visibleWidth,
|
|
492
|
+
startIndex: overscanStart,
|
|
493
|
+
endIndex: overscanEnd,
|
|
494
|
+
isVirtualized: true,
|
|
495
|
+
scrollToIndex
|
|
496
|
+
};
|
|
497
|
+
}
|
|
337
498
|
var pretextPromise = null;
|
|
338
499
|
function loadPretext() {
|
|
339
500
|
if (pretextPromise) return pretextPromise;
|
|
@@ -384,7 +545,12 @@ function usePretextMeasurement({
|
|
|
384
545
|
}
|
|
385
546
|
prepareTimeRef.current = performance.now() - start;
|
|
386
547
|
return result;
|
|
387
|
-
}, [
|
|
548
|
+
}, [
|
|
549
|
+
pretext,
|
|
550
|
+
enabled,
|
|
551
|
+
data,
|
|
552
|
+
columns.map((c) => `${c.columnId}:${c.font}:${c.fixedHeight ? "F" : "T"}`).join("|")
|
|
553
|
+
]);
|
|
388
554
|
const measurement = useMemo(() => {
|
|
389
555
|
if (!pretext || !preparedCells) {
|
|
390
556
|
return { rowHeights: null, prefixSums: null, totalHeight: 0 };
|
|
@@ -422,6 +588,7 @@ function usePretextMeasurement({
|
|
|
422
588
|
return {
|
|
423
589
|
rowHeights,
|
|
424
590
|
prefixSums,
|
|
591
|
+
// Safe: prefixSums has length data.length + 1, so [data.length] always exists
|
|
425
592
|
totalHeight: prefixSums[data.length]
|
|
426
593
|
};
|
|
427
594
|
}, [pretext, preparedCells, columnWidthsKey, minRowHeight, data.length]);
|
|
@@ -686,18 +853,10 @@ function CellDate({
|
|
|
686
853
|
if (raw == null) return null;
|
|
687
854
|
const date = raw instanceof Date ? raw : new Date(String(raw));
|
|
688
855
|
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]);
|
|
856
|
+
const formatter = typeof format === "string" && format !== "relative" ? new Intl.DateTimeFormat(locale, {
|
|
857
|
+
...PRESETS[format],
|
|
858
|
+
timeZone: "UTC"
|
|
859
|
+
}) : typeof format === "object" ? new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" }) : null;
|
|
701
860
|
const formatted = format === "relative" ? formatRelative(date) : formatter ? formatter.format(date) : date.toLocaleDateString(locale);
|
|
702
861
|
return /* @__PURE__ */ jsx("span", { className: `yable-cell-date ${className ?? ""}`, title: date.toISOString(), children: formatted });
|
|
703
862
|
}
|
|
@@ -708,8 +867,14 @@ var measureRecipe9 = {
|
|
|
708
867
|
padding: 20
|
|
709
868
|
};
|
|
710
869
|
function isSafeUrl(url) {
|
|
711
|
-
const normalized = String(url).
|
|
712
|
-
|
|
870
|
+
const normalized = String(url).trim();
|
|
871
|
+
if (/^[/#?]/.test(normalized)) return true;
|
|
872
|
+
try {
|
|
873
|
+
const parsed = new URL(normalized, "https://placeholder.invalid");
|
|
874
|
+
return ["http:", "https:", "mailto:", "tel:"].includes(parsed.protocol);
|
|
875
|
+
} catch {
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
713
878
|
}
|
|
714
879
|
function CellLink({
|
|
715
880
|
context,
|
|
@@ -886,7 +1051,7 @@ function useTableContext() {
|
|
|
886
1051
|
const ctx = useContext(TableContext);
|
|
887
1052
|
if (!ctx) {
|
|
888
1053
|
throw new Error(
|
|
889
|
-
"[yable] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
1054
|
+
"[yable E001] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
890
1055
|
);
|
|
891
1056
|
}
|
|
892
1057
|
return ctx;
|
|
@@ -936,12 +1101,234 @@ function SortIndicator({ direction, index }) {
|
|
|
936
1101
|
}
|
|
937
1102
|
);
|
|
938
1103
|
}
|
|
1104
|
+
function formatValue(value) {
|
|
1105
|
+
if (value == null || value === "") return "(empty)";
|
|
1106
|
+
if (typeof value === "string") return value;
|
|
1107
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1108
|
+
if (value instanceof Date) return value.toISOString();
|
|
1109
|
+
return JSON.stringify(value);
|
|
1110
|
+
}
|
|
1111
|
+
function SetFilter({ column, className }) {
|
|
1112
|
+
const [open, setOpen] = useState(false);
|
|
1113
|
+
const filterValue = column.getFilterValue();
|
|
1114
|
+
const selectedValues = Array.isArray(filterValue) ? filterValue : filterValue == null || filterValue === "" ? [] : [filterValue];
|
|
1115
|
+
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
1116
|
+
const options = Array.from(facetedUniqueValues.entries()).map(([value, count]) => ({
|
|
1117
|
+
value,
|
|
1118
|
+
count,
|
|
1119
|
+
label: formatValue(value)
|
|
1120
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
1121
|
+
const selectedSet = new Set(selectedValues);
|
|
1122
|
+
const toggleValue = (value) => {
|
|
1123
|
+
const next = new Set(selectedSet);
|
|
1124
|
+
if (next.has(value)) {
|
|
1125
|
+
next.delete(value);
|
|
1126
|
+
} else {
|
|
1127
|
+
next.add(value);
|
|
1128
|
+
}
|
|
1129
|
+
const nextValues = Array.from(next);
|
|
1130
|
+
column.setFilterValue(nextValues.length > 0 ? nextValues : void 0);
|
|
1131
|
+
};
|
|
1132
|
+
const headerLabel = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1133
|
+
return /* @__PURE__ */ jsxs(
|
|
1134
|
+
"div",
|
|
1135
|
+
{
|
|
1136
|
+
className: ["yable-set-filter", className].filter(Boolean).join(" "),
|
|
1137
|
+
style: { position: "relative" },
|
|
1138
|
+
children: [
|
|
1139
|
+
/* @__PURE__ */ jsx(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
type: "button",
|
|
1143
|
+
className: "yable-set-filter-trigger",
|
|
1144
|
+
"aria-haspopup": "dialog",
|
|
1145
|
+
"aria-expanded": open,
|
|
1146
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1147
|
+
style: {
|
|
1148
|
+
width: "100%",
|
|
1149
|
+
minHeight: 28,
|
|
1150
|
+
padding: "4px 8px",
|
|
1151
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1152
|
+
borderRadius: 6,
|
|
1153
|
+
background: "transparent",
|
|
1154
|
+
font: "inherit",
|
|
1155
|
+
textAlign: "left",
|
|
1156
|
+
cursor: "pointer"
|
|
1157
|
+
},
|
|
1158
|
+
children: selectedValues.length > 0 ? `${selectedValues.length} selected` : `Filter ${headerLabel}`
|
|
1159
|
+
}
|
|
1160
|
+
),
|
|
1161
|
+
open && /* @__PURE__ */ jsxs(
|
|
1162
|
+
"div",
|
|
1163
|
+
{
|
|
1164
|
+
role: "dialog",
|
|
1165
|
+
"aria-label": `${headerLabel} set filter`,
|
|
1166
|
+
className: "yable-set-filter-popover",
|
|
1167
|
+
style: {
|
|
1168
|
+
position: "absolute",
|
|
1169
|
+
insetInlineStart: 0,
|
|
1170
|
+
top: "calc(100% + 4px)",
|
|
1171
|
+
zIndex: 20,
|
|
1172
|
+
width: 220,
|
|
1173
|
+
maxHeight: 240,
|
|
1174
|
+
overflow: "auto",
|
|
1175
|
+
padding: 8,
|
|
1176
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1177
|
+
borderRadius: 8,
|
|
1178
|
+
background: "var(--yable-color-bg, #fff)",
|
|
1179
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.12)"
|
|
1180
|
+
},
|
|
1181
|
+
children: [
|
|
1182
|
+
/* @__PURE__ */ jsxs(
|
|
1183
|
+
"div",
|
|
1184
|
+
{
|
|
1185
|
+
style: {
|
|
1186
|
+
display: "flex",
|
|
1187
|
+
alignItems: "center",
|
|
1188
|
+
justifyContent: "space-between",
|
|
1189
|
+
gap: 8,
|
|
1190
|
+
marginBottom: 8
|
|
1191
|
+
},
|
|
1192
|
+
children: [
|
|
1193
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: 12 }, children: headerLabel }),
|
|
1194
|
+
selectedValues.length > 0 && /* @__PURE__ */ jsx(
|
|
1195
|
+
"button",
|
|
1196
|
+
{
|
|
1197
|
+
type: "button",
|
|
1198
|
+
onClick: () => column.setFilterValue(void 0),
|
|
1199
|
+
style: {
|
|
1200
|
+
border: "none",
|
|
1201
|
+
background: "transparent",
|
|
1202
|
+
padding: 0,
|
|
1203
|
+
cursor: "pointer",
|
|
1204
|
+
fontSize: 12
|
|
1205
|
+
},
|
|
1206
|
+
children: "Clear"
|
|
1207
|
+
}
|
|
1208
|
+
)
|
|
1209
|
+
]
|
|
1210
|
+
}
|
|
1211
|
+
),
|
|
1212
|
+
/* @__PURE__ */ jsxs("div", { role: "group", "aria-label": `${headerLabel} options`, children: [
|
|
1213
|
+
options.length === 0 && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, opacity: 0.75 }, children: "No values" }),
|
|
1214
|
+
options.map((option) => {
|
|
1215
|
+
const checked = selectedSet.has(option.value);
|
|
1216
|
+
return /* @__PURE__ */ jsxs(
|
|
1217
|
+
"label",
|
|
1218
|
+
{
|
|
1219
|
+
style: {
|
|
1220
|
+
display: "flex",
|
|
1221
|
+
alignItems: "center",
|
|
1222
|
+
gap: 8,
|
|
1223
|
+
padding: "4px 0",
|
|
1224
|
+
fontSize: 12
|
|
1225
|
+
},
|
|
1226
|
+
children: [
|
|
1227
|
+
/* @__PURE__ */ jsx(
|
|
1228
|
+
"input",
|
|
1229
|
+
{
|
|
1230
|
+
type: "checkbox",
|
|
1231
|
+
checked,
|
|
1232
|
+
onChange: () => toggleValue(option.value)
|
|
1233
|
+
}
|
|
1234
|
+
),
|
|
1235
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: option.label }),
|
|
1236
|
+
/* @__PURE__ */ jsx("span", { style: { opacity: 0.6 }, children: option.count })
|
|
1237
|
+
]
|
|
1238
|
+
},
|
|
1239
|
+
`${option.label}-${option.count}`
|
|
1240
|
+
);
|
|
1241
|
+
})
|
|
1242
|
+
] })
|
|
1243
|
+
]
|
|
1244
|
+
}
|
|
1245
|
+
)
|
|
1246
|
+
]
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function isSetCompatibleValue(value) {
|
|
1251
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1252
|
+
}
|
|
1253
|
+
function inferFilterVariant(column) {
|
|
1254
|
+
const meta = column.columnDef.meta ?? {};
|
|
1255
|
+
if (meta.filterVariant) return meta.filterVariant;
|
|
1256
|
+
const uniqueValues = column.getFacetedUniqueValues();
|
|
1257
|
+
if (uniqueValues.size > 0 && uniqueValues.size <= 12) {
|
|
1258
|
+
const allValuesSupported = Array.from(uniqueValues.keys()).every(isSetCompatibleValue);
|
|
1259
|
+
if (allValuesSupported) return "set";
|
|
1260
|
+
}
|
|
1261
|
+
return "text";
|
|
1262
|
+
}
|
|
1263
|
+
function FloatingFilter({ column }) {
|
|
1264
|
+
const variant = inferFilterVariant(column);
|
|
1265
|
+
if (!column.getCanFilter()) {
|
|
1266
|
+
return /* @__PURE__ */ jsx("div", { style: { minHeight: 28 }, "aria-hidden": "true" });
|
|
1267
|
+
}
|
|
1268
|
+
if (variant === "set") {
|
|
1269
|
+
return /* @__PURE__ */ jsx(SetFilter, { column });
|
|
1270
|
+
}
|
|
1271
|
+
const filterValue = column.getFilterValue();
|
|
1272
|
+
const normalizedValue = typeof filterValue === "string" || typeof filterValue === "number" ? String(filterValue) : "";
|
|
1273
|
+
const label = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1274
|
+
return /* @__PURE__ */ jsx("label", { style: { display: "block" }, children: /* @__PURE__ */ jsx(
|
|
1275
|
+
"input",
|
|
1276
|
+
{
|
|
1277
|
+
"aria-label": `Filter ${label}`,
|
|
1278
|
+
className: "yable-floating-filter-input",
|
|
1279
|
+
value: normalizedValue,
|
|
1280
|
+
onChange: (event) => {
|
|
1281
|
+
const nextValue = event.target.value;
|
|
1282
|
+
column.setFilterValue(nextValue === "" ? void 0 : nextValue);
|
|
1283
|
+
},
|
|
1284
|
+
placeholder: `Filter ${label}`,
|
|
1285
|
+
style: {
|
|
1286
|
+
width: "100%",
|
|
1287
|
+
minHeight: 28,
|
|
1288
|
+
padding: "4px 8px",
|
|
1289
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1290
|
+
borderRadius: 6,
|
|
1291
|
+
background: "transparent",
|
|
1292
|
+
font: "inherit"
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
) });
|
|
1296
|
+
}
|
|
939
1297
|
var DRAG_MIME = "application/yable-column";
|
|
940
1298
|
function TableHeader({
|
|
941
|
-
table
|
|
1299
|
+
table,
|
|
1300
|
+
floatingFilters = false
|
|
942
1301
|
}) {
|
|
943
1302
|
const headerGroups = table.getHeaderGroups();
|
|
944
|
-
|
|
1303
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
1304
|
+
return /* @__PURE__ */ jsxs("thead", { className: "yable-thead", children: [
|
|
1305
|
+
headerGroups.map((headerGroup) => /* @__PURE__ */ jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(HeaderCell, { header, table }, header.id)) }, headerGroup.id)),
|
|
1306
|
+
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`)) })
|
|
1307
|
+
] });
|
|
1308
|
+
}
|
|
1309
|
+
function FloatingFilterCell({
|
|
1310
|
+
column
|
|
1311
|
+
}) {
|
|
1312
|
+
const style = useMemo(() => {
|
|
1313
|
+
const next = {
|
|
1314
|
+
width: column.getSize(),
|
|
1315
|
+
minWidth: column.columnDef.minSize,
|
|
1316
|
+
maxWidth: column.columnDef.maxSize,
|
|
1317
|
+
padding: 6,
|
|
1318
|
+
verticalAlign: "top"
|
|
1319
|
+
};
|
|
1320
|
+
const pinned = column.getIsPinned();
|
|
1321
|
+
if (pinned) {
|
|
1322
|
+
next.position = "sticky";
|
|
1323
|
+
if (pinned === "left") {
|
|
1324
|
+
next.left = column.getStart("left");
|
|
1325
|
+
} else {
|
|
1326
|
+
next.right = column.getStart("right");
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return next;
|
|
1330
|
+
}, [column]);
|
|
1331
|
+
return /* @__PURE__ */ jsx("th", { className: "yable-th yable-th--filter", role: "columnheader", style, children: /* @__PURE__ */ jsx(FloatingFilter, { column }) });
|
|
945
1332
|
}
|
|
946
1333
|
function HeaderCell({
|
|
947
1334
|
header,
|
|
@@ -1030,14 +1417,11 @@ function HeaderCell({
|
|
|
1030
1417
|
},
|
|
1031
1418
|
[canReorder]
|
|
1032
1419
|
);
|
|
1033
|
-
const handleDragLeave = useCallback(
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
},
|
|
1039
|
-
[]
|
|
1040
|
-
);
|
|
1420
|
+
const handleDragLeave = useCallback((e) => {
|
|
1421
|
+
const next = e.relatedTarget;
|
|
1422
|
+
if (next && e.currentTarget.contains(next)) return;
|
|
1423
|
+
setDragOver(null);
|
|
1424
|
+
}, []);
|
|
1041
1425
|
const handleDragEnd = useCallback(() => {
|
|
1042
1426
|
setDragOver(null);
|
|
1043
1427
|
}, []);
|
|
@@ -1110,13 +1494,7 @@ function HeaderCell({
|
|
|
1110
1494
|
children: [
|
|
1111
1495
|
/* @__PURE__ */ jsxs("div", { className: "yable-th-content", children: [
|
|
1112
1496
|
/* @__PURE__ */ jsx("span", { children: headerContent }),
|
|
1113
|
-
canSort && /* @__PURE__ */ jsx(
|
|
1114
|
-
SortIndicator,
|
|
1115
|
-
{
|
|
1116
|
-
direction: sortDirection,
|
|
1117
|
-
index: sortIndex > 0 ? sortIndex : void 0
|
|
1118
|
-
}
|
|
1119
|
-
)
|
|
1497
|
+
canSort && /* @__PURE__ */ jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
|
|
1120
1498
|
] }),
|
|
1121
1499
|
canResize && /* @__PURE__ */ jsx(
|
|
1122
1500
|
"div",
|
|
@@ -1241,6 +1619,10 @@ function TableCell({
|
|
|
1241
1619
|
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
1242
1620
|
const cellErrorMessage = table.getCellErrorMessage(cell.row.id, column.id);
|
|
1243
1621
|
const cellConflictWith = table.getCellConflictWith(cell.row.id, column.id);
|
|
1622
|
+
const selectionRange = table.getCellSelectionRange();
|
|
1623
|
+
const selectionEdges = table.getCellSelectionEdges(rowIndex, columnIndex);
|
|
1624
|
+
const isCellSelected = selectionEdges !== null;
|
|
1625
|
+
const isMultiCellSelection = selectionRange !== null && (selectionRange.start.rowIndex !== selectionRange.end.rowIndex || selectionRange.start.columnIndex !== selectionRange.end.columnIndex);
|
|
1244
1626
|
const overrideValue = cellStatus !== "idle" ? table.getCellRenderValue(cell.row.id, column.id) : void 0;
|
|
1245
1627
|
let content;
|
|
1246
1628
|
const cellDef = column.columnDef.cell;
|
|
@@ -1264,23 +1646,17 @@ function TableCell({
|
|
|
1264
1646
|
}
|
|
1265
1647
|
const handleClick = useCallback(
|
|
1266
1648
|
(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
1649
|
table.events.emit("cell:click", {
|
|
1274
1650
|
cell,
|
|
1275
1651
|
row: cell.row,
|
|
1276
1652
|
column: cell.column,
|
|
1277
1653
|
event: e.nativeEvent
|
|
1278
1654
|
});
|
|
1279
|
-
if (canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing) {
|
|
1655
|
+
if (canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing && !isMultiCellSelection && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
1280
1656
|
table.startEditing(cell.row.id, column.id);
|
|
1281
1657
|
}
|
|
1282
1658
|
},
|
|
1283
|
-
[cell, column,
|
|
1659
|
+
[cell, column, isAlwaysEditable, isEditing, isMultiCellSelection, table]
|
|
1284
1660
|
);
|
|
1285
1661
|
const handleDoubleClick = useCallback(
|
|
1286
1662
|
(e) => {
|
|
@@ -1308,9 +1684,34 @@ function TableCell({
|
|
|
1308
1684
|
if (!keyboardNavigationEnabled) return;
|
|
1309
1685
|
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1310
1686
|
}, [columnIndex, keyboardNavigationEnabled, rowIndex, table]);
|
|
1687
|
+
const handleMouseDown = useCallback(
|
|
1688
|
+
(e) => {
|
|
1689
|
+
if (e.button !== 0) return;
|
|
1690
|
+
const clickTarget = e.target;
|
|
1691
|
+
if (isInteractiveClickTarget(clickTarget)) return;
|
|
1692
|
+
e.preventDefault();
|
|
1693
|
+
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1694
|
+
table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
|
|
1695
|
+
e.currentTarget.focus({ preventScroll: true });
|
|
1696
|
+
},
|
|
1697
|
+
[columnIndex, rowIndex, table]
|
|
1698
|
+
);
|
|
1699
|
+
const handleMouseEnter = useCallback(() => {
|
|
1700
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1701
|
+
table.updateCellRangeSelection({ rowIndex, columnIndex });
|
|
1702
|
+
}, [columnIndex, rowIndex, table]);
|
|
1703
|
+
const handleMouseUp = useCallback(() => {
|
|
1704
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1705
|
+
table.endCellRangeSelection();
|
|
1706
|
+
}, [table]);
|
|
1311
1707
|
const classNames = [
|
|
1312
1708
|
"yable-td",
|
|
1313
|
-
isFocused && "yable-cell--focused"
|
|
1709
|
+
isFocused && "yable-cell--focused",
|
|
1710
|
+
isCellSelected && "yable-cell--selected",
|
|
1711
|
+
selectionEdges?.top && "yable-cell--selection-top",
|
|
1712
|
+
selectionEdges?.right && "yable-cell--selection-right",
|
|
1713
|
+
selectionEdges?.bottom && "yable-cell--selection-bottom",
|
|
1714
|
+
selectionEdges?.left && "yable-cell--selection-left"
|
|
1314
1715
|
].filter(Boolean).join(" ");
|
|
1315
1716
|
return /* @__PURE__ */ jsxs(
|
|
1316
1717
|
"td",
|
|
@@ -1324,10 +1725,14 @@ function TableCell({
|
|
|
1324
1725
|
"data-column-id": column.id,
|
|
1325
1726
|
"data-row-index": rowIndex,
|
|
1326
1727
|
"data-column-index": columnIndex,
|
|
1728
|
+
"data-cell-selected": isCellSelected || void 0,
|
|
1327
1729
|
"aria-rowindex": rowIndex + 1,
|
|
1328
1730
|
"aria-colindex": columnIndex + 1,
|
|
1329
1731
|
role: "gridcell",
|
|
1330
1732
|
tabIndex: keyboardNavigationEnabled ? isTabStop ? 0 : -1 : void 0,
|
|
1733
|
+
onMouseDown: handleMouseDown,
|
|
1734
|
+
onMouseEnter: handleMouseEnter,
|
|
1735
|
+
onMouseUp: handleMouseUp,
|
|
1331
1736
|
onClick: handleClick,
|
|
1332
1737
|
onDoubleClick: handleDoubleClick,
|
|
1333
1738
|
onContextMenu: handleContextMenu,
|
|
@@ -1452,14 +1857,15 @@ var CellErrorBoundary = class extends React3.Component {
|
|
|
1452
1857
|
return this.props.children;
|
|
1453
1858
|
}
|
|
1454
1859
|
};
|
|
1455
|
-
function TableBody({
|
|
1456
|
-
table,
|
|
1457
|
-
clickableRows
|
|
1458
|
-
}) {
|
|
1860
|
+
function TableBody({ table, clickableRows }) {
|
|
1459
1861
|
const rows = table.getRowModel().rows;
|
|
1460
1862
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1461
1863
|
const activeCell = table.getState().editing.activeCell;
|
|
1462
1864
|
const focusedCell = table.getFocusedCell();
|
|
1865
|
+
const cellSelection = table.getState().cellSelection ?? {
|
|
1866
|
+
range: null,
|
|
1867
|
+
isDragging: false
|
|
1868
|
+
};
|
|
1463
1869
|
const options = table.options;
|
|
1464
1870
|
const enableVirtualization = options.enableVirtualization ?? false;
|
|
1465
1871
|
const scrollContainerRef = useRef(null);
|
|
@@ -1477,6 +1883,18 @@ function TableBody({
|
|
|
1477
1883
|
pretextHeights,
|
|
1478
1884
|
pretextPrefixSums
|
|
1479
1885
|
});
|
|
1886
|
+
const cellSelectionKey = cellSelection.range ? `${cellSelection.range.start.rowIndex}:${cellSelection.range.start.columnIndex}:${cellSelection.range.end.rowIndex}:${cellSelection.range.end.columnIndex}:${cellSelection.isDragging ? "dragging" : "idle"}` : `none:${cellSelection.isDragging ? "dragging" : "idle"}`;
|
|
1887
|
+
useEffect(() => {
|
|
1888
|
+
const handleWindowMouseUp = () => {
|
|
1889
|
+
if (table.getState().cellSelection?.isDragging) {
|
|
1890
|
+
table.endCellRangeSelection();
|
|
1891
|
+
}
|
|
1892
|
+
};
|
|
1893
|
+
window.addEventListener("mouseup", handleWindowMouseUp);
|
|
1894
|
+
return () => {
|
|
1895
|
+
window.removeEventListener("mouseup", handleWindowMouseUp);
|
|
1896
|
+
};
|
|
1897
|
+
}, [table]);
|
|
1480
1898
|
if (!enableVirtualization) {
|
|
1481
1899
|
return /* @__PURE__ */ jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx(
|
|
1482
1900
|
MemoizedTableRow,
|
|
@@ -1490,6 +1908,7 @@ function TableBody({
|
|
|
1490
1908
|
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1491
1909
|
focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
|
|
1492
1910
|
hasFocusedCell: focusedCell !== null,
|
|
1911
|
+
cellSelectionKey,
|
|
1493
1912
|
clickable: clickableRows
|
|
1494
1913
|
},
|
|
1495
1914
|
row.id
|
|
@@ -1498,73 +1917,67 @@ function TableBody({
|
|
|
1498
1917
|
const hasPretextData = !!(pretextHeights && pretextPrefixSums);
|
|
1499
1918
|
const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
|
|
1500
1919
|
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
|
-
"
|
|
1920
|
+
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(
|
|
1921
|
+
"div",
|
|
1503
1922
|
{
|
|
1504
|
-
|
|
1505
|
-
|
|
1923
|
+
ref: scrollContainerRef,
|
|
1924
|
+
className: "yable-virtual-scroll-container",
|
|
1925
|
+
style: {
|
|
1926
|
+
overflowY: "auto",
|
|
1927
|
+
height: containerHeight,
|
|
1928
|
+
position: "relative"
|
|
1929
|
+
},
|
|
1506
1930
|
children: /* @__PURE__ */ jsx(
|
|
1507
1931
|
"div",
|
|
1508
1932
|
{
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
style: {
|
|
1512
|
-
overflowY: "auto",
|
|
1513
|
-
height: containerHeight,
|
|
1514
|
-
position: "relative"
|
|
1515
|
-
},
|
|
1933
|
+
className: "yable-virtual-spacer",
|
|
1934
|
+
style: { height: totalHeight, position: "relative" },
|
|
1516
1935
|
children: /* @__PURE__ */ jsx(
|
|
1517
|
-
"
|
|
1936
|
+
"table",
|
|
1518
1937
|
{
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1938
|
+
style: {
|
|
1939
|
+
position: "absolute",
|
|
1940
|
+
top: 0,
|
|
1941
|
+
left: 0,
|
|
1942
|
+
width: "100%",
|
|
1943
|
+
tableLayout: "fixed",
|
|
1944
|
+
borderCollapse: "collapse"
|
|
1945
|
+
},
|
|
1946
|
+
children: /* @__PURE__ */ jsx("tbody", { children: virtualRows.map((vRow) => {
|
|
1947
|
+
const row = rows[vRow.index];
|
|
1948
|
+
if (!row) return null;
|
|
1949
|
+
return /* @__PURE__ */ jsx(
|
|
1950
|
+
MemoizedTableRow,
|
|
1951
|
+
{
|
|
1952
|
+
row,
|
|
1953
|
+
table,
|
|
1954
|
+
rowIndex: vRow.index,
|
|
1955
|
+
visibleColumns,
|
|
1956
|
+
isSelected: row.getIsSelected(),
|
|
1957
|
+
isExpanded: row.getIsExpanded(),
|
|
1958
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1959
|
+
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
1960
|
+
hasFocusedCell: focusedCell !== null,
|
|
1961
|
+
cellSelectionKey,
|
|
1962
|
+
clickable: clickableRows,
|
|
1963
|
+
virtualStyle: {
|
|
1964
|
+
position: "absolute",
|
|
1965
|
+
top: 0,
|
|
1966
|
+
left: 0,
|
|
1967
|
+
width: "100%",
|
|
1968
|
+
height: vRow.size,
|
|
1969
|
+
transform: `translateY(${vRow.start}px)`
|
|
1970
|
+
}
|
|
1531
1971
|
},
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
return /* @__PURE__ */ jsx(
|
|
1536
|
-
MemoizedTableRow,
|
|
1537
|
-
{
|
|
1538
|
-
row,
|
|
1539
|
-
table,
|
|
1540
|
-
rowIndex: vRow.index,
|
|
1541
|
-
visibleColumns,
|
|
1542
|
-
isSelected: row.getIsSelected(),
|
|
1543
|
-
isExpanded: row.getIsExpanded(),
|
|
1544
|
-
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1545
|
-
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
1546
|
-
hasFocusedCell: focusedCell !== null,
|
|
1547
|
-
clickable: clickableRows,
|
|
1548
|
-
virtualStyle: {
|
|
1549
|
-
position: "absolute",
|
|
1550
|
-
top: 0,
|
|
1551
|
-
left: 0,
|
|
1552
|
-
width: "100%",
|
|
1553
|
-
height: vRow.size,
|
|
1554
|
-
transform: `translateY(${vRow.start}px)`
|
|
1555
|
-
}
|
|
1556
|
-
},
|
|
1557
|
-
row.id
|
|
1558
|
-
);
|
|
1559
|
-
}) })
|
|
1560
|
-
}
|
|
1561
|
-
)
|
|
1972
|
+
row.id
|
|
1973
|
+
);
|
|
1974
|
+
}) })
|
|
1562
1975
|
}
|
|
1563
1976
|
)
|
|
1564
1977
|
}
|
|
1565
1978
|
)
|
|
1566
1979
|
}
|
|
1567
|
-
) }) });
|
|
1980
|
+
) }) }) });
|
|
1568
1981
|
}
|
|
1569
1982
|
function TableRowInner({
|
|
1570
1983
|
row,
|
|
@@ -1576,10 +1989,12 @@ function TableRowInner({
|
|
|
1576
1989
|
activeColumnId,
|
|
1577
1990
|
focusedColumnIndex,
|
|
1578
1991
|
hasFocusedCell,
|
|
1992
|
+
cellSelectionKey: _cellSelectionKey,
|
|
1579
1993
|
clickable,
|
|
1580
1994
|
virtualStyle
|
|
1581
1995
|
}) {
|
|
1582
|
-
const
|
|
1996
|
+
const allCells = row.getAllCells();
|
|
1997
|
+
const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
|
|
1583
1998
|
const handleClick = useCallback(
|
|
1584
1999
|
(e) => {
|
|
1585
2000
|
if (clickable) {
|
|
@@ -1609,6 +2024,8 @@ function TableRowInner({
|
|
|
1609
2024
|
},
|
|
1610
2025
|
[table.events, row]
|
|
1611
2026
|
);
|
|
2027
|
+
const selectionEnabled = Boolean(table.options.enableRowSelection);
|
|
2028
|
+
const expansionEnabled = Boolean(table.options.enableExpanding);
|
|
1612
2029
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1613
2030
|
/* @__PURE__ */ jsx(
|
|
1614
2031
|
"tr",
|
|
@@ -1620,6 +2037,8 @@ function TableRowInner({
|
|
|
1620
2037
|
"data-clickable": clickable || void 0,
|
|
1621
2038
|
"data-row-id": row.id,
|
|
1622
2039
|
"data-row-index": rowIndex,
|
|
2040
|
+
"aria-selected": selectionEnabled ? isSelected : void 0,
|
|
2041
|
+
"aria-expanded": expansionEnabled ? isExpanded : void 0,
|
|
1623
2042
|
onClick: handleClick,
|
|
1624
2043
|
onDoubleClick: handleDoubleClick,
|
|
1625
2044
|
onContextMenu: handleContextMenu,
|
|
@@ -1661,6 +2080,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1661
2080
|
if (prev.activeColumnId !== next.activeColumnId) return false;
|
|
1662
2081
|
if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
|
|
1663
2082
|
if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
|
|
2083
|
+
if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
|
|
1664
2084
|
if (prev.virtualStyle !== next.virtualStyle) {
|
|
1665
2085
|
if (!prev.virtualStyle || !next.virtualStyle) return false;
|
|
1666
2086
|
if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
|
|
@@ -1670,9 +2090,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1670
2090
|
return true;
|
|
1671
2091
|
}
|
|
1672
2092
|
var MemoizedTableRow = React3.memo(TableRowInner, areRowPropsEqual);
|
|
1673
|
-
function TableFooter({
|
|
1674
|
-
table
|
|
1675
|
-
}) {
|
|
2093
|
+
function TableFooter({ table }) {
|
|
1676
2094
|
const footerGroups = table.getFooterGroups();
|
|
1677
2095
|
if (!footerGroups.length) return null;
|
|
1678
2096
|
return /* @__PURE__ */ jsx("tfoot", { className: "yable-tfoot", children: footerGroups.map((footerGroup) => /* @__PURE__ */ jsx("tr", { className: "yable-tr", children: footerGroup.headers.map((header) => {
|
|
@@ -2435,11 +2853,11 @@ function ContextMenu({
|
|
|
2435
2853
|
}
|
|
2436
2854
|
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
2437
2855
|
e.preventDefault();
|
|
2438
|
-
const items2 = menuRef.current?.querySelectorAll(
|
|
2439
|
-
|
|
2440
|
-
const currentIndex = Array.from(items2).findIndex(
|
|
2441
|
-
(el) => el === document.activeElement
|
|
2856
|
+
const items2 = menuRef.current?.querySelectorAll(
|
|
2857
|
+
'[role="menuitem"]:not([aria-disabled="true"])'
|
|
2442
2858
|
);
|
|
2859
|
+
if (!items2 || items2.length === 0) return;
|
|
2860
|
+
const currentIndex = Array.from(items2).findIndex((el) => el === document.activeElement);
|
|
2443
2861
|
let nextIndex;
|
|
2444
2862
|
if (e.key === "ArrowDown") {
|
|
2445
2863
|
nextIndex = currentIndex < items2.length - 1 ? currentIndex + 1 : 0;
|
|
@@ -2484,11 +2902,7 @@ function ContextMenu({
|
|
|
2484
2902
|
navigator.clipboard?.readText().then((text) => {
|
|
2485
2903
|
const editing = table.getState().editing;
|
|
2486
2904
|
if (editing?.activeCell) {
|
|
2487
|
-
table.pasteFromClipboard(
|
|
2488
|
-
text,
|
|
2489
|
-
editing.activeCell.rowId,
|
|
2490
|
-
editing.activeCell.columnId
|
|
2491
|
-
);
|
|
2905
|
+
table.pasteFromClipboard(text, editing.activeCell.rowId, editing.activeCell.columnId);
|
|
2492
2906
|
}
|
|
2493
2907
|
}).catch(() => {
|
|
2494
2908
|
});
|
|
@@ -2828,6 +3242,12 @@ function isEditableTarget(element) {
|
|
|
2828
3242
|
}
|
|
2829
3243
|
return element.isContentEditable;
|
|
2830
3244
|
}
|
|
3245
|
+
function filterHeaderGroups(groups, visibleColumnIds) {
|
|
3246
|
+
return groups.map((group) => ({
|
|
3247
|
+
...group,
|
|
3248
|
+
headers: group.headers.filter((header) => visibleColumnIds.has(header.column.id))
|
|
3249
|
+
})).filter((group) => group.headers.length > 0);
|
|
3250
|
+
}
|
|
2831
3251
|
function Table({
|
|
2832
3252
|
table,
|
|
2833
3253
|
stickyHeader,
|
|
@@ -2854,6 +3274,10 @@ function Table({
|
|
|
2854
3274
|
sidebar,
|
|
2855
3275
|
sidebarPanels = ["columns", "filters"],
|
|
2856
3276
|
defaultSidebarPanel,
|
|
3277
|
+
floatingFilters,
|
|
3278
|
+
columnVirtualization,
|
|
3279
|
+
columnVirtualizationOverscan,
|
|
3280
|
+
ariaLabel,
|
|
2857
3281
|
...rest
|
|
2858
3282
|
}) {
|
|
2859
3283
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
@@ -2861,6 +3285,7 @@ function Table({
|
|
|
2861
3285
|
defaultSidebarPanel ?? "columns"
|
|
2862
3286
|
);
|
|
2863
3287
|
const containerRef = useRef(null);
|
|
3288
|
+
const horizontalScrollRef = useRef(null);
|
|
2864
3289
|
const isRtl = direction === "rtl";
|
|
2865
3290
|
const classNames = [
|
|
2866
3291
|
"yable",
|
|
@@ -2878,8 +3303,86 @@ function Table({
|
|
|
2878
3303
|
const hasGlobalFilter = Boolean(table.getState().globalFilter);
|
|
2879
3304
|
const hasColumnFilters = table.getState().columnFilters.length > 0;
|
|
2880
3305
|
const isFiltered = hasGlobalFilter || hasColumnFilters;
|
|
3306
|
+
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
3307
|
+
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
3308
|
+
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
3309
|
+
const canVirtualizeColumns = Boolean(columnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
3310
|
+
const columnVirtualState = useColumnVirtualization({
|
|
3311
|
+
containerRef: horizontalScrollRef,
|
|
3312
|
+
columns: allVisibleColumns,
|
|
3313
|
+
overscan: columnVirtualizationOverscan ?? 2,
|
|
3314
|
+
enabled: canVirtualizeColumns
|
|
3315
|
+
});
|
|
3316
|
+
const renderTable = useMemo(() => {
|
|
3317
|
+
if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
|
|
3318
|
+
return table;
|
|
3319
|
+
}
|
|
3320
|
+
const virtualColumns = columnVirtualState.virtualColumns.map((entry) => entry.column);
|
|
3321
|
+
const visibleColumnIds = new Set(virtualColumns.map((column) => column.id));
|
|
3322
|
+
const next = Object.create(table);
|
|
3323
|
+
next.getVisibleFlatColumns = () => virtualColumns;
|
|
3324
|
+
next.getVisibleLeafColumns = () => virtualColumns;
|
|
3325
|
+
next.getCenterVisibleLeafColumns = () => virtualColumns;
|
|
3326
|
+
next.getLeftVisibleLeafColumns = () => [];
|
|
3327
|
+
next.getRightVisibleLeafColumns = () => [];
|
|
3328
|
+
next.getHeaderGroups = () => filterHeaderGroups(table.getHeaderGroups(), visibleColumnIds);
|
|
3329
|
+
next.getCenterHeaderGroups = () => filterHeaderGroups(table.getCenterHeaderGroups(), visibleColumnIds);
|
|
3330
|
+
next.getFooterGroups = () => filterHeaderGroups(table.getFooterGroups(), visibleColumnIds);
|
|
3331
|
+
next.getCenterFooterGroups = () => filterHeaderGroups(table.getCenterFooterGroups(), visibleColumnIds);
|
|
3332
|
+
return next;
|
|
3333
|
+
}, [
|
|
3334
|
+
canVirtualizeColumns,
|
|
3335
|
+
columnVirtualState.isVirtualized,
|
|
3336
|
+
columnVirtualState.virtualColumns,
|
|
3337
|
+
table
|
|
3338
|
+
]);
|
|
3339
|
+
const showColumnVirtualizationShell = canVirtualizeColumns;
|
|
2881
3340
|
const contextMenu = useContextMenu();
|
|
2882
3341
|
useKeyboardNavigation(table, { containerRef });
|
|
3342
|
+
const [announcement, setAnnouncement] = useState("");
|
|
3343
|
+
const prevSortingRef = useRef(table.getState().sorting);
|
|
3344
|
+
const prevFilterCountRef = useRef(rows.length);
|
|
3345
|
+
const prevHasFiltersRef = useRef(isFiltered);
|
|
3346
|
+
const prevPaginationRef = useRef(table.getState().pagination);
|
|
3347
|
+
const isFirstRenderRef = useRef(true);
|
|
3348
|
+
useEffect(() => {
|
|
3349
|
+
if (isFirstRenderRef.current) {
|
|
3350
|
+
isFirstRenderRef.current = false;
|
|
3351
|
+
return;
|
|
3352
|
+
}
|
|
3353
|
+
const currentSorting = table.getState().sorting;
|
|
3354
|
+
const currentPagination = table.getState().pagination;
|
|
3355
|
+
const currentRowCount = rows.length;
|
|
3356
|
+
const currentIsFiltered = isFiltered;
|
|
3357
|
+
if (JSON.stringify(currentSorting) !== JSON.stringify(prevSortingRef.current)) {
|
|
3358
|
+
prevSortingRef.current = currentSorting;
|
|
3359
|
+
const firstSort = currentSorting[0];
|
|
3360
|
+
if (firstSort) {
|
|
3361
|
+
const column = table.getColumn(firstSort.id);
|
|
3362
|
+
const headerDef = column?.columnDef.header;
|
|
3363
|
+
const columnName = typeof headerDef === "string" ? headerDef : firstSort.id;
|
|
3364
|
+
const direction2 = firstSort.desc ? "descending" : "ascending";
|
|
3365
|
+
setAnnouncement(`Sorted by ${columnName} ${direction2}`);
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
if (currentRowCount !== prevFilterCountRef.current || currentIsFiltered !== prevHasFiltersRef.current) {
|
|
3370
|
+
prevFilterCountRef.current = currentRowCount;
|
|
3371
|
+
prevHasFiltersRef.current = currentIsFiltered;
|
|
3372
|
+
if (currentIsFiltered) {
|
|
3373
|
+
setAnnouncement(`${currentRowCount} rows after filtering`);
|
|
3374
|
+
return;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
if (JSON.stringify(currentPagination) !== JSON.stringify(prevPaginationRef.current)) {
|
|
3378
|
+
prevPaginationRef.current = currentPagination;
|
|
3379
|
+
const pageCount = table.getPageCount();
|
|
3380
|
+
if (pageCount > 0) {
|
|
3381
|
+
setAnnouncement(`Page ${currentPagination.pageIndex + 1} of ${pageCount}`);
|
|
3382
|
+
return;
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
});
|
|
2883
3386
|
const handleContextMenu = useCallback(
|
|
2884
3387
|
(e) => {
|
|
2885
3388
|
e.preventDefault();
|
|
@@ -2887,6 +3390,24 @@ function Table({
|
|
|
2887
3390
|
},
|
|
2888
3391
|
[contextMenu, table]
|
|
2889
3392
|
);
|
|
3393
|
+
const tableNode = /* @__PURE__ */ jsxs(
|
|
3394
|
+
"table",
|
|
3395
|
+
{
|
|
3396
|
+
className: "yable-table",
|
|
3397
|
+
style: columnVirtualState.isVirtualized ? {
|
|
3398
|
+
width: columnVirtualState.visibleWidth,
|
|
3399
|
+
minWidth: columnVirtualState.visibleWidth,
|
|
3400
|
+
marginLeft: columnVirtualState.startOffset,
|
|
3401
|
+
tableLayout: "fixed"
|
|
3402
|
+
} : void 0,
|
|
3403
|
+
"data-column-virtualized": columnVirtualState.isVirtualized || void 0,
|
|
3404
|
+
children: [
|
|
3405
|
+
/* @__PURE__ */ jsx(TableHeader, { table: renderTable, floatingFilters }),
|
|
3406
|
+
/* @__PURE__ */ jsx(TableBody, { table: renderTable, clickableRows }),
|
|
3407
|
+
footer && /* @__PURE__ */ jsx(TableFooter, { table: renderTable })
|
|
3408
|
+
]
|
|
3409
|
+
}
|
|
3410
|
+
);
|
|
2890
3411
|
return /* @__PURE__ */ jsx(TableProvider, { value: table, children: /* @__PURE__ */ jsxs(
|
|
2891
3412
|
"div",
|
|
2892
3413
|
{
|
|
@@ -2895,23 +3416,40 @@ function Table({
|
|
|
2895
3416
|
"data-theme": theme,
|
|
2896
3417
|
dir: direction,
|
|
2897
3418
|
role: "grid",
|
|
3419
|
+
"aria-label": ariaLabel ?? "Data table",
|
|
2898
3420
|
"aria-rowcount": table.getRowModel().rows.length,
|
|
2899
3421
|
"aria-colcount": table.getVisibleLeafColumns().length,
|
|
2900
3422
|
onContextMenu: handleContextMenu,
|
|
2901
3423
|
...rest,
|
|
2902
3424
|
children: [
|
|
2903
3425
|
/* @__PURE__ */ jsxs("div", { className: "yable-main", children: [
|
|
2904
|
-
/* @__PURE__ */
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3426
|
+
showColumnVirtualizationShell ? /* @__PURE__ */ jsx(
|
|
3427
|
+
"div",
|
|
3428
|
+
{
|
|
3429
|
+
ref: horizontalScrollRef,
|
|
3430
|
+
className: "yable-horizontal-scroll-container",
|
|
3431
|
+
style: {
|
|
3432
|
+
overflowX: "auto",
|
|
3433
|
+
overflowY: "visible",
|
|
3434
|
+
maxWidth: "100%",
|
|
3435
|
+
position: "relative"
|
|
3436
|
+
},
|
|
3437
|
+
children: /* @__PURE__ */ jsx(
|
|
3438
|
+
"div",
|
|
3439
|
+
{
|
|
3440
|
+
className: "yable-horizontal-scroll-inner",
|
|
3441
|
+
style: {
|
|
3442
|
+
width: Math.max(columnVirtualState.totalWidth, columnVirtualState.visibleWidth),
|
|
3443
|
+
minWidth: Math.max(
|
|
3444
|
+
columnVirtualState.totalWidth,
|
|
3445
|
+
columnVirtualState.visibleWidth
|
|
3446
|
+
)
|
|
3447
|
+
},
|
|
3448
|
+
children: tableNode
|
|
3449
|
+
}
|
|
3450
|
+
)
|
|
3451
|
+
}
|
|
3452
|
+
) : tableNode,
|
|
2915
3453
|
/* @__PURE__ */ jsx(
|
|
2916
3454
|
LoadingOverlay,
|
|
2917
3455
|
{
|
|
@@ -2952,6 +3490,24 @@ function Table({
|
|
|
2952
3490
|
onClose: contextMenu.close,
|
|
2953
3491
|
table
|
|
2954
3492
|
}
|
|
3493
|
+
),
|
|
3494
|
+
/* @__PURE__ */ jsx(
|
|
3495
|
+
"div",
|
|
3496
|
+
{
|
|
3497
|
+
role: "status",
|
|
3498
|
+
"aria-live": "polite",
|
|
3499
|
+
"aria-atomic": "true",
|
|
3500
|
+
style: {
|
|
3501
|
+
position: "absolute",
|
|
3502
|
+
width: "1px",
|
|
3503
|
+
height: "1px",
|
|
3504
|
+
overflow: "hidden",
|
|
3505
|
+
clip: "rect(0,0,0,0)",
|
|
3506
|
+
whiteSpace: "nowrap",
|
|
3507
|
+
border: 0
|
|
3508
|
+
},
|
|
3509
|
+
children: announcement
|
|
3510
|
+
}
|
|
2955
3511
|
)
|
|
2956
3512
|
]
|
|
2957
3513
|
}
|
|
@@ -3417,14 +3973,7 @@ function formatDateValue(value, type) {
|
|
|
3417
3973
|
return String(value);
|
|
3418
3974
|
}
|
|
3419
3975
|
function useClipboard(table, options = {}) {
|
|
3420
|
-
const {
|
|
3421
|
-
enabled = true,
|
|
3422
|
-
containerRef,
|
|
3423
|
-
onCopy,
|
|
3424
|
-
onCut,
|
|
3425
|
-
onPaste,
|
|
3426
|
-
...clipboardOptions
|
|
3427
|
-
} = options;
|
|
3976
|
+
const { enabled = true, containerRef, onCopy, onCut, onPaste, ...clipboardOptions } = options;
|
|
3428
3977
|
const handleCopy = useCallback(
|
|
3429
3978
|
(e) => {
|
|
3430
3979
|
if (isEditableTarget2(e.target)) return;
|
|
@@ -3462,20 +4011,29 @@ function useClipboard(table, options = {}) {
|
|
|
3462
4011
|
targetRowId = state.editing.activeCell.rowId;
|
|
3463
4012
|
targetColumnId = state.editing.activeCell.columnId;
|
|
3464
4013
|
} else {
|
|
3465
|
-
const
|
|
3466
|
-
|
|
3467
|
-
);
|
|
3468
|
-
if (
|
|
3469
|
-
|
|
4014
|
+
const selectedRange = table.getCellSelectionRange();
|
|
4015
|
+
const rows = table.getRowModel().rows;
|
|
4016
|
+
const columns = table.getVisibleLeafColumns();
|
|
4017
|
+
if (selectedRange) {
|
|
4018
|
+
const startRowIndex = Math.min(selectedRange.start.rowIndex, selectedRange.end.rowIndex);
|
|
4019
|
+
const startColumnIndex = Math.min(
|
|
4020
|
+
selectedRange.start.columnIndex,
|
|
4021
|
+
selectedRange.end.columnIndex
|
|
4022
|
+
);
|
|
4023
|
+
targetRowId = rows[startRowIndex]?.id;
|
|
4024
|
+
targetColumnId = columns[startColumnIndex]?.id;
|
|
3470
4025
|
} else {
|
|
3471
|
-
const
|
|
3472
|
-
|
|
4026
|
+
const selectedRowIds = Object.keys(state.rowSelection || {}).filter(
|
|
4027
|
+
(id) => state.rowSelection[id]
|
|
4028
|
+
);
|
|
4029
|
+
if (selectedRowIds.length > 0) {
|
|
4030
|
+
targetRowId = selectedRowIds[0];
|
|
4031
|
+
} else if (rows.length > 0) {
|
|
3473
4032
|
targetRowId = rows[0].id;
|
|
3474
4033
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
targetColumnId = columns[0].id;
|
|
4034
|
+
if (columns.length > 0) {
|
|
4035
|
+
targetColumnId = columns[0].id;
|
|
4036
|
+
}
|
|
3479
4037
|
}
|
|
3480
4038
|
}
|
|
3481
4039
|
if (targetRowId && targetColumnId) {
|
|
@@ -4765,7 +5323,7 @@ function sanitizeCSS(css) {
|
|
|
4765
5323
|
sanitized = sanitized.replace(/javascript\s*:/gi, "/* javascript: removed */");
|
|
4766
5324
|
return sanitized;
|
|
4767
5325
|
}
|
|
4768
|
-
function usePrintLayout(
|
|
5326
|
+
function usePrintLayout(_table, options = {}) {
|
|
4769
5327
|
const { title, additionalCSS } = options;
|
|
4770
5328
|
const isPrintingRef = useRef(false);
|
|
4771
5329
|
const preparePrint = useCallback(() => {
|
|
@@ -4802,7 +5360,7 @@ function usePrintLayout(table, options = {}) {
|
|
|
4802
5360
|
requestAnimationFrame(() => {
|
|
4803
5361
|
window.print();
|
|
4804
5362
|
});
|
|
4805
|
-
}, [
|
|
5363
|
+
}, [title, additionalCSS]);
|
|
4806
5364
|
return {
|
|
4807
5365
|
preparePrint,
|
|
4808
5366
|
isPrinting: isPrintingRef.current
|
|
@@ -4854,6 +5412,6 @@ function useTheme(options = {}) {
|
|
|
4854
5412
|
};
|
|
4855
5413
|
}
|
|
4856
5414
|
|
|
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 };
|
|
5415
|
+
export { CellBadge, CellBoolean, CellCheckbox, CellCurrency, CellDate, CellDatePicker, CellErrorBoundary, CellInput, CellLink, CellNumeric, CellProgress, CellRating, CellSelect, CellStatus, CellStatusBadge, CellToggle, ColumnsPanel, ContextMenu, ContextMenuItem, DEFAULT_TEXT_RECIPE, DragHandle, ErrorBoundary, ExpandIcon, FillHandle, FiltersPanel, FlashCell, FloatingFilter, GlobalFilter, LoadingOverlay, MasterDetail, NoRowsOverlay, Pagination, PivotConfigPanel, PrintLayout, SetFilter, Sidebar, SortIndicator, StatusBar, StatusBarPanelComponent, Table, TableBody, TableCell, TableFooter, TableHeader, TableProvider, Tooltip, TreeToggle, getMeasureRecipeForCellType, getRegisteredCellTypes, resolveMeasureRecipe, useAutoMeasurements, useCellFlash, useClipboard, useColumnVirtualization, useContextMenu, useFillHandle, useKeyboardNavigation, usePretextMeasurement, usePrintLayout, useRowAnimation, useRowDrag, useTable, useTableContext, useTableRowHeights, useTheme, useTooltip, useVirtualization };
|
|
4858
5416
|
//# sourceMappingURL=index.js.map
|
|
4859
5417
|
//# sourceMappingURL=index.js.map
|