@jinaan/uikit 0.1.39 → 0.1.40
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/data-table.d.ts.map +1 -1
- package/dist/index.js +690 -651
- package/dist/index.js.map +1 -1
- package/dist/table-surface.d.ts +11 -2
- package/dist/table-surface.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/data-table.tsx +110 -41
- package/src/table-surface.tsx +64 -28
package/dist/table-surface.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
1
|
+
import type { ReactNode, Ref } from "react";
|
|
2
2
|
export type TableSurfaceTone = "default" | "muted" | "transparent";
|
|
3
3
|
export interface TableSurfaceAction {
|
|
4
4
|
label: string;
|
|
@@ -29,6 +29,15 @@ interface TableSurfaceProps {
|
|
|
29
29
|
panelClassName?: string;
|
|
30
30
|
/** Minimum panel height; keeps empty states from collapsing. */
|
|
31
31
|
minHeight?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Where horizontal scrolling lives. `surface` (default) scrolls band and
|
|
34
|
+
* panel together — right for short content. `panel` keeps both shells fixed
|
|
35
|
+
* while the caller puts the scroller inside the panel; the band content is
|
|
36
|
+
* then expected to translate in lockstep via `headerContentRef`.
|
|
37
|
+
*/
|
|
38
|
+
scrollMode?: "surface" | "panel";
|
|
39
|
+
/** Panel mode only: ref for the band's translating inner wrapper. */
|
|
40
|
+
headerContentRef?: Ref<HTMLDivElement>;
|
|
32
41
|
}
|
|
33
42
|
/**
|
|
34
43
|
* Layered table surface: an outer shell holding a header band and an inset
|
|
@@ -37,6 +46,6 @@ interface TableSurfaceProps {
|
|
|
37
46
|
* Colors come from the `--table-*` tokens and can be adjusted per surface with
|
|
38
47
|
* `tone` plus `headerClassName` / `panelClassName`.
|
|
39
48
|
*/
|
|
40
|
-
export declare function TableSurface({ title, description, header, children, action, tone, className, headerClassName, panelClassName, minHeight, }: TableSurfaceProps): import("react").JSX.Element;
|
|
49
|
+
export declare function TableSurface({ title, description, header, children, action, tone, className, headerClassName, panelClassName, minHeight, scrollMode, headerContentRef, }: TableSurfaceProps): import("react").JSX.Element;
|
|
41
50
|
export {};
|
|
42
51
|
//# sourceMappingURL=table-surface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-surface.d.ts","sourceRoot":"","sources":["../src/table-surface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"table-surface.d.ts","sourceRoot":"","sources":["../src/table-surface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAM5C,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;IAC1D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,iBAAiB;IACzB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uCAAuC;IACvC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,yDAAyD;IACzD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAAC;IACxC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IACjC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CACxC;AAyBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAgB,EAChB,SAAS,EACT,eAAe,EACf,cAAc,EACd,SAAS,EACT,UAAsB,EACtB,gBAAgB,GACjB,EAAE,iBAAiB,+BAuFnB"}
|
package/package.json
CHANGED
package/src/data-table.tsx
CHANGED
|
@@ -12,7 +12,15 @@ import {
|
|
|
12
12
|
WarningCircle,
|
|
13
13
|
X,
|
|
14
14
|
} from "@phosphor-icons/react";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
useCallback,
|
|
17
|
+
useEffect,
|
|
18
|
+
useLayoutEffect,
|
|
19
|
+
useMemo,
|
|
20
|
+
useRef,
|
|
21
|
+
useState,
|
|
22
|
+
type ReactNode,
|
|
23
|
+
} from "react";
|
|
16
24
|
|
|
17
25
|
import { Avatar, AvatarFallback, AvatarImage } from "./avatar";
|
|
18
26
|
import { Button } from "./button";
|
|
@@ -354,20 +362,43 @@ export function DataTable<T>({
|
|
|
354
362
|
// same pixel widths; both tables share the surface's horizontal scroller.
|
|
355
363
|
const bodyTableRef = useRef<HTMLTableElement | null>(null);
|
|
356
364
|
const bandTableRef = useRef<HTMLTableElement | null>(null);
|
|
365
|
+
const bandContentRef = useRef<HTMLDivElement | null>(null);
|
|
366
|
+
const scrollerRef = useRef<HTMLDivElement | null>(null);
|
|
357
367
|
const [columnWidths, setColumnWidths] = useState<number[]>([]);
|
|
358
368
|
// Deps must be primitives: visibleColumns is a fresh array every render and
|
|
359
369
|
// would re-run this effect (and its setState) in a loop.
|
|
360
370
|
const columnKey = visibleColumns.map((c) => c.id).join("\u0000");
|
|
371
|
+
// Identity of the rendered column set (selection, actions, visibility,
|
|
372
|
+
// order). The pinned colgroup maps positionally onto the columns, so any
|
|
373
|
+
// structural change invalidates the measured widths — otherwise the new
|
|
374
|
+
// column steals its neighbor's width and every column shifts by one.
|
|
375
|
+
const structureKey = `${selectable ? "s" : "-"}|${rowActions ? "a" : "-"}|${columnKey}`;
|
|
376
|
+
const structureRef = useRef(structureKey);
|
|
377
|
+
const pinned = columnWidths.length > 0;
|
|
378
|
+
|
|
379
|
+
// Panel-scroll mode: the band stays fixed to the shell and cannot scroll
|
|
380
|
+
// natively, so it translates by the row scroller's scrollLeft to keep every
|
|
381
|
+
// title over its column. Direct DOM write — no re-render per scroll event.
|
|
382
|
+
const syncBandScroll = useCallback(() => {
|
|
383
|
+
const band = bandContentRef.current;
|
|
384
|
+
const scroller = scrollerRef.current;
|
|
385
|
+
if (band && scroller) band.style.transform = `translateX(${-scroller.scrollLeft}px)`;
|
|
386
|
+
}, []);
|
|
361
387
|
|
|
362
388
|
useLayoutEffect(() => {
|
|
363
389
|
const table = bodyTableRef.current;
|
|
364
390
|
if (!table) return;
|
|
391
|
+
if (structureRef.current !== structureKey) {
|
|
392
|
+
// Column set changed: drop the pinned widths so the body re-renders
|
|
393
|
+
// content-sized (table-auto) and the next pass measures intrinsic
|
|
394
|
+
// widths against the new structure. Without this, the effect would
|
|
395
|
+
// measure the stale colgroup's shifted layout and pin the wrong widths.
|
|
396
|
+
structureRef.current = structureKey;
|
|
397
|
+
setColumnWidths((prev) => (prev.length === 0 ? prev : []));
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
365
400
|
const measure = () => {
|
|
366
401
|
const cells = table.tBodies[0]?.rows.item(0)?.cells;
|
|
367
|
-
// The band may be squeezed narrower than its own sort-button content by
|
|
368
|
-
// the body-measured widths; scrollWidth reports the true minimum, so it
|
|
369
|
-
// floors each column and stops titles from overflowing their neighbors.
|
|
370
|
-
const bandCells = bandTableRef.current?.querySelectorAll("thead th");
|
|
371
402
|
if (!cells || cells.length === 0) {
|
|
372
403
|
setColumnWidths((prev) => (prev.length === 0 ? prev : []));
|
|
373
404
|
return;
|
|
@@ -375,10 +406,19 @@ export function DataTable<T>({
|
|
|
375
406
|
// Widths cover every rendered column — including the selection checkbox
|
|
376
407
|
// and row-actions cells — in order, so one <col> per entry maps 1:1 in
|
|
377
408
|
// both colgroups. Never add extra <col> elements alongside these.
|
|
409
|
+
//
|
|
410
|
+
// Header floor: read the th's sizer span, never the th/cell layout
|
|
411
|
+
// itself. Once pinned with w-full, fixed-layout columns render wider
|
|
412
|
+
// than their content (surplus distribution) and reading them back would
|
|
413
|
+
// ratchet totalWidth up to the container size — after any container
|
|
414
|
+
// shrink the stale minWidth would keep a scrollbar alive forever. The
|
|
415
|
+
// sizer span is intrinsic in every state. Widths stay unrounded so the
|
|
416
|
+
// sum is the exact content requirement.
|
|
417
|
+
const bandThs = bandTableRef.current?.querySelectorAll("thead th");
|
|
378
418
|
const widths = Array.from(cells, (cell, i) =>
|
|
379
419
|
Math.max(
|
|
380
|
-
|
|
381
|
-
|
|
420
|
+
cell.getBoundingClientRect().width,
|
|
421
|
+
bandThs?.item(i)?.querySelector("[data-col-sizer]")?.getBoundingClientRect().width ?? 0,
|
|
382
422
|
),
|
|
383
423
|
);
|
|
384
424
|
// Bail out when nothing changed: a new array would re-render, and the
|
|
@@ -388,11 +428,16 @@ export function DataTable<T>({
|
|
|
388
428
|
);
|
|
389
429
|
};
|
|
390
430
|
measure();
|
|
431
|
+
syncBandScroll();
|
|
391
432
|
if (typeof ResizeObserver === "undefined") return;
|
|
392
433
|
const observer = new ResizeObserver(measure);
|
|
393
434
|
observer.observe(table);
|
|
394
435
|
return () => observer.disconnect();
|
|
395
|
-
|
|
436
|
+
// `pinned` re-runs this effect after the structure reset clears the
|
|
437
|
+
// widths (false) and again after re-pinning (true). Safe to measure in
|
|
438
|
+
// the pinned state because the floor reads sizer spans — intrinsic in
|
|
439
|
+
// every state — never the pinned layout itself.
|
|
440
|
+
}, [structureKey, pinned, loading, error, syncBandScroll]);
|
|
396
441
|
|
|
397
442
|
const totalWidth = columnWidths.reduce((sum, width) => sum + width, 0);
|
|
398
443
|
|
|
@@ -657,6 +702,8 @@ export function DataTable<T>({
|
|
|
657
702
|
)}
|
|
658
703
|
|
|
659
704
|
<TableSurface
|
|
705
|
+
scrollMode="panel"
|
|
706
|
+
headerContentRef={bandContentRef}
|
|
660
707
|
action={headerAction}
|
|
661
708
|
tone={tone}
|
|
662
709
|
headerClassName={headerClassName}
|
|
@@ -670,7 +717,9 @@ export function DataTable<T>({
|
|
|
670
717
|
role="presentation"
|
|
671
718
|
className="w-full table-fixed border-collapse"
|
|
672
719
|
style={{
|
|
673
|
-
|
|
720
|
+
// Fill the container when it fits; force totalWidth (and the
|
|
721
|
+
// shared scroller) only when the columns need more room.
|
|
722
|
+
minWidth: totalWidth > 0 ? totalWidth : undefined,
|
|
674
723
|
visibility: totalWidth > 0 ? undefined : "hidden",
|
|
675
724
|
}}
|
|
676
725
|
>
|
|
@@ -681,8 +730,11 @@ export function DataTable<T>({
|
|
|
681
730
|
</colgroup>
|
|
682
731
|
<thead>
|
|
683
732
|
<tr>
|
|
733
|
+
{/* text-left: UA stylesheets center th content; without this
|
|
734
|
+
the select-all checkbox centers in its (surplus-widened)
|
|
735
|
+
column and drifts right of the row checkboxes. */}
|
|
684
736
|
{selectable && (
|
|
685
|
-
<th className="h-(--table-header-h) w-11 px-
|
|
737
|
+
<th className="h-(--table-header-h) w-11 px-(--table-pad-x) text-left align-middle">
|
|
686
738
|
<Checkbox
|
|
687
739
|
aria-label="Select all rows"
|
|
688
740
|
checked={allSelected ? true : someSelected ? "indeterminate" : false}
|
|
@@ -695,34 +747,44 @@ export function DataTable<T>({
|
|
|
695
747
|
key={c.id}
|
|
696
748
|
className={cn(HEADER_CELL, c.align === "right" && "text-right", c.className)}
|
|
697
749
|
>
|
|
698
|
-
{
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
750
|
+
{/* Sizer: shrink-wraps the title (sort carets included) so
|
|
751
|
+
its rect is the column's intrinsic header width even
|
|
752
|
+
while the fixed layout squeezes the th. The negative
|
|
753
|
+
margins cancel the cell padding the span adds, so the
|
|
754
|
+
measured width is directly comparable to cell widths. */}
|
|
755
|
+
<span
|
|
756
|
+
data-col-sizer
|
|
757
|
+
className="inline-block whitespace-nowrap px-(--table-pad-x) -mx-(--table-pad-x)"
|
|
758
|
+
>
|
|
759
|
+
{c.sortable ? (
|
|
760
|
+
<Button
|
|
761
|
+
type="button"
|
|
762
|
+
variant="ghost"
|
|
763
|
+
size="xs"
|
|
764
|
+
aria-label={`Sort by ${c.header}`}
|
|
765
|
+
onClick={() => toggleSort(c)}
|
|
766
|
+
className={cn(
|
|
767
|
+
"h-auto gap-1.5 rounded-none px-0 py-0 text-[0.8125rem] text-table-header transition-colors [&_svg]:size-3.5",
|
|
768
|
+
"hover:bg-transparent hover:text-table-header-active hover:shadow-none",
|
|
769
|
+
"active:scale-100 active:bg-transparent active:shadow-none",
|
|
770
|
+
sort?.id === c.id && "text-table-header-active",
|
|
771
|
+
)}
|
|
772
|
+
>
|
|
773
|
+
{c.header}
|
|
774
|
+
{sort?.id === c.id ? (
|
|
775
|
+
sort.dir === "asc" ? (
|
|
776
|
+
<CaretUp className="size-3.5" weight="bold" />
|
|
777
|
+
) : (
|
|
778
|
+
<CaretDown className="size-3.5" weight="bold" />
|
|
779
|
+
)
|
|
716
780
|
) : (
|
|
717
|
-
<
|
|
718
|
-
)
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
c.header
|
|
725
|
-
)}
|
|
781
|
+
<CaretUpDown className="size-3.5 opacity-50" />
|
|
782
|
+
)}
|
|
783
|
+
</Button>
|
|
784
|
+
) : (
|
|
785
|
+
c.header
|
|
786
|
+
)}
|
|
787
|
+
</span>
|
|
726
788
|
</th>
|
|
727
789
|
))}
|
|
728
790
|
{rowActions && (
|
|
@@ -735,6 +797,10 @@ export function DataTable<T>({
|
|
|
735
797
|
</table>
|
|
736
798
|
}
|
|
737
799
|
>
|
|
800
|
+
{/* The scroller lives inside the panel: both shells stay fixed while
|
|
801
|
+
only the row content scrolls, and onScroll keeps the band titles
|
|
802
|
+
translated in lockstep with the rows. */}
|
|
803
|
+
<div ref={scrollerRef} className="overflow-x-auto" onScroll={syncBandScroll}>
|
|
738
804
|
{loading ? (
|
|
739
805
|
<div className="space-y-2 p-4">
|
|
740
806
|
{[0, 1, 2].map((i) => (
|
|
@@ -772,10 +838,12 @@ export function DataTable<T>({
|
|
|
772
838
|
"border-collapse text-left",
|
|
773
839
|
// Unmeasured: content-sized so intrinsic column widths can be
|
|
774
840
|
// measured (w-full would squeeze columns into the container).
|
|
775
|
-
// Measured: pinned to the band's colgroup
|
|
841
|
+
// Measured: fill the container, pinned to the band's colgroup
|
|
842
|
+
// pixel widths; minWidth forces the shared scroller open only
|
|
843
|
+
// when the columns need more room than the container has.
|
|
776
844
|
columnWidths.length > 0 ? "w-full table-fixed" : "table-auto",
|
|
777
845
|
)}
|
|
778
|
-
style={{
|
|
846
|
+
style={{ minWidth: totalWidth > 0 ? totalWidth : undefined }}
|
|
779
847
|
>
|
|
780
848
|
{columnWidths.length > 0 && (
|
|
781
849
|
<colgroup>
|
|
@@ -808,7 +876,7 @@ export function DataTable<T>({
|
|
|
808
876
|
className={onRowClick ? "cursor-pointer" : undefined}
|
|
809
877
|
>
|
|
810
878
|
{selectable && (
|
|
811
|
-
<TableCell className="w-11
|
|
879
|
+
<TableCell className="w-11" onClick={(e) => e.stopPropagation()}>
|
|
812
880
|
<Checkbox
|
|
813
881
|
aria-label="Select row"
|
|
814
882
|
checked={isSelected}
|
|
@@ -836,7 +904,8 @@ export function DataTable<T>({
|
|
|
836
904
|
</TableBody>
|
|
837
905
|
</table>
|
|
838
906
|
)}
|
|
839
|
-
|
|
907
|
+
</div>
|
|
908
|
+
</TableSurface>
|
|
840
909
|
|
|
841
910
|
{showPagination && (
|
|
842
911
|
<div className="flex flex-wrap items-center justify-between gap-3 text-sm">
|
package/src/table-surface.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
1
|
+
import type { ReactNode, Ref } from "react";
|
|
2
2
|
|
|
3
3
|
import { Button } from "./button";
|
|
4
4
|
import { TableContainer, TablePanel } from "./table";
|
|
@@ -36,6 +36,15 @@ interface TableSurfaceProps {
|
|
|
36
36
|
panelClassName?: string;
|
|
37
37
|
/** Minimum panel height; keeps empty states from collapsing. */
|
|
38
38
|
minHeight?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Where horizontal scrolling lives. `surface` (default) scrolls band and
|
|
41
|
+
* panel together — right for short content. `panel` keeps both shells fixed
|
|
42
|
+
* while the caller puts the scroller inside the panel; the band content is
|
|
43
|
+
* then expected to translate in lockstep via `headerContentRef`.
|
|
44
|
+
*/
|
|
45
|
+
scrollMode?: "surface" | "panel";
|
|
46
|
+
/** Panel mode only: ref for the band's translating inner wrapper. */
|
|
47
|
+
headerContentRef?: Ref<HTMLDivElement>;
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
const SHELL_TONE: Record<TableSurfaceTone, string> = {
|
|
@@ -79,8 +88,11 @@ export function TableSurface({
|
|
|
79
88
|
headerClassName,
|
|
80
89
|
panelClassName,
|
|
81
90
|
minHeight,
|
|
91
|
+
scrollMode = "surface",
|
|
92
|
+
headerContentRef,
|
|
82
93
|
}: TableSurfaceProps) {
|
|
83
94
|
const hasTitle = Boolean(title || description);
|
|
95
|
+
const panelScroll = scrollMode === "panel";
|
|
84
96
|
const actionNode = isActionConfig(action) ? (
|
|
85
97
|
<Button
|
|
86
98
|
variant={action.variant ?? "primary"}
|
|
@@ -103,37 +115,61 @@ export function TableSurface({
|
|
|
103
115
|
action
|
|
104
116
|
);
|
|
105
117
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
const band =
|
|
119
|
+
header || hasTitle ? (
|
|
120
|
+
// Header rows must not inherit the body row hover surface. Panel mode
|
|
121
|
+
// clips the band instead of scrolling it; the caller translates the
|
|
122
|
+
// inner wrapper so titles track the row content. px-px mirrors the
|
|
123
|
+
// panel's 1px border so band and body share the same width context —
|
|
124
|
+
// identical fixed-layout distribution keeps every column aligned.
|
|
125
|
+
<div
|
|
126
|
+
className={cn(
|
|
127
|
+
"[--table-row-hover:transparent] text-table-header",
|
|
128
|
+
panelScroll && "overflow-hidden px-px",
|
|
129
|
+
headerClassName,
|
|
130
|
+
)}
|
|
131
|
+
>
|
|
132
|
+
{hasTitle ? (
|
|
133
|
+
<div
|
|
134
|
+
className={cn(
|
|
135
|
+
"px-(--table-pad-x) pb-3 pt-4",
|
|
136
|
+
actionNode && "pr-28",
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
{title ? (
|
|
140
|
+
<div className="text-sm font-semibold text-fg">{title}</div>
|
|
141
|
+
) : null}
|
|
142
|
+
{description ? (
|
|
143
|
+
<div className="mt-0.5 text-sm text-muted">{description}</div>
|
|
126
144
|
) : null}
|
|
127
|
-
{header}
|
|
128
145
|
</div>
|
|
129
146
|
) : null}
|
|
130
|
-
<
|
|
131
|
-
className={cn(PANEL_TONE[tone], panelClassName)}
|
|
132
|
-
style={minHeight ? { minHeight } : undefined}
|
|
133
|
-
>
|
|
134
|
-
{children}
|
|
135
|
-
</TablePanel>
|
|
147
|
+
{panelScroll ? <div ref={headerContentRef}>{header}</div> : header}
|
|
136
148
|
</div>
|
|
149
|
+
) : null;
|
|
150
|
+
|
|
151
|
+
const panel = (
|
|
152
|
+
<TablePanel
|
|
153
|
+
className={cn(PANEL_TONE[tone], panelClassName)}
|
|
154
|
+
style={minHeight ? { minHeight } : undefined}
|
|
155
|
+
>
|
|
156
|
+
{children}
|
|
157
|
+
</TablePanel>
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<TableContainer className={cn("relative", SHELL_TONE[tone], className)}>
|
|
162
|
+
{panelScroll ? (
|
|
163
|
+
<>
|
|
164
|
+
{band}
|
|
165
|
+
{panel}
|
|
166
|
+
</>
|
|
167
|
+
) : (
|
|
168
|
+
<div className="overflow-x-auto">
|
|
169
|
+
{band}
|
|
170
|
+
{panel}
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
137
173
|
{actionNode ? (
|
|
138
174
|
<div className="pointer-events-none absolute right-4 top-(--table-inset) flex h-(--table-header-h) items-center">
|
|
139
175
|
<div className="pointer-events-auto">{actionNode}</div>
|