@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.cjs
CHANGED
|
@@ -215,7 +215,15 @@ function useVirtualization({
|
|
|
215
215
|
container.scrollTop = offset;
|
|
216
216
|
}
|
|
217
217
|
},
|
|
218
|
-
[
|
|
218
|
+
[
|
|
219
|
+
containerRef,
|
|
220
|
+
totalRows,
|
|
221
|
+
rowHeight,
|
|
222
|
+
isFixedHeight,
|
|
223
|
+
getRowHeight,
|
|
224
|
+
hasPretextHeights,
|
|
225
|
+
pretextPrefixSums
|
|
226
|
+
]
|
|
219
227
|
);
|
|
220
228
|
const totalHeight = React3.useMemo(() => {
|
|
221
229
|
if (totalRows === 0) return 0;
|
|
@@ -269,10 +277,7 @@ function useVirtualization({
|
|
|
269
277
|
} else if (isFixedHeight) {
|
|
270
278
|
const fixedH = rowHeight;
|
|
271
279
|
startIndex = Math.floor(scrollTop / fixedH);
|
|
272
|
-
endIndex = Math.min(
|
|
273
|
-
totalRows - 1,
|
|
274
|
-
Math.ceil((scrollTop + containerHeight) / fixedH) - 1
|
|
275
|
-
);
|
|
280
|
+
endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / fixedH) - 1);
|
|
276
281
|
} else {
|
|
277
282
|
let accum = 0;
|
|
278
283
|
let foundStart = false;
|
|
@@ -339,6 +344,162 @@ function useVirtualization({
|
|
|
339
344
|
scrollTo
|
|
340
345
|
};
|
|
341
346
|
}
|
|
347
|
+
function binarySearchOffsets(offsets, target) {
|
|
348
|
+
let low = 0;
|
|
349
|
+
let high = offsets.length - 1;
|
|
350
|
+
while (low < high) {
|
|
351
|
+
const mid = low + high >>> 1;
|
|
352
|
+
if (offsets[mid + 1] <= target) {
|
|
353
|
+
low = mid + 1;
|
|
354
|
+
} else {
|
|
355
|
+
high = mid;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return low;
|
|
359
|
+
}
|
|
360
|
+
function useColumnVirtualization({
|
|
361
|
+
containerRef,
|
|
362
|
+
columns,
|
|
363
|
+
overscan = 2,
|
|
364
|
+
enabled = true
|
|
365
|
+
}) {
|
|
366
|
+
const [scrollState, setScrollState] = React3.useState({
|
|
367
|
+
scrollLeft: 0,
|
|
368
|
+
containerWidth: 0
|
|
369
|
+
});
|
|
370
|
+
const rafRef = React3.useRef(null);
|
|
371
|
+
const sizes = React3.useMemo(() => columns.map((column) => column.getSize()), [columns]);
|
|
372
|
+
const offsets = React3.useMemo(() => {
|
|
373
|
+
const next = new Array(columns.length + 1);
|
|
374
|
+
next[0] = 0;
|
|
375
|
+
for (let i = 0; i < columns.length; i++) {
|
|
376
|
+
next[i + 1] = next[i] + (sizes[i] ?? 0);
|
|
377
|
+
}
|
|
378
|
+
return next;
|
|
379
|
+
}, [columns.length, sizes]);
|
|
380
|
+
const totalWidth = offsets[offsets.length - 1] ?? 0;
|
|
381
|
+
React3.useEffect(() => {
|
|
382
|
+
const container = containerRef.current;
|
|
383
|
+
if (!container) return;
|
|
384
|
+
setScrollState({
|
|
385
|
+
scrollLeft: container.scrollLeft,
|
|
386
|
+
containerWidth: container.clientWidth
|
|
387
|
+
});
|
|
388
|
+
const handleScroll = () => {
|
|
389
|
+
if (rafRef.current !== null) return;
|
|
390
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
391
|
+
rafRef.current = null;
|
|
392
|
+
const el = containerRef.current;
|
|
393
|
+
if (!el) return;
|
|
394
|
+
setScrollState({
|
|
395
|
+
scrollLeft: el.scrollLeft,
|
|
396
|
+
containerWidth: el.clientWidth
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
401
|
+
let resizeObserver;
|
|
402
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
403
|
+
resizeObserver = new ResizeObserver(() => {
|
|
404
|
+
const el = containerRef.current;
|
|
405
|
+
if (!el) return;
|
|
406
|
+
setScrollState((prev) => {
|
|
407
|
+
const nextWidth = el.clientWidth;
|
|
408
|
+
if (prev.containerWidth === nextWidth && prev.scrollLeft === el.scrollLeft) {
|
|
409
|
+
return prev;
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
scrollLeft: el.scrollLeft,
|
|
413
|
+
containerWidth: nextWidth
|
|
414
|
+
};
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
resizeObserver.observe(container);
|
|
418
|
+
}
|
|
419
|
+
return () => {
|
|
420
|
+
container.removeEventListener("scroll", handleScroll);
|
|
421
|
+
if (rafRef.current !== null) {
|
|
422
|
+
cancelAnimationFrame(rafRef.current);
|
|
423
|
+
rafRef.current = null;
|
|
424
|
+
}
|
|
425
|
+
resizeObserver?.disconnect();
|
|
426
|
+
};
|
|
427
|
+
}, [containerRef]);
|
|
428
|
+
const scrollToIndex = React3.useCallback(
|
|
429
|
+
(index) => {
|
|
430
|
+
const container = containerRef.current;
|
|
431
|
+
if (!container || columns.length === 0) return;
|
|
432
|
+
const clampedIndex = Math.max(0, Math.min(index, columns.length - 1));
|
|
433
|
+
container.scrollLeft = offsets[clampedIndex] ?? 0;
|
|
434
|
+
},
|
|
435
|
+
[columns.length, containerRef, offsets]
|
|
436
|
+
);
|
|
437
|
+
if (!enabled || columns.length === 0) {
|
|
438
|
+
return {
|
|
439
|
+
virtualColumns: columns.map((column, index) => ({
|
|
440
|
+
column,
|
|
441
|
+
index,
|
|
442
|
+
start: offsets[index] ?? 0,
|
|
443
|
+
size: sizes[index] ?? 0
|
|
444
|
+
})),
|
|
445
|
+
startOffset: 0,
|
|
446
|
+
endOffset: 0,
|
|
447
|
+
totalWidth,
|
|
448
|
+
visibleWidth: totalWidth,
|
|
449
|
+
startIndex: 0,
|
|
450
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
451
|
+
isVirtualized: false,
|
|
452
|
+
scrollToIndex
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
const { scrollLeft, containerWidth } = scrollState;
|
|
456
|
+
if (containerWidth <= 0 || totalWidth <= containerWidth) {
|
|
457
|
+
return {
|
|
458
|
+
virtualColumns: columns.map((column, index) => ({
|
|
459
|
+
column,
|
|
460
|
+
index,
|
|
461
|
+
start: offsets[index] ?? 0,
|
|
462
|
+
size: sizes[index] ?? 0
|
|
463
|
+
})),
|
|
464
|
+
startOffset: 0,
|
|
465
|
+
endOffset: 0,
|
|
466
|
+
totalWidth,
|
|
467
|
+
visibleWidth: totalWidth,
|
|
468
|
+
startIndex: 0,
|
|
469
|
+
endIndex: Math.max(columns.length - 1, 0),
|
|
470
|
+
isVirtualized: false,
|
|
471
|
+
scrollToIndex
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
const startIndex = binarySearchOffsets(offsets, scrollLeft);
|
|
475
|
+
const endBoundary = scrollLeft + containerWidth;
|
|
476
|
+
const endIndex = binarySearchOffsets(offsets, Math.max(scrollLeft, endBoundary - 1));
|
|
477
|
+
const overscanStart = Math.max(0, startIndex - overscan);
|
|
478
|
+
const overscanEnd = Math.min(columns.length - 1, endIndex + overscan);
|
|
479
|
+
const virtualColumns = [];
|
|
480
|
+
for (let i = overscanStart; i <= overscanEnd; i++) {
|
|
481
|
+
virtualColumns.push({
|
|
482
|
+
column: columns[i],
|
|
483
|
+
index: i,
|
|
484
|
+
start: offsets[i] ?? 0,
|
|
485
|
+
size: sizes[i] ?? 0
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
const startOffset = offsets[overscanStart] ?? 0;
|
|
489
|
+
const visibleWidth = (offsets[overscanEnd + 1] ?? totalWidth) - startOffset;
|
|
490
|
+
const endOffset = totalWidth - (offsets[overscanEnd + 1] ?? totalWidth);
|
|
491
|
+
return {
|
|
492
|
+
virtualColumns,
|
|
493
|
+
startOffset,
|
|
494
|
+
endOffset,
|
|
495
|
+
totalWidth,
|
|
496
|
+
visibleWidth,
|
|
497
|
+
startIndex: overscanStart,
|
|
498
|
+
endIndex: overscanEnd,
|
|
499
|
+
isVirtualized: true,
|
|
500
|
+
scrollToIndex
|
|
501
|
+
};
|
|
502
|
+
}
|
|
342
503
|
var pretextPromise = null;
|
|
343
504
|
function loadPretext() {
|
|
344
505
|
if (pretextPromise) return pretextPromise;
|
|
@@ -389,7 +550,12 @@ function usePretextMeasurement({
|
|
|
389
550
|
}
|
|
390
551
|
prepareTimeRef.current = performance.now() - start;
|
|
391
552
|
return result;
|
|
392
|
-
}, [
|
|
553
|
+
}, [
|
|
554
|
+
pretext,
|
|
555
|
+
enabled,
|
|
556
|
+
data,
|
|
557
|
+
columns.map((c) => `${c.columnId}:${c.font}:${c.fixedHeight ? "F" : "T"}`).join("|")
|
|
558
|
+
]);
|
|
393
559
|
const measurement = React3.useMemo(() => {
|
|
394
560
|
if (!pretext || !preparedCells) {
|
|
395
561
|
return { rowHeights: null, prefixSums: null, totalHeight: 0 };
|
|
@@ -427,6 +593,7 @@ function usePretextMeasurement({
|
|
|
427
593
|
return {
|
|
428
594
|
rowHeights,
|
|
429
595
|
prefixSums,
|
|
596
|
+
// Safe: prefixSums has length data.length + 1, so [data.length] always exists
|
|
430
597
|
totalHeight: prefixSums[data.length]
|
|
431
598
|
};
|
|
432
599
|
}, [pretext, preparedCells, columnWidthsKey, minRowHeight, data.length]);
|
|
@@ -691,18 +858,10 @@ function CellDate({
|
|
|
691
858
|
if (raw == null) return null;
|
|
692
859
|
const date = raw instanceof Date ? raw : new Date(String(raw));
|
|
693
860
|
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]);
|
|
861
|
+
const formatter = typeof format === "string" && format !== "relative" ? new Intl.DateTimeFormat(locale, {
|
|
862
|
+
...PRESETS[format],
|
|
863
|
+
timeZone: "UTC"
|
|
864
|
+
}) : typeof format === "object" ? new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" }) : null;
|
|
706
865
|
const formatted = format === "relative" ? formatRelative(date) : formatter ? formatter.format(date) : date.toLocaleDateString(locale);
|
|
707
866
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `yable-cell-date ${className ?? ""}`, title: date.toISOString(), children: formatted });
|
|
708
867
|
}
|
|
@@ -713,8 +872,14 @@ var measureRecipe9 = {
|
|
|
713
872
|
padding: 20
|
|
714
873
|
};
|
|
715
874
|
function isSafeUrl(url) {
|
|
716
|
-
const normalized = String(url).
|
|
717
|
-
|
|
875
|
+
const normalized = String(url).trim();
|
|
876
|
+
if (/^[/#?]/.test(normalized)) return true;
|
|
877
|
+
try {
|
|
878
|
+
const parsed = new URL(normalized, "https://placeholder.invalid");
|
|
879
|
+
return ["http:", "https:", "mailto:", "tel:"].includes(parsed.protocol);
|
|
880
|
+
} catch {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
718
883
|
}
|
|
719
884
|
function CellLink({
|
|
720
885
|
context,
|
|
@@ -891,7 +1056,7 @@ function useTableContext() {
|
|
|
891
1056
|
const ctx = React3.useContext(TableContext);
|
|
892
1057
|
if (!ctx) {
|
|
893
1058
|
throw new Error(
|
|
894
|
-
"[yable] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
1059
|
+
"[yable E001] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
|
|
895
1060
|
);
|
|
896
1061
|
}
|
|
897
1062
|
return ctx;
|
|
@@ -941,12 +1106,234 @@ function SortIndicator({ direction, index }) {
|
|
|
941
1106
|
}
|
|
942
1107
|
);
|
|
943
1108
|
}
|
|
1109
|
+
function formatValue(value) {
|
|
1110
|
+
if (value == null || value === "") return "(empty)";
|
|
1111
|
+
if (typeof value === "string") return value;
|
|
1112
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1113
|
+
if (value instanceof Date) return value.toISOString();
|
|
1114
|
+
return JSON.stringify(value);
|
|
1115
|
+
}
|
|
1116
|
+
function SetFilter({ column, className }) {
|
|
1117
|
+
const [open, setOpen] = React3.useState(false);
|
|
1118
|
+
const filterValue = column.getFilterValue();
|
|
1119
|
+
const selectedValues = Array.isArray(filterValue) ? filterValue : filterValue == null || filterValue === "" ? [] : [filterValue];
|
|
1120
|
+
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
1121
|
+
const options = Array.from(facetedUniqueValues.entries()).map(([value, count]) => ({
|
|
1122
|
+
value,
|
|
1123
|
+
count,
|
|
1124
|
+
label: formatValue(value)
|
|
1125
|
+
})).sort((a, b) => a.label.localeCompare(b.label));
|
|
1126
|
+
const selectedSet = new Set(selectedValues);
|
|
1127
|
+
const toggleValue = (value) => {
|
|
1128
|
+
const next = new Set(selectedSet);
|
|
1129
|
+
if (next.has(value)) {
|
|
1130
|
+
next.delete(value);
|
|
1131
|
+
} else {
|
|
1132
|
+
next.add(value);
|
|
1133
|
+
}
|
|
1134
|
+
const nextValues = Array.from(next);
|
|
1135
|
+
column.setFilterValue(nextValues.length > 0 ? nextValues : void 0);
|
|
1136
|
+
};
|
|
1137
|
+
const headerLabel = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1138
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1139
|
+
"div",
|
|
1140
|
+
{
|
|
1141
|
+
className: ["yable-set-filter", className].filter(Boolean).join(" "),
|
|
1142
|
+
style: { position: "relative" },
|
|
1143
|
+
children: [
|
|
1144
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1145
|
+
"button",
|
|
1146
|
+
{
|
|
1147
|
+
type: "button",
|
|
1148
|
+
className: "yable-set-filter-trigger",
|
|
1149
|
+
"aria-haspopup": "dialog",
|
|
1150
|
+
"aria-expanded": open,
|
|
1151
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1152
|
+
style: {
|
|
1153
|
+
width: "100%",
|
|
1154
|
+
minHeight: 28,
|
|
1155
|
+
padding: "4px 8px",
|
|
1156
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1157
|
+
borderRadius: 6,
|
|
1158
|
+
background: "transparent",
|
|
1159
|
+
font: "inherit",
|
|
1160
|
+
textAlign: "left",
|
|
1161
|
+
cursor: "pointer"
|
|
1162
|
+
},
|
|
1163
|
+
children: selectedValues.length > 0 ? `${selectedValues.length} selected` : `Filter ${headerLabel}`
|
|
1164
|
+
}
|
|
1165
|
+
),
|
|
1166
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1167
|
+
"div",
|
|
1168
|
+
{
|
|
1169
|
+
role: "dialog",
|
|
1170
|
+
"aria-label": `${headerLabel} set filter`,
|
|
1171
|
+
className: "yable-set-filter-popover",
|
|
1172
|
+
style: {
|
|
1173
|
+
position: "absolute",
|
|
1174
|
+
insetInlineStart: 0,
|
|
1175
|
+
top: "calc(100% + 4px)",
|
|
1176
|
+
zIndex: 20,
|
|
1177
|
+
width: 220,
|
|
1178
|
+
maxHeight: 240,
|
|
1179
|
+
overflow: "auto",
|
|
1180
|
+
padding: 8,
|
|
1181
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1182
|
+
borderRadius: 8,
|
|
1183
|
+
background: "var(--yable-color-bg, #fff)",
|
|
1184
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.12)"
|
|
1185
|
+
},
|
|
1186
|
+
children: [
|
|
1187
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1188
|
+
"div",
|
|
1189
|
+
{
|
|
1190
|
+
style: {
|
|
1191
|
+
display: "flex",
|
|
1192
|
+
alignItems: "center",
|
|
1193
|
+
justifyContent: "space-between",
|
|
1194
|
+
gap: 8,
|
|
1195
|
+
marginBottom: 8
|
|
1196
|
+
},
|
|
1197
|
+
children: [
|
|
1198
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: 12 }, children: headerLabel }),
|
|
1199
|
+
selectedValues.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1200
|
+
"button",
|
|
1201
|
+
{
|
|
1202
|
+
type: "button",
|
|
1203
|
+
onClick: () => column.setFilterValue(void 0),
|
|
1204
|
+
style: {
|
|
1205
|
+
border: "none",
|
|
1206
|
+
background: "transparent",
|
|
1207
|
+
padding: 0,
|
|
1208
|
+
cursor: "pointer",
|
|
1209
|
+
fontSize: 12
|
|
1210
|
+
},
|
|
1211
|
+
children: "Clear"
|
|
1212
|
+
}
|
|
1213
|
+
)
|
|
1214
|
+
]
|
|
1215
|
+
}
|
|
1216
|
+
),
|
|
1217
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": `${headerLabel} options`, children: [
|
|
1218
|
+
options.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, opacity: 0.75 }, children: "No values" }),
|
|
1219
|
+
options.map((option) => {
|
|
1220
|
+
const checked = selectedSet.has(option.value);
|
|
1221
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1222
|
+
"label",
|
|
1223
|
+
{
|
|
1224
|
+
style: {
|
|
1225
|
+
display: "flex",
|
|
1226
|
+
alignItems: "center",
|
|
1227
|
+
gap: 8,
|
|
1228
|
+
padding: "4px 0",
|
|
1229
|
+
fontSize: 12
|
|
1230
|
+
},
|
|
1231
|
+
children: [
|
|
1232
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1233
|
+
"input",
|
|
1234
|
+
{
|
|
1235
|
+
type: "checkbox",
|
|
1236
|
+
checked,
|
|
1237
|
+
onChange: () => toggleValue(option.value)
|
|
1238
|
+
}
|
|
1239
|
+
),
|
|
1240
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1 }, children: option.label }),
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { opacity: 0.6 }, children: option.count })
|
|
1242
|
+
]
|
|
1243
|
+
},
|
|
1244
|
+
`${option.label}-${option.count}`
|
|
1245
|
+
);
|
|
1246
|
+
})
|
|
1247
|
+
] })
|
|
1248
|
+
]
|
|
1249
|
+
}
|
|
1250
|
+
)
|
|
1251
|
+
]
|
|
1252
|
+
}
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
function isSetCompatibleValue(value) {
|
|
1256
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1257
|
+
}
|
|
1258
|
+
function inferFilterVariant(column) {
|
|
1259
|
+
const meta = column.columnDef.meta ?? {};
|
|
1260
|
+
if (meta.filterVariant) return meta.filterVariant;
|
|
1261
|
+
const uniqueValues = column.getFacetedUniqueValues();
|
|
1262
|
+
if (uniqueValues.size > 0 && uniqueValues.size <= 12) {
|
|
1263
|
+
const allValuesSupported = Array.from(uniqueValues.keys()).every(isSetCompatibleValue);
|
|
1264
|
+
if (allValuesSupported) return "set";
|
|
1265
|
+
}
|
|
1266
|
+
return "text";
|
|
1267
|
+
}
|
|
1268
|
+
function FloatingFilter({ column }) {
|
|
1269
|
+
const variant = inferFilterVariant(column);
|
|
1270
|
+
if (!column.getCanFilter()) {
|
|
1271
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minHeight: 28 }, "aria-hidden": "true" });
|
|
1272
|
+
}
|
|
1273
|
+
if (variant === "set") {
|
|
1274
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SetFilter, { column });
|
|
1275
|
+
}
|
|
1276
|
+
const filterValue = column.getFilterValue();
|
|
1277
|
+
const normalizedValue = typeof filterValue === "string" || typeof filterValue === "number" ? String(filterValue) : "";
|
|
1278
|
+
const label = typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
|
|
1279
|
+
return /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1280
|
+
"input",
|
|
1281
|
+
{
|
|
1282
|
+
"aria-label": `Filter ${label}`,
|
|
1283
|
+
className: "yable-floating-filter-input",
|
|
1284
|
+
value: normalizedValue,
|
|
1285
|
+
onChange: (event) => {
|
|
1286
|
+
const nextValue = event.target.value;
|
|
1287
|
+
column.setFilterValue(nextValue === "" ? void 0 : nextValue);
|
|
1288
|
+
},
|
|
1289
|
+
placeholder: `Filter ${label}`,
|
|
1290
|
+
style: {
|
|
1291
|
+
width: "100%",
|
|
1292
|
+
minHeight: 28,
|
|
1293
|
+
padding: "4px 8px",
|
|
1294
|
+
border: "1px solid rgba(127, 127, 127, 0.35)",
|
|
1295
|
+
borderRadius: 6,
|
|
1296
|
+
background: "transparent",
|
|
1297
|
+
font: "inherit"
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
) });
|
|
1301
|
+
}
|
|
944
1302
|
var DRAG_MIME = "application/yable-column";
|
|
945
1303
|
function TableHeader({
|
|
946
|
-
table
|
|
1304
|
+
table,
|
|
1305
|
+
floatingFilters = false
|
|
947
1306
|
}) {
|
|
948
1307
|
const headerGroups = table.getHeaderGroups();
|
|
949
|
-
|
|
1308
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
1309
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("thead", { className: "yable-thead", children: [
|
|
1310
|
+
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)),
|
|
1311
|
+
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`)) })
|
|
1312
|
+
] });
|
|
1313
|
+
}
|
|
1314
|
+
function FloatingFilterCell({
|
|
1315
|
+
column
|
|
1316
|
+
}) {
|
|
1317
|
+
const style = React3.useMemo(() => {
|
|
1318
|
+
const next = {
|
|
1319
|
+
width: column.getSize(),
|
|
1320
|
+
minWidth: column.columnDef.minSize,
|
|
1321
|
+
maxWidth: column.columnDef.maxSize,
|
|
1322
|
+
padding: 6,
|
|
1323
|
+
verticalAlign: "top"
|
|
1324
|
+
};
|
|
1325
|
+
const pinned = column.getIsPinned();
|
|
1326
|
+
if (pinned) {
|
|
1327
|
+
next.position = "sticky";
|
|
1328
|
+
if (pinned === "left") {
|
|
1329
|
+
next.left = column.getStart("left");
|
|
1330
|
+
} else {
|
|
1331
|
+
next.right = column.getStart("right");
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
return next;
|
|
1335
|
+
}, [column]);
|
|
1336
|
+
return /* @__PURE__ */ jsxRuntime.jsx("th", { className: "yable-th yable-th--filter", role: "columnheader", style, children: /* @__PURE__ */ jsxRuntime.jsx(FloatingFilter, { column }) });
|
|
950
1337
|
}
|
|
951
1338
|
function HeaderCell({
|
|
952
1339
|
header,
|
|
@@ -1035,14 +1422,11 @@ function HeaderCell({
|
|
|
1035
1422
|
},
|
|
1036
1423
|
[canReorder]
|
|
1037
1424
|
);
|
|
1038
|
-
const handleDragLeave = React3.useCallback(
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
},
|
|
1044
|
-
[]
|
|
1045
|
-
);
|
|
1425
|
+
const handleDragLeave = React3.useCallback((e) => {
|
|
1426
|
+
const next = e.relatedTarget;
|
|
1427
|
+
if (next && e.currentTarget.contains(next)) return;
|
|
1428
|
+
setDragOver(null);
|
|
1429
|
+
}, []);
|
|
1046
1430
|
const handleDragEnd = React3.useCallback(() => {
|
|
1047
1431
|
setDragOver(null);
|
|
1048
1432
|
}, []);
|
|
@@ -1115,13 +1499,7 @@ function HeaderCell({
|
|
|
1115
1499
|
children: [
|
|
1116
1500
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "yable-th-content", children: [
|
|
1117
1501
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: headerContent }),
|
|
1118
|
-
canSort && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1119
|
-
SortIndicator,
|
|
1120
|
-
{
|
|
1121
|
-
direction: sortDirection,
|
|
1122
|
-
index: sortIndex > 0 ? sortIndex : void 0
|
|
1123
|
-
}
|
|
1124
|
-
)
|
|
1502
|
+
canSort && /* @__PURE__ */ jsxRuntime.jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
|
|
1125
1503
|
] }),
|
|
1126
1504
|
canResize && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1127
1505
|
"div",
|
|
@@ -1246,6 +1624,10 @@ function TableCell({
|
|
|
1246
1624
|
const cellStatus = table.getCellStatus(cell.row.id, column.id);
|
|
1247
1625
|
const cellErrorMessage = table.getCellErrorMessage(cell.row.id, column.id);
|
|
1248
1626
|
const cellConflictWith = table.getCellConflictWith(cell.row.id, column.id);
|
|
1627
|
+
const selectionRange = table.getCellSelectionRange();
|
|
1628
|
+
const selectionEdges = table.getCellSelectionEdges(rowIndex, columnIndex);
|
|
1629
|
+
const isCellSelected = selectionEdges !== null;
|
|
1630
|
+
const isMultiCellSelection = selectionRange !== null && (selectionRange.start.rowIndex !== selectionRange.end.rowIndex || selectionRange.start.columnIndex !== selectionRange.end.columnIndex);
|
|
1249
1631
|
const overrideValue = cellStatus !== "idle" ? table.getCellRenderValue(cell.row.id, column.id) : void 0;
|
|
1250
1632
|
let content;
|
|
1251
1633
|
const cellDef = column.columnDef.cell;
|
|
@@ -1269,23 +1651,17 @@ function TableCell({
|
|
|
1269
1651
|
}
|
|
1270
1652
|
const handleClick = React3.useCallback(
|
|
1271
1653
|
(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
1654
|
table.events.emit("cell:click", {
|
|
1279
1655
|
cell,
|
|
1280
1656
|
row: cell.row,
|
|
1281
1657
|
column: cell.column,
|
|
1282
1658
|
event: e.nativeEvent
|
|
1283
1659
|
});
|
|
1284
|
-
if (yableCore.canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing) {
|
|
1660
|
+
if (yableCore.canCellEnterEditMode(table, cell.row, column) && !isAlwaysEditable && !isEditing && !isMultiCellSelection && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
1285
1661
|
table.startEditing(cell.row.id, column.id);
|
|
1286
1662
|
}
|
|
1287
1663
|
},
|
|
1288
|
-
[cell, column,
|
|
1664
|
+
[cell, column, isAlwaysEditable, isEditing, isMultiCellSelection, table]
|
|
1289
1665
|
);
|
|
1290
1666
|
const handleDoubleClick = React3.useCallback(
|
|
1291
1667
|
(e) => {
|
|
@@ -1313,9 +1689,34 @@ function TableCell({
|
|
|
1313
1689
|
if (!keyboardNavigationEnabled) return;
|
|
1314
1690
|
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1315
1691
|
}, [columnIndex, keyboardNavigationEnabled, rowIndex, table]);
|
|
1692
|
+
const handleMouseDown = React3.useCallback(
|
|
1693
|
+
(e) => {
|
|
1694
|
+
if (e.button !== 0) return;
|
|
1695
|
+
const clickTarget = e.target;
|
|
1696
|
+
if (isInteractiveClickTarget(clickTarget)) return;
|
|
1697
|
+
e.preventDefault();
|
|
1698
|
+
table.setFocusedCell({ rowIndex, columnIndex });
|
|
1699
|
+
table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
|
|
1700
|
+
e.currentTarget.focus({ preventScroll: true });
|
|
1701
|
+
},
|
|
1702
|
+
[columnIndex, rowIndex, table]
|
|
1703
|
+
);
|
|
1704
|
+
const handleMouseEnter = React3.useCallback(() => {
|
|
1705
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1706
|
+
table.updateCellRangeSelection({ rowIndex, columnIndex });
|
|
1707
|
+
}, [columnIndex, rowIndex, table]);
|
|
1708
|
+
const handleMouseUp = React3.useCallback(() => {
|
|
1709
|
+
if (!table.getState().cellSelection?.isDragging) return;
|
|
1710
|
+
table.endCellRangeSelection();
|
|
1711
|
+
}, [table]);
|
|
1316
1712
|
const classNames = [
|
|
1317
1713
|
"yable-td",
|
|
1318
|
-
isFocused && "yable-cell--focused"
|
|
1714
|
+
isFocused && "yable-cell--focused",
|
|
1715
|
+
isCellSelected && "yable-cell--selected",
|
|
1716
|
+
selectionEdges?.top && "yable-cell--selection-top",
|
|
1717
|
+
selectionEdges?.right && "yable-cell--selection-right",
|
|
1718
|
+
selectionEdges?.bottom && "yable-cell--selection-bottom",
|
|
1719
|
+
selectionEdges?.left && "yable-cell--selection-left"
|
|
1319
1720
|
].filter(Boolean).join(" ");
|
|
1320
1721
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1321
1722
|
"td",
|
|
@@ -1329,10 +1730,14 @@ function TableCell({
|
|
|
1329
1730
|
"data-column-id": column.id,
|
|
1330
1731
|
"data-row-index": rowIndex,
|
|
1331
1732
|
"data-column-index": columnIndex,
|
|
1733
|
+
"data-cell-selected": isCellSelected || void 0,
|
|
1332
1734
|
"aria-rowindex": rowIndex + 1,
|
|
1333
1735
|
"aria-colindex": columnIndex + 1,
|
|
1334
1736
|
role: "gridcell",
|
|
1335
1737
|
tabIndex: keyboardNavigationEnabled ? isTabStop ? 0 : -1 : void 0,
|
|
1738
|
+
onMouseDown: handleMouseDown,
|
|
1739
|
+
onMouseEnter: handleMouseEnter,
|
|
1740
|
+
onMouseUp: handleMouseUp,
|
|
1336
1741
|
onClick: handleClick,
|
|
1337
1742
|
onDoubleClick: handleDoubleClick,
|
|
1338
1743
|
onContextMenu: handleContextMenu,
|
|
@@ -1457,14 +1862,15 @@ var CellErrorBoundary = class extends React3__default.default.Component {
|
|
|
1457
1862
|
return this.props.children;
|
|
1458
1863
|
}
|
|
1459
1864
|
};
|
|
1460
|
-
function TableBody({
|
|
1461
|
-
table,
|
|
1462
|
-
clickableRows
|
|
1463
|
-
}) {
|
|
1865
|
+
function TableBody({ table, clickableRows }) {
|
|
1464
1866
|
const rows = table.getRowModel().rows;
|
|
1465
1867
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
1466
1868
|
const activeCell = table.getState().editing.activeCell;
|
|
1467
1869
|
const focusedCell = table.getFocusedCell();
|
|
1870
|
+
const cellSelection = table.getState().cellSelection ?? {
|
|
1871
|
+
range: null,
|
|
1872
|
+
isDragging: false
|
|
1873
|
+
};
|
|
1468
1874
|
const options = table.options;
|
|
1469
1875
|
const enableVirtualization = options.enableVirtualization ?? false;
|
|
1470
1876
|
const scrollContainerRef = React3.useRef(null);
|
|
@@ -1482,6 +1888,18 @@ function TableBody({
|
|
|
1482
1888
|
pretextHeights,
|
|
1483
1889
|
pretextPrefixSums
|
|
1484
1890
|
});
|
|
1891
|
+
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"}`;
|
|
1892
|
+
React3.useEffect(() => {
|
|
1893
|
+
const handleWindowMouseUp = () => {
|
|
1894
|
+
if (table.getState().cellSelection?.isDragging) {
|
|
1895
|
+
table.endCellRangeSelection();
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
window.addEventListener("mouseup", handleWindowMouseUp);
|
|
1899
|
+
return () => {
|
|
1900
|
+
window.removeEventListener("mouseup", handleWindowMouseUp);
|
|
1901
|
+
};
|
|
1902
|
+
}, [table]);
|
|
1485
1903
|
if (!enableVirtualization) {
|
|
1486
1904
|
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1487
1905
|
MemoizedTableRow,
|
|
@@ -1495,6 +1913,7 @@ function TableBody({
|
|
|
1495
1913
|
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1496
1914
|
focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
|
|
1497
1915
|
hasFocusedCell: focusedCell !== null,
|
|
1916
|
+
cellSelectionKey,
|
|
1498
1917
|
clickable: clickableRows
|
|
1499
1918
|
},
|
|
1500
1919
|
row.id
|
|
@@ -1503,73 +1922,67 @@ function TableBody({
|
|
|
1503
1922
|
const hasPretextData = !!(pretextHeights && pretextPrefixSums);
|
|
1504
1923
|
const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
|
|
1505
1924
|
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
|
-
"
|
|
1925
|
+
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(
|
|
1926
|
+
"div",
|
|
1508
1927
|
{
|
|
1509
|
-
|
|
1510
|
-
|
|
1928
|
+
ref: scrollContainerRef,
|
|
1929
|
+
className: "yable-virtual-scroll-container",
|
|
1930
|
+
style: {
|
|
1931
|
+
overflowY: "auto",
|
|
1932
|
+
height: containerHeight,
|
|
1933
|
+
position: "relative"
|
|
1934
|
+
},
|
|
1511
1935
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1512
1936
|
"div",
|
|
1513
1937
|
{
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
style: {
|
|
1517
|
-
overflowY: "auto",
|
|
1518
|
-
height: containerHeight,
|
|
1519
|
-
position: "relative"
|
|
1520
|
-
},
|
|
1938
|
+
className: "yable-virtual-spacer",
|
|
1939
|
+
style: { height: totalHeight, position: "relative" },
|
|
1521
1940
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1522
|
-
"
|
|
1941
|
+
"table",
|
|
1523
1942
|
{
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1943
|
+
style: {
|
|
1944
|
+
position: "absolute",
|
|
1945
|
+
top: 0,
|
|
1946
|
+
left: 0,
|
|
1947
|
+
width: "100%",
|
|
1948
|
+
tableLayout: "fixed",
|
|
1949
|
+
borderCollapse: "collapse"
|
|
1950
|
+
},
|
|
1951
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: virtualRows.map((vRow) => {
|
|
1952
|
+
const row = rows[vRow.index];
|
|
1953
|
+
if (!row) return null;
|
|
1954
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1955
|
+
MemoizedTableRow,
|
|
1956
|
+
{
|
|
1957
|
+
row,
|
|
1958
|
+
table,
|
|
1959
|
+
rowIndex: vRow.index,
|
|
1960
|
+
visibleColumns,
|
|
1961
|
+
isSelected: row.getIsSelected(),
|
|
1962
|
+
isExpanded: row.getIsExpanded(),
|
|
1963
|
+
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1964
|
+
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
1965
|
+
hasFocusedCell: focusedCell !== null,
|
|
1966
|
+
cellSelectionKey,
|
|
1967
|
+
clickable: clickableRows,
|
|
1968
|
+
virtualStyle: {
|
|
1969
|
+
position: "absolute",
|
|
1970
|
+
top: 0,
|
|
1971
|
+
left: 0,
|
|
1972
|
+
width: "100%",
|
|
1973
|
+
height: vRow.size,
|
|
1974
|
+
transform: `translateY(${vRow.start}px)`
|
|
1975
|
+
}
|
|
1536
1976
|
},
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1541
|
-
MemoizedTableRow,
|
|
1542
|
-
{
|
|
1543
|
-
row,
|
|
1544
|
-
table,
|
|
1545
|
-
rowIndex: vRow.index,
|
|
1546
|
-
visibleColumns,
|
|
1547
|
-
isSelected: row.getIsSelected(),
|
|
1548
|
-
isExpanded: row.getIsExpanded(),
|
|
1549
|
-
activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
|
|
1550
|
-
focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
|
|
1551
|
-
hasFocusedCell: focusedCell !== null,
|
|
1552
|
-
clickable: clickableRows,
|
|
1553
|
-
virtualStyle: {
|
|
1554
|
-
position: "absolute",
|
|
1555
|
-
top: 0,
|
|
1556
|
-
left: 0,
|
|
1557
|
-
width: "100%",
|
|
1558
|
-
height: vRow.size,
|
|
1559
|
-
transform: `translateY(${vRow.start}px)`
|
|
1560
|
-
}
|
|
1561
|
-
},
|
|
1562
|
-
row.id
|
|
1563
|
-
);
|
|
1564
|
-
}) })
|
|
1565
|
-
}
|
|
1566
|
-
)
|
|
1977
|
+
row.id
|
|
1978
|
+
);
|
|
1979
|
+
}) })
|
|
1567
1980
|
}
|
|
1568
1981
|
)
|
|
1569
1982
|
}
|
|
1570
1983
|
)
|
|
1571
1984
|
}
|
|
1572
|
-
) }) });
|
|
1985
|
+
) }) }) });
|
|
1573
1986
|
}
|
|
1574
1987
|
function TableRowInner({
|
|
1575
1988
|
row,
|
|
@@ -1581,10 +1994,12 @@ function TableRowInner({
|
|
|
1581
1994
|
activeColumnId,
|
|
1582
1995
|
focusedColumnIndex,
|
|
1583
1996
|
hasFocusedCell,
|
|
1997
|
+
cellSelectionKey: _cellSelectionKey,
|
|
1584
1998
|
clickable,
|
|
1585
1999
|
virtualStyle
|
|
1586
2000
|
}) {
|
|
1587
|
-
const
|
|
2001
|
+
const allCells = row.getAllCells();
|
|
2002
|
+
const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
|
|
1588
2003
|
const handleClick = React3.useCallback(
|
|
1589
2004
|
(e) => {
|
|
1590
2005
|
if (clickable) {
|
|
@@ -1614,6 +2029,8 @@ function TableRowInner({
|
|
|
1614
2029
|
},
|
|
1615
2030
|
[table.events, row]
|
|
1616
2031
|
);
|
|
2032
|
+
const selectionEnabled = Boolean(table.options.enableRowSelection);
|
|
2033
|
+
const expansionEnabled = Boolean(table.options.enableExpanding);
|
|
1617
2034
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1618
2035
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1619
2036
|
"tr",
|
|
@@ -1625,6 +2042,8 @@ function TableRowInner({
|
|
|
1625
2042
|
"data-clickable": clickable || void 0,
|
|
1626
2043
|
"data-row-id": row.id,
|
|
1627
2044
|
"data-row-index": rowIndex,
|
|
2045
|
+
"aria-selected": selectionEnabled ? isSelected : void 0,
|
|
2046
|
+
"aria-expanded": expansionEnabled ? isExpanded : void 0,
|
|
1628
2047
|
onClick: handleClick,
|
|
1629
2048
|
onDoubleClick: handleDoubleClick,
|
|
1630
2049
|
onContextMenu: handleContextMenu,
|
|
@@ -1666,6 +2085,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1666
2085
|
if (prev.activeColumnId !== next.activeColumnId) return false;
|
|
1667
2086
|
if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
|
|
1668
2087
|
if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
|
|
2088
|
+
if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
|
|
1669
2089
|
if (prev.virtualStyle !== next.virtualStyle) {
|
|
1670
2090
|
if (!prev.virtualStyle || !next.virtualStyle) return false;
|
|
1671
2091
|
if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
|
|
@@ -1675,9 +2095,7 @@ function areRowPropsEqual(prev, next) {
|
|
|
1675
2095
|
return true;
|
|
1676
2096
|
}
|
|
1677
2097
|
var MemoizedTableRow = React3__default.default.memo(TableRowInner, areRowPropsEqual);
|
|
1678
|
-
function TableFooter({
|
|
1679
|
-
table
|
|
1680
|
-
}) {
|
|
2098
|
+
function TableFooter({ table }) {
|
|
1681
2099
|
const footerGroups = table.getFooterGroups();
|
|
1682
2100
|
if (!footerGroups.length) return null;
|
|
1683
2101
|
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 +2858,11 @@ function ContextMenu({
|
|
|
2440
2858
|
}
|
|
2441
2859
|
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
2442
2860
|
e.preventDefault();
|
|
2443
|
-
const items2 = menuRef.current?.querySelectorAll(
|
|
2444
|
-
|
|
2445
|
-
const currentIndex = Array.from(items2).findIndex(
|
|
2446
|
-
(el) => el === document.activeElement
|
|
2861
|
+
const items2 = menuRef.current?.querySelectorAll(
|
|
2862
|
+
'[role="menuitem"]:not([aria-disabled="true"])'
|
|
2447
2863
|
);
|
|
2864
|
+
if (!items2 || items2.length === 0) return;
|
|
2865
|
+
const currentIndex = Array.from(items2).findIndex((el) => el === document.activeElement);
|
|
2448
2866
|
let nextIndex;
|
|
2449
2867
|
if (e.key === "ArrowDown") {
|
|
2450
2868
|
nextIndex = currentIndex < items2.length - 1 ? currentIndex + 1 : 0;
|
|
@@ -2489,11 +2907,7 @@ function ContextMenu({
|
|
|
2489
2907
|
navigator.clipboard?.readText().then((text) => {
|
|
2490
2908
|
const editing = table.getState().editing;
|
|
2491
2909
|
if (editing?.activeCell) {
|
|
2492
|
-
table.pasteFromClipboard(
|
|
2493
|
-
text,
|
|
2494
|
-
editing.activeCell.rowId,
|
|
2495
|
-
editing.activeCell.columnId
|
|
2496
|
-
);
|
|
2910
|
+
table.pasteFromClipboard(text, editing.activeCell.rowId, editing.activeCell.columnId);
|
|
2497
2911
|
}
|
|
2498
2912
|
}).catch(() => {
|
|
2499
2913
|
});
|
|
@@ -2833,6 +3247,12 @@ function isEditableTarget(element) {
|
|
|
2833
3247
|
}
|
|
2834
3248
|
return element.isContentEditable;
|
|
2835
3249
|
}
|
|
3250
|
+
function filterHeaderGroups(groups, visibleColumnIds) {
|
|
3251
|
+
return groups.map((group) => ({
|
|
3252
|
+
...group,
|
|
3253
|
+
headers: group.headers.filter((header) => visibleColumnIds.has(header.column.id))
|
|
3254
|
+
})).filter((group) => group.headers.length > 0);
|
|
3255
|
+
}
|
|
2836
3256
|
function Table({
|
|
2837
3257
|
table,
|
|
2838
3258
|
stickyHeader,
|
|
@@ -2859,6 +3279,10 @@ function Table({
|
|
|
2859
3279
|
sidebar,
|
|
2860
3280
|
sidebarPanels = ["columns", "filters"],
|
|
2861
3281
|
defaultSidebarPanel,
|
|
3282
|
+
floatingFilters,
|
|
3283
|
+
columnVirtualization,
|
|
3284
|
+
columnVirtualizationOverscan,
|
|
3285
|
+
ariaLabel,
|
|
2862
3286
|
...rest
|
|
2863
3287
|
}) {
|
|
2864
3288
|
const [sidebarOpen, setSidebarOpen] = React3.useState(false);
|
|
@@ -2866,6 +3290,7 @@ function Table({
|
|
|
2866
3290
|
defaultSidebarPanel ?? "columns"
|
|
2867
3291
|
);
|
|
2868
3292
|
const containerRef = React3.useRef(null);
|
|
3293
|
+
const horizontalScrollRef = React3.useRef(null);
|
|
2869
3294
|
const isRtl = direction === "rtl";
|
|
2870
3295
|
const classNames = [
|
|
2871
3296
|
"yable",
|
|
@@ -2883,8 +3308,86 @@ function Table({
|
|
|
2883
3308
|
const hasGlobalFilter = Boolean(table.getState().globalFilter);
|
|
2884
3309
|
const hasColumnFilters = table.getState().columnFilters.length > 0;
|
|
2885
3310
|
const isFiltered = hasGlobalFilter || hasColumnFilters;
|
|
3311
|
+
const allVisibleColumns = table.getVisibleLeafColumns();
|
|
3312
|
+
const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
|
|
3313
|
+
const hasGroupedHeaders = table.getHeaderGroups().length > 1;
|
|
3314
|
+
const canVirtualizeColumns = Boolean(columnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
|
|
3315
|
+
const columnVirtualState = useColumnVirtualization({
|
|
3316
|
+
containerRef: horizontalScrollRef,
|
|
3317
|
+
columns: allVisibleColumns,
|
|
3318
|
+
overscan: columnVirtualizationOverscan ?? 2,
|
|
3319
|
+
enabled: canVirtualizeColumns
|
|
3320
|
+
});
|
|
3321
|
+
const renderTable = React3.useMemo(() => {
|
|
3322
|
+
if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
|
|
3323
|
+
return table;
|
|
3324
|
+
}
|
|
3325
|
+
const virtualColumns = columnVirtualState.virtualColumns.map((entry) => entry.column);
|
|
3326
|
+
const visibleColumnIds = new Set(virtualColumns.map((column) => column.id));
|
|
3327
|
+
const next = Object.create(table);
|
|
3328
|
+
next.getVisibleFlatColumns = () => virtualColumns;
|
|
3329
|
+
next.getVisibleLeafColumns = () => virtualColumns;
|
|
3330
|
+
next.getCenterVisibleLeafColumns = () => virtualColumns;
|
|
3331
|
+
next.getLeftVisibleLeafColumns = () => [];
|
|
3332
|
+
next.getRightVisibleLeafColumns = () => [];
|
|
3333
|
+
next.getHeaderGroups = () => filterHeaderGroups(table.getHeaderGroups(), visibleColumnIds);
|
|
3334
|
+
next.getCenterHeaderGroups = () => filterHeaderGroups(table.getCenterHeaderGroups(), visibleColumnIds);
|
|
3335
|
+
next.getFooterGroups = () => filterHeaderGroups(table.getFooterGroups(), visibleColumnIds);
|
|
3336
|
+
next.getCenterFooterGroups = () => filterHeaderGroups(table.getCenterFooterGroups(), visibleColumnIds);
|
|
3337
|
+
return next;
|
|
3338
|
+
}, [
|
|
3339
|
+
canVirtualizeColumns,
|
|
3340
|
+
columnVirtualState.isVirtualized,
|
|
3341
|
+
columnVirtualState.virtualColumns,
|
|
3342
|
+
table
|
|
3343
|
+
]);
|
|
3344
|
+
const showColumnVirtualizationShell = canVirtualizeColumns;
|
|
2886
3345
|
const contextMenu = useContextMenu();
|
|
2887
3346
|
useKeyboardNavigation(table, { containerRef });
|
|
3347
|
+
const [announcement, setAnnouncement] = React3.useState("");
|
|
3348
|
+
const prevSortingRef = React3.useRef(table.getState().sorting);
|
|
3349
|
+
const prevFilterCountRef = React3.useRef(rows.length);
|
|
3350
|
+
const prevHasFiltersRef = React3.useRef(isFiltered);
|
|
3351
|
+
const prevPaginationRef = React3.useRef(table.getState().pagination);
|
|
3352
|
+
const isFirstRenderRef = React3.useRef(true);
|
|
3353
|
+
React3.useEffect(() => {
|
|
3354
|
+
if (isFirstRenderRef.current) {
|
|
3355
|
+
isFirstRenderRef.current = false;
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
const currentSorting = table.getState().sorting;
|
|
3359
|
+
const currentPagination = table.getState().pagination;
|
|
3360
|
+
const currentRowCount = rows.length;
|
|
3361
|
+
const currentIsFiltered = isFiltered;
|
|
3362
|
+
if (JSON.stringify(currentSorting) !== JSON.stringify(prevSortingRef.current)) {
|
|
3363
|
+
prevSortingRef.current = currentSorting;
|
|
3364
|
+
const firstSort = currentSorting[0];
|
|
3365
|
+
if (firstSort) {
|
|
3366
|
+
const column = table.getColumn(firstSort.id);
|
|
3367
|
+
const headerDef = column?.columnDef.header;
|
|
3368
|
+
const columnName = typeof headerDef === "string" ? headerDef : firstSort.id;
|
|
3369
|
+
const direction2 = firstSort.desc ? "descending" : "ascending";
|
|
3370
|
+
setAnnouncement(`Sorted by ${columnName} ${direction2}`);
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
if (currentRowCount !== prevFilterCountRef.current || currentIsFiltered !== prevHasFiltersRef.current) {
|
|
3375
|
+
prevFilterCountRef.current = currentRowCount;
|
|
3376
|
+
prevHasFiltersRef.current = currentIsFiltered;
|
|
3377
|
+
if (currentIsFiltered) {
|
|
3378
|
+
setAnnouncement(`${currentRowCount} rows after filtering`);
|
|
3379
|
+
return;
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
if (JSON.stringify(currentPagination) !== JSON.stringify(prevPaginationRef.current)) {
|
|
3383
|
+
prevPaginationRef.current = currentPagination;
|
|
3384
|
+
const pageCount = table.getPageCount();
|
|
3385
|
+
if (pageCount > 0) {
|
|
3386
|
+
setAnnouncement(`Page ${currentPagination.pageIndex + 1} of ${pageCount}`);
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
});
|
|
2888
3391
|
const handleContextMenu = React3.useCallback(
|
|
2889
3392
|
(e) => {
|
|
2890
3393
|
e.preventDefault();
|
|
@@ -2892,6 +3395,24 @@ function Table({
|
|
|
2892
3395
|
},
|
|
2893
3396
|
[contextMenu, table]
|
|
2894
3397
|
);
|
|
3398
|
+
const tableNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3399
|
+
"table",
|
|
3400
|
+
{
|
|
3401
|
+
className: "yable-table",
|
|
3402
|
+
style: columnVirtualState.isVirtualized ? {
|
|
3403
|
+
width: columnVirtualState.visibleWidth,
|
|
3404
|
+
minWidth: columnVirtualState.visibleWidth,
|
|
3405
|
+
marginLeft: columnVirtualState.startOffset,
|
|
3406
|
+
tableLayout: "fixed"
|
|
3407
|
+
} : void 0,
|
|
3408
|
+
"data-column-virtualized": columnVirtualState.isVirtualized || void 0,
|
|
3409
|
+
children: [
|
|
3410
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHeader, { table: renderTable, floatingFilters }),
|
|
3411
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableBody, { table: renderTable, clickableRows }),
|
|
3412
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx(TableFooter, { table: renderTable })
|
|
3413
|
+
]
|
|
3414
|
+
}
|
|
3415
|
+
);
|
|
2895
3416
|
return /* @__PURE__ */ jsxRuntime.jsx(TableProvider, { value: table, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2896
3417
|
"div",
|
|
2897
3418
|
{
|
|
@@ -2900,23 +3421,40 @@ function Table({
|
|
|
2900
3421
|
"data-theme": theme,
|
|
2901
3422
|
dir: direction,
|
|
2902
3423
|
role: "grid",
|
|
3424
|
+
"aria-label": ariaLabel ?? "Data table",
|
|
2903
3425
|
"aria-rowcount": table.getRowModel().rows.length,
|
|
2904
3426
|
"aria-colcount": table.getVisibleLeafColumns().length,
|
|
2905
3427
|
onContextMenu: handleContextMenu,
|
|
2906
3428
|
...rest,
|
|
2907
3429
|
children: [
|
|
2908
3430
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "yable-main", children: [
|
|
2909
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
3431
|
+
showColumnVirtualizationShell ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3432
|
+
"div",
|
|
3433
|
+
{
|
|
3434
|
+
ref: horizontalScrollRef,
|
|
3435
|
+
className: "yable-horizontal-scroll-container",
|
|
3436
|
+
style: {
|
|
3437
|
+
overflowX: "auto",
|
|
3438
|
+
overflowY: "visible",
|
|
3439
|
+
maxWidth: "100%",
|
|
3440
|
+
position: "relative"
|
|
3441
|
+
},
|
|
3442
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3443
|
+
"div",
|
|
3444
|
+
{
|
|
3445
|
+
className: "yable-horizontal-scroll-inner",
|
|
3446
|
+
style: {
|
|
3447
|
+
width: Math.max(columnVirtualState.totalWidth, columnVirtualState.visibleWidth),
|
|
3448
|
+
minWidth: Math.max(
|
|
3449
|
+
columnVirtualState.totalWidth,
|
|
3450
|
+
columnVirtualState.visibleWidth
|
|
3451
|
+
)
|
|
3452
|
+
},
|
|
3453
|
+
children: tableNode
|
|
3454
|
+
}
|
|
3455
|
+
)
|
|
3456
|
+
}
|
|
3457
|
+
) : tableNode,
|
|
2920
3458
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2921
3459
|
LoadingOverlay,
|
|
2922
3460
|
{
|
|
@@ -2957,6 +3495,24 @@ function Table({
|
|
|
2957
3495
|
onClose: contextMenu.close,
|
|
2958
3496
|
table
|
|
2959
3497
|
}
|
|
3498
|
+
),
|
|
3499
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3500
|
+
"div",
|
|
3501
|
+
{
|
|
3502
|
+
role: "status",
|
|
3503
|
+
"aria-live": "polite",
|
|
3504
|
+
"aria-atomic": "true",
|
|
3505
|
+
style: {
|
|
3506
|
+
position: "absolute",
|
|
3507
|
+
width: "1px",
|
|
3508
|
+
height: "1px",
|
|
3509
|
+
overflow: "hidden",
|
|
3510
|
+
clip: "rect(0,0,0,0)",
|
|
3511
|
+
whiteSpace: "nowrap",
|
|
3512
|
+
border: 0
|
|
3513
|
+
},
|
|
3514
|
+
children: announcement
|
|
3515
|
+
}
|
|
2960
3516
|
)
|
|
2961
3517
|
]
|
|
2962
3518
|
}
|
|
@@ -3422,14 +3978,7 @@ function formatDateValue(value, type) {
|
|
|
3422
3978
|
return String(value);
|
|
3423
3979
|
}
|
|
3424
3980
|
function useClipboard(table, options = {}) {
|
|
3425
|
-
const {
|
|
3426
|
-
enabled = true,
|
|
3427
|
-
containerRef,
|
|
3428
|
-
onCopy,
|
|
3429
|
-
onCut,
|
|
3430
|
-
onPaste,
|
|
3431
|
-
...clipboardOptions
|
|
3432
|
-
} = options;
|
|
3981
|
+
const { enabled = true, containerRef, onCopy, onCut, onPaste, ...clipboardOptions } = options;
|
|
3433
3982
|
const handleCopy = React3.useCallback(
|
|
3434
3983
|
(e) => {
|
|
3435
3984
|
if (isEditableTarget2(e.target)) return;
|
|
@@ -3467,20 +4016,29 @@ function useClipboard(table, options = {}) {
|
|
|
3467
4016
|
targetRowId = state.editing.activeCell.rowId;
|
|
3468
4017
|
targetColumnId = state.editing.activeCell.columnId;
|
|
3469
4018
|
} else {
|
|
3470
|
-
const
|
|
3471
|
-
|
|
3472
|
-
);
|
|
3473
|
-
if (
|
|
3474
|
-
|
|
4019
|
+
const selectedRange = table.getCellSelectionRange();
|
|
4020
|
+
const rows = table.getRowModel().rows;
|
|
4021
|
+
const columns = table.getVisibleLeafColumns();
|
|
4022
|
+
if (selectedRange) {
|
|
4023
|
+
const startRowIndex = Math.min(selectedRange.start.rowIndex, selectedRange.end.rowIndex);
|
|
4024
|
+
const startColumnIndex = Math.min(
|
|
4025
|
+
selectedRange.start.columnIndex,
|
|
4026
|
+
selectedRange.end.columnIndex
|
|
4027
|
+
);
|
|
4028
|
+
targetRowId = rows[startRowIndex]?.id;
|
|
4029
|
+
targetColumnId = columns[startColumnIndex]?.id;
|
|
3475
4030
|
} else {
|
|
3476
|
-
const
|
|
3477
|
-
|
|
4031
|
+
const selectedRowIds = Object.keys(state.rowSelection || {}).filter(
|
|
4032
|
+
(id) => state.rowSelection[id]
|
|
4033
|
+
);
|
|
4034
|
+
if (selectedRowIds.length > 0) {
|
|
4035
|
+
targetRowId = selectedRowIds[0];
|
|
4036
|
+
} else if (rows.length > 0) {
|
|
3478
4037
|
targetRowId = rows[0].id;
|
|
3479
4038
|
}
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
targetColumnId = columns[0].id;
|
|
4039
|
+
if (columns.length > 0) {
|
|
4040
|
+
targetColumnId = columns[0].id;
|
|
4041
|
+
}
|
|
3484
4042
|
}
|
|
3485
4043
|
}
|
|
3486
4044
|
if (targetRowId && targetColumnId) {
|
|
@@ -4770,7 +5328,7 @@ function sanitizeCSS(css) {
|
|
|
4770
5328
|
sanitized = sanitized.replace(/javascript\s*:/gi, "/* javascript: removed */");
|
|
4771
5329
|
return sanitized;
|
|
4772
5330
|
}
|
|
4773
|
-
function usePrintLayout(
|
|
5331
|
+
function usePrintLayout(_table, options = {}) {
|
|
4774
5332
|
const { title, additionalCSS } = options;
|
|
4775
5333
|
const isPrintingRef = React3.useRef(false);
|
|
4776
5334
|
const preparePrint = React3.useCallback(() => {
|
|
@@ -4807,7 +5365,7 @@ function usePrintLayout(table, options = {}) {
|
|
|
4807
5365
|
requestAnimationFrame(() => {
|
|
4808
5366
|
window.print();
|
|
4809
5367
|
});
|
|
4810
|
-
}, [
|
|
5368
|
+
}, [title, additionalCSS]);
|
|
4811
5369
|
return {
|
|
4812
5370
|
preparePrint,
|
|
4813
5371
|
isPrinting: isPrintingRef.current
|
|
@@ -4965,6 +5523,7 @@ exports.ExpandIcon = ExpandIcon;
|
|
|
4965
5523
|
exports.FillHandle = FillHandle;
|
|
4966
5524
|
exports.FiltersPanel = FiltersPanel;
|
|
4967
5525
|
exports.FlashCell = FlashCell;
|
|
5526
|
+
exports.FloatingFilter = FloatingFilter;
|
|
4968
5527
|
exports.GlobalFilter = GlobalFilter;
|
|
4969
5528
|
exports.LoadingOverlay = LoadingOverlay;
|
|
4970
5529
|
exports.MasterDetail = MasterDetail;
|
|
@@ -4972,6 +5531,7 @@ exports.NoRowsOverlay = NoRowsOverlay;
|
|
|
4972
5531
|
exports.Pagination = Pagination;
|
|
4973
5532
|
exports.PivotConfigPanel = PivotConfigPanel;
|
|
4974
5533
|
exports.PrintLayout = PrintLayout;
|
|
5534
|
+
exports.SetFilter = SetFilter;
|
|
4975
5535
|
exports.Sidebar = Sidebar;
|
|
4976
5536
|
exports.SortIndicator = SortIndicator;
|
|
4977
5537
|
exports.StatusBar = StatusBar;
|
|
@@ -4990,6 +5550,7 @@ exports.resolveMeasureRecipe = resolveMeasureRecipe;
|
|
|
4990
5550
|
exports.useAutoMeasurements = useAutoMeasurements;
|
|
4991
5551
|
exports.useCellFlash = useCellFlash;
|
|
4992
5552
|
exports.useClipboard = useClipboard;
|
|
5553
|
+
exports.useColumnVirtualization = useColumnVirtualization;
|
|
4993
5554
|
exports.useContextMenu = useContextMenu;
|
|
4994
5555
|
exports.useFillHandle = useFillHandle;
|
|
4995
5556
|
exports.useKeyboardNavigation = useKeyboardNavigation;
|