@jinaan/uikit 0.1.46 → 0.1.47
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 +6 -1
- package/dist/data-table.d.ts.map +1 -1
- package/dist/index.js +754 -715
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/data-table.tsx +89 -33
package/package.json
CHANGED
package/src/data-table.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
X,
|
|
14
14
|
} from "@phosphor-icons/react";
|
|
15
15
|
import {
|
|
16
|
+
Fragment,
|
|
16
17
|
useCallback,
|
|
17
18
|
useEffect,
|
|
18
19
|
useLayoutEffect,
|
|
@@ -138,6 +139,11 @@ interface DataTableProps<T> {
|
|
|
138
139
|
bulkActions?: BulkAction<T>[];
|
|
139
140
|
|
|
140
141
|
rowActions?: (row: T) => ReactNode;
|
|
142
|
+
/**
|
|
143
|
+
* Expanding rows: renders a chevron toggle cell at the row start and the
|
|
144
|
+
* returned content in a full-width muted band beneath the row.
|
|
145
|
+
*/
|
|
146
|
+
renderExpanded?: (row: T) => ReactNode;
|
|
141
147
|
onRowClick?: (row: T) => void;
|
|
142
148
|
|
|
143
149
|
defaultSort?: { id: string; dir: "asc" | "desc" };
|
|
@@ -233,6 +239,7 @@ export function DataTable<T>({
|
|
|
233
239
|
selectable = false,
|
|
234
240
|
bulkActions,
|
|
235
241
|
rowActions,
|
|
242
|
+
renderExpanded,
|
|
236
243
|
onRowClick,
|
|
237
244
|
defaultSort,
|
|
238
245
|
sort: sortProp,
|
|
@@ -268,6 +275,15 @@ export function DataTable<T>({
|
|
|
268
275
|
const [page, setPage] = useState(0);
|
|
269
276
|
const [pageSize, setPageSize] = useState(initialPageSize);
|
|
270
277
|
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
278
|
+
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
|
279
|
+
const toggleExpanded = (id: string) => {
|
|
280
|
+
setExpanded((prev) => {
|
|
281
|
+
const next = new Set(prev);
|
|
282
|
+
if (next.has(id)) next.delete(id);
|
|
283
|
+
else next.add(id);
|
|
284
|
+
return next;
|
|
285
|
+
});
|
|
286
|
+
};
|
|
271
287
|
const [activeFilterIds, setActiveFilterIds] = useState<string[]>([]);
|
|
272
288
|
|
|
273
289
|
const propOrder = columns.map((c) => c.id);
|
|
@@ -398,7 +414,7 @@ export function DataTable<T>({
|
|
|
398
414
|
// order). The pinned colgroup maps positionally onto the columns, so any
|
|
399
415
|
// structural change invalidates the measured widths — otherwise the new
|
|
400
416
|
// column steals its neighbor's width and every column shifts by one.
|
|
401
|
-
const structureKey = `${selectable ? "s" : "-"}|${rowActions ? "a" : "-"}|${columnKey}`;
|
|
417
|
+
const structureKey = `${selectable ? "s" : "-"}|${rowActions ? "a" : "-"}|${renderExpanded ? "e" : "-"}|${columnKey}`;
|
|
402
418
|
const structureRef = useRef(structureKey);
|
|
403
419
|
const pinned = columnWidths.length > 0;
|
|
404
420
|
|
|
@@ -772,6 +788,7 @@ export function DataTable<T>({
|
|
|
772
788
|
/>
|
|
773
789
|
</th>
|
|
774
790
|
)}
|
|
791
|
+
{renderExpanded && <th className="h-(--table-header-h) w-11 px-(--table-pad-x)" />}
|
|
775
792
|
{visibleColumns.map((c) => (
|
|
776
793
|
<th
|
|
777
794
|
key={c.id}
|
|
@@ -886,6 +903,7 @@ export function DataTable<T>({
|
|
|
886
903
|
<thead className="sr-only">
|
|
887
904
|
<tr>
|
|
888
905
|
{selectable && <th scope="col">Select</th>}
|
|
906
|
+
{renderExpanded && <th scope="col">Details</th>}
|
|
889
907
|
{visibleColumns.map((c) => (
|
|
890
908
|
<th key={c.id} scope="col" aria-sort={ariaSort(c)}>
|
|
891
909
|
{c.header}
|
|
@@ -898,22 +916,49 @@ export function DataTable<T>({
|
|
|
898
916
|
{pageRows.map((row) => {
|
|
899
917
|
const id = getRowId(row);
|
|
900
918
|
const isSelected = selected.has(id);
|
|
919
|
+
const isExpanded = expanded.has(id);
|
|
920
|
+
const columnCount =
|
|
921
|
+
visibleColumns.length +
|
|
922
|
+
(selectable ? 1 : 0) +
|
|
923
|
+
(renderExpanded ? 1 : 0) +
|
|
924
|
+
(rowActions ? 1 : 0);
|
|
901
925
|
return (
|
|
902
|
-
<
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
926
|
+
<Fragment key={id}>
|
|
927
|
+
<TableRow
|
|
928
|
+
data-state={isSelected ? "selected" : undefined}
|
|
929
|
+
onClick={onRowClick ? () => onRowClick(row) : undefined}
|
|
930
|
+
className={onRowClick ? "cursor-pointer" : undefined}
|
|
931
|
+
>
|
|
932
|
+
{selectable && (
|
|
933
|
+
<TableCell className="w-11" onClick={(e) => e.stopPropagation()}>
|
|
934
|
+
<Checkbox
|
|
935
|
+
aria-label="Select row"
|
|
936
|
+
checked={isSelected}
|
|
937
|
+
onCheckedChange={() => toggleOne(id)}
|
|
938
|
+
/>
|
|
939
|
+
</TableCell>
|
|
940
|
+
)}
|
|
941
|
+
{renderExpanded && (
|
|
942
|
+
<TableCell className="w-11" onClick={(e) => e.stopPropagation()}>
|
|
943
|
+
<Button
|
|
944
|
+
type="button"
|
|
945
|
+
variant="ghost"
|
|
946
|
+
size="icon"
|
|
947
|
+
className="size-7"
|
|
948
|
+
aria-label={isExpanded ? "Collapse row" : "Expand row"}
|
|
949
|
+
aria-expanded={isExpanded}
|
|
950
|
+
onClick={() => toggleExpanded(id)}
|
|
951
|
+
>
|
|
952
|
+
<CaretDown
|
|
953
|
+
className={cn(
|
|
954
|
+
"size-3.5 text-muted transition-transform motion-safe:duration-200",
|
|
955
|
+
isExpanded ? "" : "-rotate-90",
|
|
956
|
+
)}
|
|
957
|
+
weight="bold"
|
|
958
|
+
/>
|
|
959
|
+
</Button>
|
|
960
|
+
</TableCell>
|
|
961
|
+
)}
|
|
917
962
|
{visibleColumns.map((c) => (
|
|
918
963
|
<TableCell
|
|
919
964
|
key={c.id}
|
|
@@ -923,23 +968,34 @@ export function DataTable<T>({
|
|
|
923
968
|
{c.cell(row)}
|
|
924
969
|
</TableCell>
|
|
925
970
|
))}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
971
|
+
{rowActions && (
|
|
972
|
+
<TableCell
|
|
973
|
+
className="w-44 px-4 text-right"
|
|
974
|
+
onClick={(e) => {
|
|
975
|
+
// Dead-zone fix: only swallow clicks on the
|
|
976
|
+
// action controls themselves (menus, buttons);
|
|
977
|
+
// the cell's padding stays part of the clickable
|
|
978
|
+
// row.
|
|
979
|
+
if ((e.target as HTMLElement).closest("button, a, input, [role='menuitem']")) {
|
|
980
|
+
e.stopPropagation();
|
|
981
|
+
}
|
|
982
|
+
}}
|
|
983
|
+
>
|
|
984
|
+
{rowActions(row)}
|
|
985
|
+
</TableCell>
|
|
986
|
+
)}
|
|
987
|
+
</TableRow>
|
|
988
|
+
{renderExpanded && isExpanded ? (
|
|
989
|
+
<TableRow className="hover:bg-inherit" data-expanded="">
|
|
990
|
+
<TableCell
|
|
991
|
+
colSpan={columnCount}
|
|
992
|
+
className="border-t border-line bg-elevated/60 px-(--table-pad-x) py-3 align-top text-[13px] text-muted"
|
|
993
|
+
>
|
|
994
|
+
{renderExpanded(row)}
|
|
995
|
+
</TableCell>
|
|
996
|
+
</TableRow>
|
|
997
|
+
) : null}
|
|
998
|
+
</Fragment>
|
|
943
999
|
);
|
|
944
1000
|
})}
|
|
945
1001
|
</TableBody>
|