boneless-table 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -92,10 +92,13 @@ function ColumnFilter({
92
92
  var _a, _b;
93
93
  const value = String((_a = column.getFilterValue()) != null ? _a : "");
94
94
  const [inputValue, setInputValue] = (0, import_react.useState)(value);
95
+ const lastColumnValueRef = (0, import_react.useRef)(value);
95
96
  (0, import_react.useEffect)(() => {
96
- setInputValue(value);
97
- }, [value]);
98
- (0, import_react.useEffect)(() => {
97
+ if (value !== lastColumnValueRef.current) {
98
+ lastColumnValueRef.current = value;
99
+ setInputValue(value);
100
+ return;
101
+ }
99
102
  if (settings.type !== "text" || inputValue === value) return;
100
103
  if (debounceMs <= 0) {
101
104
  column.setFilterValue(inputValue || void 0);
@@ -248,7 +251,7 @@ var defaultBonelessTableSettings = {
248
251
  borders: "none",
249
252
  sorting: { enabled: true, reveal: "hover" }
250
253
  },
251
- interactions: { filterReveal: "hover", horizontalOverflow: "auto" }
254
+ interactions: { horizontalOverflow: "auto" }
252
255
  };
253
256
  function mergeBonelessTableSettings(override, base = defaultBonelessTableSettings) {
254
257
  var _a, _b, _c, _d, _e, _f;
@@ -268,7 +271,7 @@ function resolveColumnSettings(settings, column) {
268
271
  const configured = (_a = column.columnDef.meta) == null ? void 0 : _a.bonelessTable;
269
272
  const configuredSizing = configured == null ? void 0 : configured.sizing;
270
273
  return {
271
- sizing: configuredSizing && "widthPx" in configuredSizing ? { widthPx: configuredSizing.widthPx } : __spreadValues(__spreadValues({}, settings.columnDefaults.sizing), configuredSizing),
274
+ sizing: (configuredSizing == null ? void 0 : configuredSizing.widthPx) != null && configuredSizing.minPx == null && configuredSizing.maxPx == null && configuredSizing.flex == null && configuredSizing.resizable == null ? { widthPx: configuredSizing.widthPx } : __spreadValues(__spreadValues({}, settings.columnDefaults.sizing), configuredSizing),
272
275
  align: (_b = configured == null ? void 0 : configured.align) != null ? _b : settings.columnDefaults.align,
273
276
  borders: (_c = configured == null ? void 0 : configured.borders) != null ? _c : settings.columnDefaults.borders,
274
277
  sorting: __spreadValues(__spreadValues({}, settings.columnDefaults.sorting), configured == null ? void 0 : configured.sorting),
@@ -402,6 +405,8 @@ function BonelessTable(_a) {
402
405
  scroller = "auto",
403
406
  toolbar = true,
404
407
  toolbarLayout,
408
+ filters = true,
409
+ filterPlacement = "above",
405
410
  footer = true,
406
411
  totalCount,
407
412
  resultLabel = "rows",
@@ -431,6 +436,8 @@ function BonelessTable(_a) {
431
436
  "scroller",
432
437
  "toolbar",
433
438
  "toolbarLayout",
439
+ "filters",
440
+ "filterPlacement",
434
441
  "footer",
435
442
  "totalCount",
436
443
  "resultLabel",
@@ -448,11 +455,13 @@ function BonelessTable(_a) {
448
455
  const defaultOrder = (0, import_react3.useMemo)(() => getColumnIds(resolvedColumns), [resolvedColumns]);
449
456
  const scrollerRef = (0, import_react3.useRef)(null);
450
457
  const headerScrollerRef = (0, import_react3.useRef)(null);
458
+ const rootRef = (0, import_react3.useRef)(null);
459
+ const lastScrollLeftRef = (0, import_react3.useRef)(0);
451
460
  const columnsButtonRef = (0, import_react3.useRef)(null);
452
461
  const nearEndTriggeredRef = (0, import_react3.useRef)(false);
453
462
  const columnMenuId = (0, import_react3.useId)();
454
463
  const [showColumns, setShowColumns] = (0, import_react3.useState)(false);
455
- const [headerScrollbarGutter, setHeaderScrollbarGutter] = (0, import_react3.useState)(0);
464
+ const [headerScrollbarInset, setHeaderScrollbarInset] = (0, import_react3.useState)(0);
456
465
  const [sorting, setSorting] = (0, import_react3.useState)((_b2 = (_a2 = tableOptions.initialState) == null ? void 0 : _a2.sorting) != null ? _b2 : []);
457
466
  const [columnFilters, setColumnFilters] = (0, import_react3.useState)(
458
467
  (_d = (_c = tableOptions.initialState) == null ? void 0 : _c.columnFilters) != null ? _d : []
@@ -464,6 +473,7 @@ function BonelessTable(_a) {
464
473
  (_h = (_g = tableOptions.initialState) == null ? void 0 : _g.columnOrder) != null ? _h : defaultOrder
465
474
  );
466
475
  const [expanded, setExpanded] = (0, import_react3.useState)((_j = (_i = tableOptions.initialState) == null ? void 0 : _i.expanded) != null ? _j : {});
476
+ const [columnSizing, setColumnSizing] = (0, import_react3.useState)({});
467
477
  const _k = tableOptions, {
468
478
  state: controlledState,
469
479
  onSortingChange,
@@ -495,19 +505,27 @@ function BonelessTable(_a) {
495
505
  ]);
496
506
  (0, import_react3.useEffect)(() => {
497
507
  var _a3;
498
- if (scrollToTopOn !== void 0) (_a3 = scrollerRef.current) == null ? void 0 : _a3.scrollTo({ top: 0 });
508
+ if (scrollToTopOn !== void 0) {
509
+ nearEndTriggeredRef.current = false;
510
+ (_a3 = scrollerRef.current) == null ? void 0 : _a3.scrollTo({ top: 0 });
511
+ }
499
512
  }, [scrollToTopOn]);
500
513
  (0, import_react3.useEffect)(() => {
501
- const scroller2 = scrollerRef.current;
502
- if (!scroller2) return;
503
- const syncHeaderScrollbarGutter = () => {
504
- setHeaderScrollbarGutter(Math.max(0, scroller2.offsetWidth - scroller2.clientWidth));
514
+ const scrollerElement = scrollerRef.current;
515
+ if (!scrollerElement) return;
516
+ const syncHeaderScrollbarInset = () => {
517
+ setHeaderScrollbarInset(
518
+ Math.max(0, scrollerElement.offsetWidth - scrollerElement.clientWidth)
519
+ );
520
+ };
521
+ syncHeaderScrollbarInset();
522
+ const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(syncHeaderScrollbarInset);
523
+ resizeObserver == null ? void 0 : resizeObserver.observe(scrollerElement);
524
+ window.addEventListener("resize", syncHeaderScrollbarInset);
525
+ return () => {
526
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
527
+ window.removeEventListener("resize", syncHeaderScrollbarInset);
505
528
  };
506
- syncHeaderScrollbarGutter();
507
- if (typeof ResizeObserver === "undefined") return;
508
- const observer = new ResizeObserver(syncHeaderScrollbarGutter);
509
- observer.observe(scroller2);
510
- return () => observer.disconnect();
511
529
  }, []);
512
530
  const table = (0, import_react_table.useReactTable)(__spreadProps(__spreadValues({}, restTableOptions), {
513
531
  data,
@@ -543,18 +561,33 @@ function BonelessTable(_a) {
543
561
  var _a3;
544
562
  return (_a3 = columnSettingsById.get(column.id)) != null ? _a3 : resolveColumnSettings(settings, column);
545
563
  };
564
+ const columnResizeVariables = (0, import_react3.useMemo)(
565
+ () => new Map(
566
+ allColumns.map((column, index) => [column.id, `--boneless-table-column-${index}-width`])
567
+ ),
568
+ [allColumns]
569
+ );
570
+ const getColumnResizeVariable = (columnId) => {
571
+ var _a3;
572
+ return (_a3 = columnResizeVariables.get(columnId)) != null ? _a3 : `--boneless-table-column-${columnId}-width`;
573
+ };
546
574
  const grid = visibleColumns.map((column) => {
575
+ var _a3, _b3, _c2;
547
576
  const columnSettings = getColumnSettings(column);
548
- if ("widthPx" in columnSettings.sizing) return `${columnSettings.sizing.widthPx}px`;
549
- return `minmax(${columnSettings.sizing.minPx}px, ${columnSettings.sizing.flex}fr)`;
577
+ const { sizing } = columnSettings;
578
+ const width = (_a3 = columnSizing[column.id]) != null ? _a3 : sizing.widthPx;
579
+ const track = width != null ? `${width}px` : `minmax(${(_b3 = sizing.minPx) != null ? _b3 : settings.columnDefaults.sizing.minPx}px, ${(_c2 = sizing.flex) != null ? _c2 : settings.columnDefaults.sizing.flex}fr)`;
580
+ return `var(${getColumnResizeVariable(column.id)}, ${track})`;
550
581
  }).join(" ");
551
582
  const minWidth = visibleColumns.reduce((width, column) => {
583
+ var _a3, _b3;
552
584
  const { sizing } = getColumnSettings(column);
553
- return width + ("widthPx" in sizing ? sizing.widthPx : sizing.minPx);
585
+ const configuredWidth = (_a3 = columnSizing[column.id]) != null ? _a3 : sizing.widthPx;
586
+ return width + ((_b3 = configuredWidth != null ? configuredWidth : sizing.minPx) != null ? _b3 : settings.columnDefaults.sizing.minPx);
554
587
  }, 0);
555
588
  const gridStyle = {
556
589
  "--boneless-table-grid": grid,
557
- minWidth: `${minWidth}px`
590
+ minWidth: `var(--boneless-table-min-width, ${minWidth}px)`
558
591
  };
559
592
  const tree = treeOption === true ? {} : treeOption === false ? void 0 : treeOption;
560
593
  const treeColumnId = (_m = tree == null ? void 0 : tree.columnId) != null ? _m : (_l = visibleColumns[0]) == null ? void 0 : _l.id;
@@ -572,28 +605,94 @@ function BonelessTable(_a) {
572
605
  [expandableRows, expanded]
573
606
  );
574
607
  (0, import_react3.useEffect)(() => {
575
- if (!isFetchingMore || !canLoadMore) nearEndTriggeredRef.current = false;
576
- }, [canLoadMore, isFetchingMore]);
608
+ if (!canLoadMore) nearEndTriggeredRef.current = false;
609
+ }, [canLoadMore]);
577
610
  function handleScroll() {
578
611
  const element = scrollerRef.current;
579
612
  if (!element) return;
580
- if (headerScrollerRef.current) headerScrollerRef.current.scrollLeft = element.scrollLeft;
613
+ if (element.scrollLeft !== lastScrollLeftRef.current) {
614
+ lastScrollLeftRef.current = element.scrollLeft;
615
+ if (headerScrollerRef.current) headerScrollerRef.current.scrollLeft = element.scrollLeft;
616
+ }
617
+ if (!onNearEnd) return;
581
618
  const isNearEnd = element.scrollHeight - element.scrollTop - element.clientHeight < nearEndOffset;
582
619
  if (!isNearEnd) {
583
620
  nearEndTriggeredRef.current = false;
584
621
  return;
585
622
  }
586
- if (!onNearEnd || !canLoadMore || isFetchingMore || nearEndTriggeredRef.current) return;
623
+ if (!canLoadMore || isFetchingMore || nearEndTriggeredRef.current) return;
587
624
  nearEndTriggeredRef.current = true;
588
625
  onNearEnd();
589
626
  }
590
627
  function resetTable() {
628
+ var _a3;
591
629
  if (onReset) return onReset();
592
630
  table.resetSorting();
593
631
  table.resetColumnFilters();
594
632
  table.resetColumnVisibility();
595
633
  table.setColumnOrder(defaultOrder);
596
634
  table.resetExpanded();
635
+ columnResizeVariables.forEach((property) => {
636
+ var _a4;
637
+ return (_a4 = rootRef.current) == null ? void 0 : _a4.style.removeProperty(property);
638
+ });
639
+ (_a3 = rootRef.current) == null ? void 0 : _a3.style.removeProperty("--boneless-table-min-width");
640
+ setColumnSizing({});
641
+ }
642
+ function resizeColumn(columnId, startWidth, startX, minPx, maxPx) {
643
+ const property = getColumnResizeVariable(columnId);
644
+ const startMinWidth = minWidth;
645
+ let nextWidth = startWidth;
646
+ let hasMoved = false;
647
+ const onMove = (event) => {
648
+ var _a3, _b3;
649
+ nextWidth = constrainColumnWidth(startWidth + event.clientX - startX, minPx, maxPx);
650
+ hasMoved || (hasMoved = nextWidth !== startWidth);
651
+ (_a3 = rootRef.current) == null ? void 0 : _a3.style.setProperty(property, `${nextWidth}px`);
652
+ (_b3 = rootRef.current) == null ? void 0 : _b3.style.setProperty(
653
+ "--boneless-table-min-width",
654
+ `${startMinWidth - startWidth + nextWidth}px`
655
+ );
656
+ };
657
+ const onEnd = () => {
658
+ window.removeEventListener("pointermove", onMove);
659
+ window.removeEventListener("pointerup", onEnd);
660
+ window.removeEventListener("pointercancel", onEnd);
661
+ if (hasMoved) {
662
+ setColumnSizing((current) => __spreadProps(__spreadValues({}, current), { [columnId]: nextWidth }));
663
+ }
664
+ };
665
+ window.addEventListener("pointermove", onMove);
666
+ window.addEventListener("pointerup", onEnd);
667
+ window.addEventListener("pointercancel", onEnd);
668
+ }
669
+ function constrainColumnWidth(width, minPx, maxPx) {
670
+ return Math.min(maxPx != null ? maxPx : Number.POSITIVE_INFINITY, Math.max(minPx, Math.round(width)));
671
+ }
672
+ function getCurrentColumnWidth(columnId, fallback, element) {
673
+ var _a3, _b3, _c2, _d2;
674
+ const column = allColumns.find((item) => item.id === columnId);
675
+ const configuredWidth = column ? getColumnSettings(column).sizing.widthPx : void 0;
676
+ return (_d2 = (_c2 = (_a3 = columnSizing[columnId]) != null ? _a3 : configuredWidth) != null ? _c2 : (_b3 = element == null ? void 0 : element.parentElement) == null ? void 0 : _b3.getBoundingClientRect().width) != null ? _d2 : fallback;
677
+ }
678
+ function handleResizeStart(event, columnId, minPx, maxPx) {
679
+ var _a3, _b3;
680
+ event.preventDefault();
681
+ event.stopPropagation();
682
+ const currentWidth = getCurrentColumnWidth(columnId, minPx, event.currentTarget);
683
+ (_b3 = (_a3 = event.currentTarget).setPointerCapture) == null ? void 0 : _b3.call(_a3, event.pointerId);
684
+ resizeColumn(columnId, currentWidth, event.clientX, minPx, maxPx);
685
+ }
686
+ function handleResizeKeyDown(event, columnId, minPx, maxPx) {
687
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
688
+ event.preventDefault();
689
+ event.stopPropagation();
690
+ const step = event.shiftKey ? 32 : 8;
691
+ const currentWidth = getCurrentColumnWidth(columnId, minPx, event.currentTarget);
692
+ const direction = event.key === "ArrowLeft" ? -1 : 1;
693
+ setColumnSizing((current) => __spreadProps(__spreadValues({}, current), {
694
+ [columnId]: constrainColumnWidth(currentWidth + direction * step, minPx, maxPx)
695
+ }));
597
696
  }
598
697
  function moveColumn(id, direction) {
599
698
  const current = table.getState().columnOrder;
@@ -615,6 +714,11 @@ function BonelessTable(_a) {
615
714
  initialRect: { width: 0, height: 600 }
616
715
  });
617
716
  const estimatedRowSize = virtualization === false ? 58 : (_p = virtualization.estimateSize) != null ? _p : 58;
717
+ const measuredVirtualHeight = rowVirtualizer.getTotalSize();
718
+ const virtualHeight = isVirtualized ? Math.max(
719
+ Number.isFinite(measuredVirtualHeight) ? measuredVirtualHeight : 0,
720
+ rows.length * estimatedRowSize
721
+ ) : void 0;
618
722
  const virtualRows = !isVirtualized ? rows.map((row, index) => ({ index, start: index * 58, key: row.id })) : rowVirtualizer.getVirtualItems().length > 0 ? rowVirtualizer.getVirtualItems() : rows.slice(0, Math.ceil(600 / estimatedRowSize) + ((_q = virtualization.overscan) != null ? _q : 5)).map((row, index) => ({
619
723
  index,
620
724
  start: index * estimatedRowSize,
@@ -626,10 +730,13 @@ function BonelessTable(_a) {
626
730
  (_a3 = columnsButtonRef.current) == null ? void 0 : _a3.focus();
627
731
  }
628
732
  const toolbarSummary = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: classNames.toolbarSummary, "data-slot": "toolbar-summary", children: [
629
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: total.toLocaleString() }),
733
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { className: classNames.toolbarCount, "data-slot": "toolbar-count", children: total.toLocaleString() }),
630
734
  " ",
631
- resultLabel,
632
- resultHint ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: classNames.toolbarHint, "data-slot": "toolbar-hint", children: resultHint }) : null
735
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: classNames.toolbarLabel, "data-slot": "toolbar-label", children: resultLabel }),
736
+ resultHint ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
737
+ " ",
738
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: classNames.toolbarHint, "data-slot": "toolbar-hint", children: resultHint })
739
+ ] }) : null
633
740
  ] });
634
741
  const toolbarActions = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: classNames.toolbarActions, "data-slot": "toolbar-actions", children: [
635
742
  tree && expandableRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -681,6 +788,43 @@ function BonelessTable(_a) {
681
788
  toolbarSummary,
682
789
  toolbarActions
683
790
  ] });
791
+ const filterHeaders = table.getLeafHeaders().filter((header) => !header.isPlaceholder && getColumnSettings(header.column).filtering);
792
+ const defaultFilters = filterHeaders.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
793
+ "div",
794
+ {
795
+ "aria-label": "Table filters",
796
+ className: classNames.filters,
797
+ "data-slot": "filters",
798
+ role: "group",
799
+ children: filterHeaders.map((header) => {
800
+ var _a3, _b3;
801
+ const filterSettings = getColumnSettings(header.column).filtering;
802
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
803
+ "div",
804
+ {
805
+ className: classNames.filterItem,
806
+ "data-column-id": header.column.id,
807
+ "data-slot": "filter-item",
808
+ children: [
809
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: classNames.filterLabel, "data-slot": "filter-label", children: (_b3 = (_a3 = header.column.columnDef.meta) == null ? void 0 : _a3.columnLabel) != null ? _b3 : typeof header.column.columnDef.header === "string" || typeof header.column.columnDef.header === "number" ? String(header.column.columnDef.header) : header.column.id }),
810
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
811
+ ColumnFilter,
812
+ {
813
+ className: classNames.filter,
814
+ column: header.column,
815
+ settings: filterSettings,
816
+ icon: filterSettings.type === "text" ? icons == null ? void 0 : icons.search : void 0,
817
+ debounceMs: filterDebounceMs
818
+ }
819
+ )
820
+ ]
821
+ },
822
+ header.id
823
+ );
824
+ })
825
+ }
826
+ ) : null;
827
+ const renderedFilters = renderSlot(filters, table, defaultFilters);
684
828
  const defaultFooter = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("footer", { className: classNames.footer, "data-slot": "footer", children: [
685
829
  "Showing ",
686
830
  shown.toLocaleString(),
@@ -691,266 +835,322 @@ function BonelessTable(_a) {
691
835
  ] });
692
836
  const rootStyle = scroller === "fill" ? { display: "flex", flexDirection: "column", minHeight: 0 } : void 0;
693
837
  const scrollerStyle = __spreadValues({
694
- overflowX: settings.interactions.horizontalOverflow
838
+ overflowX: settings.interactions.horizontalOverflow,
839
+ scrollbarGutter: "stable"
695
840
  }, scroller === "fill" ? { flex: "1 1 auto", minHeight: 0, overflowY: "auto" } : {});
841
+ const headerScrollerStyle = {
842
+ flex: "0 0 auto",
843
+ minWidth: 0,
844
+ overflow: "hidden",
845
+ // The body loses this space to a classic vertical scrollbar on Windows. Reserving the
846
+ // same width here keeps both horizontal scroll ranges identical at their far edge.
847
+ marginInlineEnd: `${headerScrollbarInset}px`
848
+ };
696
849
  const tableStyle = __spreadValues({
697
850
  "--boneless-table-grid": grid
698
851
  }, scroller === "fill" ? { display: "flex", flexDirection: "column", flex: "1 1 auto", minHeight: 0 } : {});
699
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn(className, classNames.root), "data-slot": "root", style: rootStyle, children: [
700
- renderSlot(toolbar, table, defaultToolbar),
701
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
702
- "div",
703
- {
704
- className: classNames.table,
705
- "data-slot": "table",
706
- style: tableStyle,
707
- "aria-busy": isLoading || isFetchingMore,
708
- role: "table",
709
- children: [
710
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
711
- "div",
712
- {
713
- "data-slot": "header-scroller",
714
- ref: headerScrollerRef,
715
- style: {
716
- flex: "0 0 auto",
717
- minWidth: 0,
718
- overflow: "hidden",
719
- paddingInlineEnd: headerScrollbarGutter || void 0
720
- },
721
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
852
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
853
+ "div",
854
+ {
855
+ className: cn(className, classNames.root),
856
+ "data-slot": "root",
857
+ ref: rootRef,
858
+ style: rootStyle,
859
+ children: [
860
+ renderSlot(toolbar, table, defaultToolbar),
861
+ filterPlacement === "above" ? renderedFilters : null,
862
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
863
+ "div",
864
+ {
865
+ className: classNames.table,
866
+ "data-slot": "table",
867
+ style: tableStyle,
868
+ "aria-busy": isLoading || isFetchingMore,
869
+ role: "table",
870
+ children: [
871
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
722
872
  "div",
723
873
  {
724
- className: classNames.headerGroup,
725
- "data-slot": "header-group",
726
- role: "rowgroup",
727
- style: gridStyle,
728
- children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
874
+ className: classNames.headerScroller,
875
+ "data-slot": "header-scroller",
876
+ ref: headerScrollerRef,
877
+ style: headerScrollerStyle,
878
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
729
879
  "div",
730
880
  {
731
- className: classNames.headerRow,
732
- "data-slot": "header-row",
733
- role: "row",
734
- style: { display: "grid", gridTemplateColumns: "var(--boneless-table-grid)" },
735
- children: headerGroup.headers.map((header) => {
736
- var _a3;
737
- const columnSettings = getColumnSettings(header.column);
738
- const direction = header.column.getIsSorted();
739
- const isSortable = !header.isPlaceholder && header.column.getCanSort() && columnSettings.sorting.enabled;
740
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
741
- "div",
742
- {
743
- className: classNames.header,
744
- "data-slot": "header",
745
- "data-align": columnSettings.align,
746
- "data-borders": columnSettings.borders,
747
- role: "columnheader",
748
- "aria-colspan": header.colSpan > 1 ? header.colSpan : void 0,
749
- "aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : isSortable ? "none" : void 0,
750
- style: { gridColumn: `span ${header.colSpan}` },
751
- children: [
752
- header.isPlaceholder ? null : isSortable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
753
- "button",
754
- {
755
- className: classNames.headerButton,
756
- "data-align": columnSettings.align,
757
- "data-slot": "header-button",
758
- onClick: header.column.getToggleSortingHandler(),
759
- children: [
760
- (0, import_react_table.flexRender)(header.column.columnDef.header, header.getContext()),
761
- (icons == null ? void 0 : icons.sort) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
762
- "span",
763
- {
764
- className: classNames.sortIndicator,
765
- "data-align": columnSettings.align,
766
- "data-slot": "sort-indicator",
767
- "data-reveal": columnSettings.sorting.reveal,
768
- children: icons.sort(direction)
769
- }
770
- ) : null
771
- ]
772
- }
773
- ) : (0, import_react_table.flexRender)(header.column.columnDef.header, header.getContext()),
774
- !header.isPlaceholder && columnSettings.filtering ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
775
- "div",
776
- {
777
- className: classNames.filter,
778
- "data-slot": "filter",
779
- "data-reveal": (_a3 = columnSettings.filtering.reveal) != null ? _a3 : settings.interactions.filterReveal,
780
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
781
- ColumnFilter,
782
- {
783
- column: header.column,
784
- settings: columnSettings.filtering,
785
- icon: icons == null ? void 0 : icons.search,
786
- debounceMs: filterDebounceMs
787
- }
788
- )
789
- }
790
- ) : null
791
- ]
792
- },
793
- header.id
794
- );
795
- })
796
- },
797
- headerGroup.id
798
- ))
799
- }
800
- )
801
- }
802
- ),
803
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
804
- "div",
805
- {
806
- className: classNames.scroller,
807
- "data-slot": "scroller",
808
- ref: scrollerRef,
809
- onScroll: handleScroll,
810
- style: scrollerStyle,
811
- children: [
812
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
813
- TableSkeleton,
814
- {
815
- columnCount: visibleColumns.length,
816
- rows: skeletonRows,
817
- label: skeletonLabel,
818
- classNames
819
- }
820
- ) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: classNames.emptyState, "data-slot": "empty-state", role: "status", children: emptyState ? typeof emptyState === "function" ? emptyState(table) : emptyState : table.getState().columnFilters.length > 0 ? "No rows match the current filters." : "No rows to display." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
821
- "div",
822
- {
823
- className: classNames.rowGroup,
824
- "data-slot": "row-group",
825
- style: __spreadProps(__spreadValues({}, gridStyle), {
826
- height: `${isVirtualized ? rowVirtualizer.getTotalSize() : "auto"}`,
827
- position: "relative"
828
- }),
829
- role: "rowgroup",
830
- children: virtualRows.map((virtualRow) => {
831
- var _a3;
832
- const row = rows[virtualRow.index];
833
- const href = rowLink ? resolveRowHref(rowLink, row.original) : void 0;
834
- const RowLink = rowLink == null ? void 0 : rowLink.component;
835
- const rowContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
881
+ className: classNames.headerGroup,
882
+ "data-slot": "header-group",
883
+ role: "rowgroup",
884
+ style: gridStyle,
885
+ children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
836
886
  "div",
837
887
  {
838
- className: classNames.row,
839
- "data-slot": "row",
888
+ className: classNames.headerRow,
889
+ "data-slot": "header-row",
840
890
  role: "row",
841
891
  style: { display: "grid", gridTemplateColumns: "var(--boneless-table-grid)" },
842
- tabIndex: onRowClick && !href ? 0 : void 0,
843
- onClick: (event) => onRowClick == null ? void 0 : onRowClick(row.original, event),
844
- onKeyDown: (event) => {
845
- if (!onRowClick || href || event.key !== "Enter" && event.key !== " ")
846
- return;
847
- event.preventDefault();
848
- onRowClick(row.original, event);
849
- },
850
- children: row.getVisibleCells().map((cell) => {
851
- var _a4, _b3, _c2;
852
- const columnSettings = getColumnSettings(cell.column);
853
- const title = columnSettings.valueDisplay != null ? String((_a4 = cell.getValue()) != null ? _a4 : "") : void 0;
854
- const isTreeCell = Boolean(tree && cell.column.id === treeColumnId);
855
- const canExpand = row.getCanExpand();
856
- const cellContent = (0, import_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext());
892
+ children: headerGroup.headers.map((header) => {
893
+ const columnSettings = getColumnSettings(header.column);
894
+ const direction = header.column.getIsSorted();
895
+ const isSortable = !header.isPlaceholder && header.column.getCanSort() && columnSettings.sorting.enabled;
857
896
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
858
897
  "div",
859
898
  {
860
- className: classNames.cell,
861
- "data-slot": "cell",
899
+ className: classNames.header,
900
+ "data-slot": "header",
862
901
  "data-align": columnSettings.align,
863
902
  "data-borders": columnSettings.borders,
864
- role: "cell",
865
- title,
866
- children: isTreeCell ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
867
- "div",
868
- {
869
- "data-slot": "tree-content",
870
- style: { paddingInlineStart: `${row.depth * treeIndentPx}px` },
871
- children: [
872
- canExpand ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
873
- "button",
874
- {
875
- "data-slot": "tree-row-toggle",
876
- type: "button",
877
- "aria-expanded": row.getIsExpanded(),
878
- "aria-label": `${row.getIsExpanded() ? "Collapse" : "Expand"} row`,
879
- onClick: (event) => {
880
- event.stopPropagation();
881
- row.toggleExpanded();
882
- },
883
- children: row.getIsExpanded() ? (_b3 = icons == null ? void 0 : icons.collapse) != null ? _b3 : "\u2212" : (_c2 = icons == null ? void 0 : icons.expand) != null ? _c2 : "+"
884
- }
885
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-slot": "tree-row-toggle-spacer", "aria-hidden": "true" }),
886
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-slot": "tree-value", children: cellContent })
887
- ]
888
- }
889
- ) : cellContent
903
+ role: "columnheader",
904
+ "aria-colspan": header.colSpan > 1 ? header.colSpan : void 0,
905
+ "aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : isSortable ? "none" : void 0,
906
+ style: { gridColumn: `span ${header.colSpan}` },
907
+ children: header.isPlaceholder ? null : isSortable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
909
+ "button",
910
+ {
911
+ className: classNames.headerButton,
912
+ "data-align": columnSettings.align,
913
+ "data-slot": "header-button",
914
+ onClick: header.column.getToggleSortingHandler(),
915
+ children: [
916
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: classNames.headerLabel, "data-slot": "header-label", children: (0, import_react_table.flexRender)(header.column.columnDef.header, header.getContext()) }),
917
+ (icons == null ? void 0 : icons.sort) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
918
+ "span",
919
+ {
920
+ className: classNames.sortIndicator,
921
+ "data-align": columnSettings.align,
922
+ "data-slot": "sort-indicator",
923
+ "data-reveal": columnSettings.sorting.reveal,
924
+ children: icons.sort(direction)
925
+ }
926
+ ) : null
927
+ ]
928
+ }
929
+ ),
930
+ header.colSpan === 1 && columnSettings.sizing.resizable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
931
+ "button",
932
+ {
933
+ "aria-label": `Resize ${header.column.id} column`,
934
+ className: classNames.resizeHandle,
935
+ "data-slot": "resize-handle",
936
+ onKeyDown: (event) => {
937
+ var _a3;
938
+ return handleResizeKeyDown(
939
+ event,
940
+ header.column.id,
941
+ (_a3 = columnSettings.sizing.minPx) != null ? _a3 : settings.columnDefaults.sizing.minPx,
942
+ columnSettings.sizing.maxPx
943
+ );
944
+ },
945
+ onPointerDown: (event) => {
946
+ var _a3;
947
+ return handleResizeStart(
948
+ event,
949
+ header.column.id,
950
+ (_a3 = columnSettings.sizing.minPx) != null ? _a3 : settings.columnDefaults.sizing.minPx,
951
+ columnSettings.sizing.maxPx
952
+ );
953
+ },
954
+ type: "button"
955
+ }
956
+ ) : null
957
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
958
+ (0, import_react_table.flexRender)(header.column.columnDef.header, header.getContext()),
959
+ header.colSpan === 1 && columnSettings.sizing.resizable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
960
+ "button",
961
+ {
962
+ "aria-label": `Resize ${header.column.id} column`,
963
+ className: classNames.resizeHandle,
964
+ "data-slot": "resize-handle",
965
+ onKeyDown: (event) => {
966
+ var _a3;
967
+ return handleResizeKeyDown(
968
+ event,
969
+ header.column.id,
970
+ (_a3 = columnSettings.sizing.minPx) != null ? _a3 : settings.columnDefaults.sizing.minPx,
971
+ columnSettings.sizing.maxPx
972
+ );
973
+ },
974
+ onPointerDown: (event) => {
975
+ var _a3;
976
+ return handleResizeStart(
977
+ event,
978
+ header.column.id,
979
+ (_a3 = columnSettings.sizing.minPx) != null ? _a3 : settings.columnDefaults.sizing.minPx,
980
+ columnSettings.sizing.maxPx
981
+ );
982
+ },
983
+ type: "button"
984
+ }
985
+ ) : null
986
+ ] })
890
987
  },
891
- cell.id
988
+ header.id
892
989
  );
893
990
  })
894
- }
895
- );
896
- const rowStyle = !isVirtualized ? void 0 : {
897
- position: "absolute",
898
- top: 0,
899
- left: 0,
900
- width: "100%",
901
- transform: `translateY(${virtualRow.start}px)`
902
- };
903
- if (!href || !rowLink || !RowLink || tree && row.getCanExpand())
904
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
905
- "div",
906
- {
907
- "data-index": isVirtualized ? virtualRow.index : void 0,
908
- ref: isVirtualized ? rowVirtualizer.measureElement : void 0,
909
- style: rowStyle,
910
- children: rowContent
911
- },
912
- row.id
913
- );
914
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
915
- "div",
916
- {
917
- "data-index": isVirtualized ? virtualRow.index : void 0,
918
- ref: isVirtualized ? rowVirtualizer.measureElement : void 0,
919
- style: rowStyle,
920
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
921
- RowLink,
991
+ },
992
+ headerGroup.id
993
+ ))
994
+ }
995
+ )
996
+ }
997
+ ),
998
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
999
+ "div",
1000
+ {
1001
+ "aria-label": "Table rows",
1002
+ className: classNames.scroller,
1003
+ "data-slot": "scroller",
1004
+ ref: scrollerRef,
1005
+ onScroll: handleScroll,
1006
+ style: scrollerStyle,
1007
+ tabIndex: 0,
1008
+ children: [
1009
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1010
+ TableSkeleton,
1011
+ {
1012
+ columnCount: visibleColumns.length,
1013
+ rows: skeletonRows,
1014
+ label: skeletonLabel,
1015
+ classNames
1016
+ }
1017
+ ) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: classNames.emptyState, "data-slot": "empty-state", role: "status", children: emptyState ? typeof emptyState === "function" ? emptyState(table) : emptyState : table.getState().columnFilters.length > 0 ? "No rows match the current filters." : "No rows to display." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1018
+ "div",
1019
+ {
1020
+ className: classNames.rowGroup,
1021
+ "data-slot": "row-group",
1022
+ style: __spreadProps(__spreadValues({}, gridStyle), {
1023
+ height: isVirtualized ? `${virtualHeight}px` : "auto",
1024
+ position: "relative"
1025
+ }),
1026
+ role: "rowgroup",
1027
+ children: virtualRows.map((virtualRow) => {
1028
+ var _a3;
1029
+ const row = rows[virtualRow.index];
1030
+ const href = rowLink ? resolveRowHref(rowLink, row.original) : void 0;
1031
+ const RowLink = rowLink == null ? void 0 : rowLink.component;
1032
+ const rowContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1033
+ "div",
922
1034
  {
923
- className: (_a3 = classNames.rowLink) != null ? _a3 : "",
924
- href,
925
- "aria-label": resolveRowLinkLabel(rowLink, row.original),
926
- target: rowLink.target,
927
- rel: rowLink.rel,
928
- children: rowContent
1035
+ className: classNames.row,
1036
+ "data-slot": "row",
1037
+ role: "row",
1038
+ style: { display: "grid", gridTemplateColumns: "var(--boneless-table-grid)" },
1039
+ tabIndex: onRowClick && !href ? 0 : void 0,
1040
+ onClick: (event) => onRowClick == null ? void 0 : onRowClick(row.original, event),
1041
+ onKeyDown: (event) => {
1042
+ if (!onRowClick || href || event.key !== "Enter" && event.key !== " ")
1043
+ return;
1044
+ event.preventDefault();
1045
+ onRowClick(row.original, event);
1046
+ },
1047
+ children: row.getVisibleCells().map((cell) => {
1048
+ var _a4, _b3, _c2;
1049
+ const columnSettings = getColumnSettings(cell.column);
1050
+ const title = columnSettings.valueDisplay != null ? String((_a4 = cell.getValue()) != null ? _a4 : "") : void 0;
1051
+ const isTreeCell = Boolean(tree && cell.column.id === treeColumnId);
1052
+ const canExpand = row.getCanExpand();
1053
+ const cellContent = (0, import_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext());
1054
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1055
+ "div",
1056
+ {
1057
+ className: classNames.cell,
1058
+ "data-slot": "cell",
1059
+ "data-align": columnSettings.align,
1060
+ "data-borders": columnSettings.borders,
1061
+ role: "cell",
1062
+ title,
1063
+ children: isTreeCell ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1064
+ "div",
1065
+ {
1066
+ "data-slot": "tree-content",
1067
+ style: { paddingInlineStart: `${row.depth * treeIndentPx}px` },
1068
+ children: [
1069
+ canExpand ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1070
+ "button",
1071
+ {
1072
+ "data-slot": "tree-row-toggle",
1073
+ type: "button",
1074
+ "aria-expanded": row.getIsExpanded(),
1075
+ "aria-label": `${row.getIsExpanded() ? "Collapse" : "Expand"} row`,
1076
+ onClick: (event) => {
1077
+ event.stopPropagation();
1078
+ row.toggleExpanded();
1079
+ },
1080
+ children: row.getIsExpanded() ? (_b3 = icons == null ? void 0 : icons.collapse) != null ? _b3 : "\u2212" : (_c2 = icons == null ? void 0 : icons.expand) != null ? _c2 : "+"
1081
+ }
1082
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-slot": "tree-row-toggle-spacer", "aria-hidden": "true" }),
1083
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-slot": "tree-value", children: cellContent })
1084
+ ]
1085
+ }
1086
+ ) : cellContent
1087
+ },
1088
+ cell.id
1089
+ );
1090
+ })
929
1091
  }
930
- )
931
- },
932
- row.id
933
- );
934
- })
935
- }
936
- ),
937
- isFetchingMore ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
938
- TableSkeleton,
939
- {
940
- columnCount: visibleColumns.length,
941
- rows: 3,
942
- label: skeletonLabel,
943
- classNames
944
- }
945
- ) : null
946
- ]
947
- }
948
- )
949
- ]
950
- }
951
- ),
952
- renderSlot(footer, table, defaultFooter)
953
- ] });
1092
+ );
1093
+ const rowStyle = !isVirtualized ? void 0 : {
1094
+ position: "absolute",
1095
+ top: 0,
1096
+ left: 0,
1097
+ width: "100%",
1098
+ transform: `translateY(${virtualRow.start}px)`
1099
+ };
1100
+ if (!href || !rowLink || !RowLink || tree && row.getCanExpand())
1101
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1102
+ "div",
1103
+ {
1104
+ "data-index": isVirtualized ? virtualRow.index : void 0,
1105
+ ref: isVirtualized ? rowVirtualizer.measureElement : void 0,
1106
+ style: rowStyle,
1107
+ children: rowContent
1108
+ },
1109
+ row.id
1110
+ );
1111
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1112
+ "div",
1113
+ {
1114
+ "data-index": isVirtualized ? virtualRow.index : void 0,
1115
+ ref: isVirtualized ? rowVirtualizer.measureElement : void 0,
1116
+ style: rowStyle,
1117
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1118
+ RowLink,
1119
+ {
1120
+ className: (_a3 = classNames.rowLink) != null ? _a3 : "",
1121
+ href,
1122
+ "aria-label": resolveRowLinkLabel(rowLink, row.original),
1123
+ target: rowLink.target,
1124
+ rel: rowLink.rel,
1125
+ children: rowContent
1126
+ }
1127
+ )
1128
+ },
1129
+ row.id
1130
+ );
1131
+ })
1132
+ }
1133
+ ),
1134
+ isFetchingMore ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1135
+ TableSkeleton,
1136
+ {
1137
+ columnCount: visibleColumns.length,
1138
+ rows: 3,
1139
+ label: skeletonLabel,
1140
+ classNames
1141
+ }
1142
+ ) : null
1143
+ ]
1144
+ }
1145
+ )
1146
+ ]
1147
+ }
1148
+ ),
1149
+ filterPlacement === "below" ? renderedFilters : null,
1150
+ renderSlot(footer, table, defaultFooter)
1151
+ ]
1152
+ }
1153
+ );
954
1154
  }
955
1155
 
956
1156
  // src/index.ts