@geomak/ui 1.7.2 → 1.7.3
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.cjs +120 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -18
- package/dist/index.d.ts +75 -18
- package/dist/index.js +120 -96
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -30
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -885,11 +885,34 @@ interface WizardProps {
|
|
|
885
885
|
declare function Wizard({ children, steps, storageKey }: WizardProps): react_jsx_runtime.JSX.Element;
|
|
886
886
|
|
|
887
887
|
/** ─────────────────── types ─────────────────── */
|
|
888
|
-
|
|
889
|
-
|
|
888
|
+
/**
|
|
889
|
+
* Column descriptor for the Table.
|
|
890
|
+
*
|
|
891
|
+
* The generic `T` is the shape of a row — `keyBind` must be one of T's
|
|
892
|
+
* string-keyed properties, and `component(cellValue, row)` receives the
|
|
893
|
+
* matching value with full type inference. When used without a generic
|
|
894
|
+
* (`TableColumn[]`), `T` falls back to `Record<string, any>` for backwards
|
|
895
|
+
* compatibility — narrower typing is preferred whenever possible:
|
|
896
|
+
*
|
|
897
|
+
* ```ts
|
|
898
|
+
* type Vessel = { id: number; name: string; status: 'At Sea' | 'In Port' }
|
|
899
|
+
* const cols: TableColumn<Vessel>[] = [
|
|
900
|
+
* { key: 'name', label: 'Name', keyBind: 'name' }, // cellValue inferred as string
|
|
901
|
+
* ]
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
interface TableColumn<T extends Record<string, any> = Record<string, any>> {
|
|
905
|
+
/** React reconciliation key for the column itself. */
|
|
906
|
+
key: React$1.Key;
|
|
890
907
|
label: React$1.ReactNode;
|
|
891
|
-
|
|
892
|
-
|
|
908
|
+
/** Property on the row to read for this column. */
|
|
909
|
+
keyBind: keyof T & string;
|
|
910
|
+
/** Custom cell renderer. Receives the cell value and the full row. */
|
|
911
|
+
component?: (cellValue: T[keyof T], row: T) => React$1.ReactNode;
|
|
912
|
+
/** Explicit column width (CSS length or px number). Optional — defaults to auto. */
|
|
913
|
+
width?: string | number;
|
|
914
|
+
/** Text alignment for both header and cells. Defaults to `'center'`. */
|
|
915
|
+
align?: 'left' | 'center' | 'right';
|
|
893
916
|
}
|
|
894
917
|
interface PaginationOptions {
|
|
895
918
|
enabled?: boolean;
|
|
@@ -910,36 +933,70 @@ interface PaginationOptions {
|
|
|
910
933
|
onPageChange?: (page: number) => void;
|
|
911
934
|
onPerPageChange?: (perPage: number) => void;
|
|
912
935
|
}
|
|
913
|
-
interface ExpandRowOptions {
|
|
936
|
+
interface ExpandRowOptions<T extends Record<string, any> = Record<string, any>> {
|
|
914
937
|
enabled?: boolean;
|
|
915
938
|
expandIcon?: React$1.ReactNode;
|
|
916
|
-
expandComponent?: (row:
|
|
939
|
+
expandComponent?: (row: T) => React$1.ReactNode;
|
|
917
940
|
}
|
|
918
|
-
interface TableProps {
|
|
919
|
-
columns?: TableColumn[];
|
|
920
|
-
rows?:
|
|
941
|
+
interface TableProps<T extends Record<string, any> = Record<string, any>> {
|
|
942
|
+
columns?: TableColumn<T>[];
|
|
943
|
+
rows?: T[];
|
|
944
|
+
/**
|
|
945
|
+
* Returns a stable key for each row, used for React reconciliation AND
|
|
946
|
+
* for tracking expanded state when `expandRow.enabled` is true.
|
|
947
|
+
* Defaults to the row index — fine for static lists, but pass an
|
|
948
|
+
* explicit getter (e.g. `(row) => row.id`) if rows can be reordered or
|
|
949
|
+
* filtered while expand state should persist.
|
|
950
|
+
*/
|
|
951
|
+
getRowKey?: (row: T, index: number) => React$1.Key;
|
|
921
952
|
pagination?: PaginationOptions;
|
|
922
|
-
expandRow?: ExpandRowOptions
|
|
953
|
+
expandRow?: ExpandRowOptions<T>;
|
|
923
954
|
hasSearch?: boolean;
|
|
924
955
|
footer?: React$1.ReactNode;
|
|
925
956
|
header?: React$1.ReactNode;
|
|
926
|
-
tableRef?: React$1.Ref<any>;
|
|
927
|
-
[key: string]: any;
|
|
928
957
|
}
|
|
929
958
|
/** ─────────────────── main component ─────────────────── */
|
|
930
959
|
/**
|
|
931
960
|
* Data table with optional search, pagination, and expandable rows.
|
|
932
961
|
*
|
|
933
|
-
*
|
|
962
|
+
* - **Typed rows**: pass a generic `T` for full type inference on columns
|
|
963
|
+
* and cell renderers (`<Table<Vessel> ... />`).
|
|
964
|
+
* - **Real `<table>` semantics**: keeps row / col / cell context intact for
|
|
965
|
+
* screen readers and lets the browser handle column sizing natively.
|
|
966
|
+
* Per-column widths via `column.width`.
|
|
967
|
+
* - **Search**: client-side filter across ALL row values; result is
|
|
968
|
+
* memoized so each keystroke costs O(n) once per term change, not per
|
|
969
|
+
* render. Set `pagination.serverSide` to skip client-side filter and
|
|
970
|
+
* pagination entirely.
|
|
971
|
+
* - **Expand**: each row gets a real `<button>` with `aria-expanded`.
|
|
972
|
+
* Expand state is keyed by `getRowKey(row, i)` so it survives reorders.
|
|
973
|
+
*
|
|
974
|
+
* @example Static, fully typed
|
|
975
|
+
* ```tsx
|
|
976
|
+
* type Vessel = { id: number; name: string; status: string }
|
|
977
|
+
* <Table<Vessel>
|
|
978
|
+
* columns={[
|
|
979
|
+
* { key: 'name', label: 'Name', keyBind: 'name' },
|
|
980
|
+
* { key: 'status', label: 'Status', keyBind: 'status', width: 120 },
|
|
981
|
+
* ]}
|
|
982
|
+
* rows={vessels}
|
|
983
|
+
* getRowKey={(row) => row.id}
|
|
984
|
+
* />
|
|
985
|
+
* ```
|
|
934
986
|
*
|
|
935
|
-
* @example
|
|
987
|
+
* @example Server-side pagination
|
|
988
|
+
* ```tsx
|
|
936
989
|
* <Table
|
|
937
|
-
* columns={
|
|
938
|
-
* rows={
|
|
939
|
-
* pagination={{
|
|
990
|
+
* columns={cols}
|
|
991
|
+
* rows={pageRows}
|
|
992
|
+
* pagination={{
|
|
993
|
+
* enabled: true, serverSide: true, perPage: 20,
|
|
994
|
+
* page: currentPage, totalCount, onPageChange, onPerPageChange,
|
|
995
|
+
* }}
|
|
940
996
|
* />
|
|
997
|
+
* ```
|
|
941
998
|
*/
|
|
942
|
-
declare function Table({ columns, rows, pagination, expandRow, hasSearch, footer, header, }: TableProps): react_jsx_runtime.JSX.Element;
|
|
999
|
+
declare function Table<T extends Record<string, any> = Record<string, any>>({ columns, rows, getRowKey, pagination, expandRow, hasSearch, footer, header, }: TableProps<T>): react_jsx_runtime.JSX.Element;
|
|
943
1000
|
|
|
944
1001
|
interface ThemeSwitchProps {
|
|
945
1002
|
checked: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -885,11 +885,34 @@ interface WizardProps {
|
|
|
885
885
|
declare function Wizard({ children, steps, storageKey }: WizardProps): react_jsx_runtime.JSX.Element;
|
|
886
886
|
|
|
887
887
|
/** ─────────────────── types ─────────────────── */
|
|
888
|
-
|
|
889
|
-
|
|
888
|
+
/**
|
|
889
|
+
* Column descriptor for the Table.
|
|
890
|
+
*
|
|
891
|
+
* The generic `T` is the shape of a row — `keyBind` must be one of T's
|
|
892
|
+
* string-keyed properties, and `component(cellValue, row)` receives the
|
|
893
|
+
* matching value with full type inference. When used without a generic
|
|
894
|
+
* (`TableColumn[]`), `T` falls back to `Record<string, any>` for backwards
|
|
895
|
+
* compatibility — narrower typing is preferred whenever possible:
|
|
896
|
+
*
|
|
897
|
+
* ```ts
|
|
898
|
+
* type Vessel = { id: number; name: string; status: 'At Sea' | 'In Port' }
|
|
899
|
+
* const cols: TableColumn<Vessel>[] = [
|
|
900
|
+
* { key: 'name', label: 'Name', keyBind: 'name' }, // cellValue inferred as string
|
|
901
|
+
* ]
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
interface TableColumn<T extends Record<string, any> = Record<string, any>> {
|
|
905
|
+
/** React reconciliation key for the column itself. */
|
|
906
|
+
key: React$1.Key;
|
|
890
907
|
label: React$1.ReactNode;
|
|
891
|
-
|
|
892
|
-
|
|
908
|
+
/** Property on the row to read for this column. */
|
|
909
|
+
keyBind: keyof T & string;
|
|
910
|
+
/** Custom cell renderer. Receives the cell value and the full row. */
|
|
911
|
+
component?: (cellValue: T[keyof T], row: T) => React$1.ReactNode;
|
|
912
|
+
/** Explicit column width (CSS length or px number). Optional — defaults to auto. */
|
|
913
|
+
width?: string | number;
|
|
914
|
+
/** Text alignment for both header and cells. Defaults to `'center'`. */
|
|
915
|
+
align?: 'left' | 'center' | 'right';
|
|
893
916
|
}
|
|
894
917
|
interface PaginationOptions {
|
|
895
918
|
enabled?: boolean;
|
|
@@ -910,36 +933,70 @@ interface PaginationOptions {
|
|
|
910
933
|
onPageChange?: (page: number) => void;
|
|
911
934
|
onPerPageChange?: (perPage: number) => void;
|
|
912
935
|
}
|
|
913
|
-
interface ExpandRowOptions {
|
|
936
|
+
interface ExpandRowOptions<T extends Record<string, any> = Record<string, any>> {
|
|
914
937
|
enabled?: boolean;
|
|
915
938
|
expandIcon?: React$1.ReactNode;
|
|
916
|
-
expandComponent?: (row:
|
|
939
|
+
expandComponent?: (row: T) => React$1.ReactNode;
|
|
917
940
|
}
|
|
918
|
-
interface TableProps {
|
|
919
|
-
columns?: TableColumn[];
|
|
920
|
-
rows?:
|
|
941
|
+
interface TableProps<T extends Record<string, any> = Record<string, any>> {
|
|
942
|
+
columns?: TableColumn<T>[];
|
|
943
|
+
rows?: T[];
|
|
944
|
+
/**
|
|
945
|
+
* Returns a stable key for each row, used for React reconciliation AND
|
|
946
|
+
* for tracking expanded state when `expandRow.enabled` is true.
|
|
947
|
+
* Defaults to the row index — fine for static lists, but pass an
|
|
948
|
+
* explicit getter (e.g. `(row) => row.id`) if rows can be reordered or
|
|
949
|
+
* filtered while expand state should persist.
|
|
950
|
+
*/
|
|
951
|
+
getRowKey?: (row: T, index: number) => React$1.Key;
|
|
921
952
|
pagination?: PaginationOptions;
|
|
922
|
-
expandRow?: ExpandRowOptions
|
|
953
|
+
expandRow?: ExpandRowOptions<T>;
|
|
923
954
|
hasSearch?: boolean;
|
|
924
955
|
footer?: React$1.ReactNode;
|
|
925
956
|
header?: React$1.ReactNode;
|
|
926
|
-
tableRef?: React$1.Ref<any>;
|
|
927
|
-
[key: string]: any;
|
|
928
957
|
}
|
|
929
958
|
/** ─────────────────── main component ─────────────────── */
|
|
930
959
|
/**
|
|
931
960
|
* Data table with optional search, pagination, and expandable rows.
|
|
932
961
|
*
|
|
933
|
-
*
|
|
962
|
+
* - **Typed rows**: pass a generic `T` for full type inference on columns
|
|
963
|
+
* and cell renderers (`<Table<Vessel> ... />`).
|
|
964
|
+
* - **Real `<table>` semantics**: keeps row / col / cell context intact for
|
|
965
|
+
* screen readers and lets the browser handle column sizing natively.
|
|
966
|
+
* Per-column widths via `column.width`.
|
|
967
|
+
* - **Search**: client-side filter across ALL row values; result is
|
|
968
|
+
* memoized so each keystroke costs O(n) once per term change, not per
|
|
969
|
+
* render. Set `pagination.serverSide` to skip client-side filter and
|
|
970
|
+
* pagination entirely.
|
|
971
|
+
* - **Expand**: each row gets a real `<button>` with `aria-expanded`.
|
|
972
|
+
* Expand state is keyed by `getRowKey(row, i)` so it survives reorders.
|
|
973
|
+
*
|
|
974
|
+
* @example Static, fully typed
|
|
975
|
+
* ```tsx
|
|
976
|
+
* type Vessel = { id: number; name: string; status: string }
|
|
977
|
+
* <Table<Vessel>
|
|
978
|
+
* columns={[
|
|
979
|
+
* { key: 'name', label: 'Name', keyBind: 'name' },
|
|
980
|
+
* { key: 'status', label: 'Status', keyBind: 'status', width: 120 },
|
|
981
|
+
* ]}
|
|
982
|
+
* rows={vessels}
|
|
983
|
+
* getRowKey={(row) => row.id}
|
|
984
|
+
* />
|
|
985
|
+
* ```
|
|
934
986
|
*
|
|
935
|
-
* @example
|
|
987
|
+
* @example Server-side pagination
|
|
988
|
+
* ```tsx
|
|
936
989
|
* <Table
|
|
937
|
-
* columns={
|
|
938
|
-
* rows={
|
|
939
|
-
* pagination={{
|
|
990
|
+
* columns={cols}
|
|
991
|
+
* rows={pageRows}
|
|
992
|
+
* pagination={{
|
|
993
|
+
* enabled: true, serverSide: true, perPage: 20,
|
|
994
|
+
* page: currentPage, totalCount, onPageChange, onPerPageChange,
|
|
995
|
+
* }}
|
|
940
996
|
* />
|
|
997
|
+
* ```
|
|
941
998
|
*/
|
|
942
|
-
declare function Table({ columns, rows, pagination, expandRow, hasSearch, footer, header, }: TableProps): react_jsx_runtime.JSX.Element;
|
|
999
|
+
declare function Table<T extends Record<string, any> = Record<string, any>>({ columns, rows, getRowKey, pagination, expandRow, hasSearch, footer, header, }: TableProps<T>): react_jsx_runtime.JSX.Element;
|
|
943
1000
|
|
|
944
1001
|
interface ThemeSwitchProps {
|
|
945
1002
|
checked: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1691,9 +1691,7 @@ var DEFAULT_PAGINATION = {
|
|
|
1691
1691
|
pickerOptions: DEFAULT_PICKER
|
|
1692
1692
|
};
|
|
1693
1693
|
var DEFAULT_EXPAND = {
|
|
1694
|
-
enabled: false
|
|
1695
|
-
expandIcon: /* @__PURE__ */ jsx(Fragment, {}),
|
|
1696
|
-
expandComponent: () => /* @__PURE__ */ jsx(Fragment, {})
|
|
1694
|
+
enabled: false
|
|
1697
1695
|
};
|
|
1698
1696
|
function createDatasets(rows, perPage) {
|
|
1699
1697
|
if (!perPage) return [rows.slice()];
|
|
@@ -1703,78 +1701,95 @@ function createDatasets(rows, perPage) {
|
|
|
1703
1701
|
}
|
|
1704
1702
|
return all;
|
|
1705
1703
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1704
|
+
var defaultGetRowKey = (_row, index) => index;
|
|
1705
|
+
var cellAlign = (align) => align === "left" ? "text-left" : align === "right" ? "text-right" : "text-center";
|
|
1706
|
+
function TableHeader({
|
|
1707
|
+
columns,
|
|
1708
|
+
hasExpand
|
|
1709
|
+
}) {
|
|
1710
|
+
return /* @__PURE__ */ jsx("thead", { className: "bg-surface-raised border-b border-border", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1711
|
+
hasExpand && /* @__PURE__ */ jsx("th", { "aria-hidden": "true", className: "w-9" }),
|
|
1712
|
+
columns.map((col) => /* @__PURE__ */ jsx(
|
|
1713
|
+
"th",
|
|
1714
|
+
{
|
|
1715
|
+
scope: "col",
|
|
1716
|
+
className: `${cellAlign(col.align)} text-sm font-semibold text-foreground py-3 px-3`,
|
|
1717
|
+
style: col.width != null ? { width: col.width } : void 0,
|
|
1718
|
+
children: col.label
|
|
1719
|
+
},
|
|
1720
|
+
col.key
|
|
1721
|
+
))
|
|
1722
|
+
] }) });
|
|
1715
1723
|
}
|
|
1724
|
+
var DefaultExpandIcon = /* @__PURE__ */ jsx(
|
|
1725
|
+
"svg",
|
|
1726
|
+
{
|
|
1727
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1728
|
+
viewBox: "0 0 24 24",
|
|
1729
|
+
fill: "currentColor",
|
|
1730
|
+
className: "w-5 h-5 text-foreground-muted",
|
|
1731
|
+
"aria-hidden": "true",
|
|
1732
|
+
children: /* @__PURE__ */ jsx(
|
|
1733
|
+
"path",
|
|
1734
|
+
{
|
|
1735
|
+
fillRule: "evenodd",
|
|
1736
|
+
d: "M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zM12.75 9a.75.75 0 00-1.5 0v2.25H9a.75.75 0 000 1.5h2.25V15a.75.75 0 001.5 0v-2.25H15a.75.75 0 000-1.5h-2.25V9z",
|
|
1737
|
+
clipRule: "evenodd"
|
|
1738
|
+
}
|
|
1739
|
+
)
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1716
1742
|
function TableBody({
|
|
1717
1743
|
columns,
|
|
1718
1744
|
rows,
|
|
1719
|
-
expandRow
|
|
1745
|
+
expandRow,
|
|
1746
|
+
getRowKey
|
|
1720
1747
|
}) {
|
|
1721
|
-
const [
|
|
1748
|
+
const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set());
|
|
1722
1749
|
const toggleRow = (rowKey) => {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1750
|
+
setExpanded((prev) => {
|
|
1751
|
+
const next = new Set(prev);
|
|
1752
|
+
if (next.has(rowKey)) next.delete(rowKey);
|
|
1753
|
+
else next.add(rowKey);
|
|
1754
|
+
return next;
|
|
1755
|
+
});
|
|
1727
1756
|
};
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
}
|
|
1762
|
-
)
|
|
1763
|
-
|
|
1764
|
-
"tr",
|
|
1765
|
-
{
|
|
1766
|
-
className: `overflow-hidden w-full transition-all duration-300 ${visibleRows[row.key]?.visible ? "max-h-[2000px]" : "max-h-0"}`,
|
|
1767
|
-
children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "p-0 pb-1", children: /* @__PURE__ */ jsx(
|
|
1768
|
-
"div",
|
|
1769
|
-
{
|
|
1770
|
-
className: `overflow-hidden w-full transition-[max-height] duration-300 ${visibleRows[row.key]?.visible ? "max-h-[2000px]" : "max-h-0"}`,
|
|
1771
|
-
children: expandRow.expandComponent?.(row)
|
|
1772
|
-
}
|
|
1773
|
-
) })
|
|
1774
|
-
},
|
|
1775
|
-
`extra-${i}`
|
|
1776
|
-
)
|
|
1777
|
-
] }, row.key)) });
|
|
1757
|
+
const hasExpand = !!expandRow.enabled;
|
|
1758
|
+
const expandColCount = columns.length + (hasExpand ? 1 : 0);
|
|
1759
|
+
return /* @__PURE__ */ jsx("tbody", { children: rows.map((row, i) => {
|
|
1760
|
+
const rowKey = getRowKey(row, i);
|
|
1761
|
+
const isExpanded = expanded.has(rowKey);
|
|
1762
|
+
return /* @__PURE__ */ jsxs(React9.Fragment, { children: [
|
|
1763
|
+
/* @__PURE__ */ jsxs(
|
|
1764
|
+
"tr",
|
|
1765
|
+
{
|
|
1766
|
+
className: `border-b border-border hover:bg-surface-raised transition-colors duration-150 ${i % 2 === 0 ? "bg-surface" : "bg-surface-raised"}`,
|
|
1767
|
+
children: [
|
|
1768
|
+
hasExpand && /* @__PURE__ */ jsx("td", { className: "p-0 align-middle w-9", children: /* @__PURE__ */ jsx(
|
|
1769
|
+
"button",
|
|
1770
|
+
{
|
|
1771
|
+
type: "button",
|
|
1772
|
+
onClick: () => toggleRow(rowKey),
|
|
1773
|
+
"aria-expanded": isExpanded,
|
|
1774
|
+
"aria-label": isExpanded ? "Collapse row" : "Expand row",
|
|
1775
|
+
className: `w-9 h-9 inline-flex items-center justify-center rounded-md hover:bg-surface/80 transition-transform duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${isExpanded ? "rotate-180" : ""}`,
|
|
1776
|
+
children: expandRow.expandIcon ?? DefaultExpandIcon
|
|
1777
|
+
}
|
|
1778
|
+
) }),
|
|
1779
|
+
columns.map((col) => /* @__PURE__ */ jsx(
|
|
1780
|
+
"td",
|
|
1781
|
+
{
|
|
1782
|
+
className: `${cellAlign(col.align)} text-sm text-foreground py-2 px-3 align-middle`,
|
|
1783
|
+
children: col.component ? col.component(row[col.keyBind], row) : row[col.keyBind]
|
|
1784
|
+
},
|
|
1785
|
+
col.key
|
|
1786
|
+
))
|
|
1787
|
+
]
|
|
1788
|
+
}
|
|
1789
|
+
),
|
|
1790
|
+
hasExpand && isExpanded && /* @__PURE__ */ jsx("tr", { className: "bg-surface", children: /* @__PURE__ */ jsx("td", { colSpan: expandColCount, className: "p-0 border-b border-border", children: /* @__PURE__ */ jsx("div", { className: "p-3", children: expandRow.expandComponent?.(row) }) }) })
|
|
1791
|
+
] }, rowKey);
|
|
1792
|
+
}) });
|
|
1778
1793
|
}
|
|
1779
1794
|
function Pagination({
|
|
1780
1795
|
activePage,
|
|
@@ -1797,29 +1812,27 @@ function Pagination({
|
|
|
1797
1812
|
}
|
|
1798
1813
|
}, [serverSide, options.perPage, picker]);
|
|
1799
1814
|
const navBtn = (icon, disabled, onClick) => /* @__PURE__ */ jsx(IconButton, { disabled, onClick, icon });
|
|
1800
|
-
const chevronRight =
|
|
1801
|
-
const doubleChevronRight =
|
|
1802
|
-
const disabledColor = "var(--color-foreground-muted)";
|
|
1803
|
-
const enabledColor = "var(--color-foreground)";
|
|
1815
|
+
const chevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-5 w-5", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
1816
|
+
const doubleChevronRight = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-5 w-5", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7-7 7M5 5l7 7-7 7" }) });
|
|
1804
1817
|
return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center justify-end pt-2", children: [
|
|
1805
1818
|
navBtn(
|
|
1806
|
-
/* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: doubleChevronRight
|
|
1819
|
+
/* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: doubleChevronRight }),
|
|
1807
1820
|
activePage === 0,
|
|
1808
1821
|
() => onPageChange(0)
|
|
1809
1822
|
),
|
|
1810
1823
|
navBtn(
|
|
1811
|
-
/* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: chevronRight
|
|
1824
|
+
/* @__PURE__ */ jsx("span", { className: "rotate-180 inline-flex", children: chevronRight }),
|
|
1812
1825
|
activePage === 0,
|
|
1813
1826
|
() => activePage > 0 && onPageChange(activePage - 1)
|
|
1814
1827
|
),
|
|
1815
1828
|
/* @__PURE__ */ jsx("span", { className: "bg-surface-raised rounded-lg ml-2 mr-2 shadow-sm p-2 w-10 text-center select-none text-foreground", children: activePage + 1 }),
|
|
1816
1829
|
navBtn(
|
|
1817
|
-
chevronRight
|
|
1830
|
+
chevronRight,
|
|
1818
1831
|
activePage === maxPage,
|
|
1819
1832
|
() => activePage < maxPage && onPageChange(activePage + 1)
|
|
1820
1833
|
),
|
|
1821
1834
|
navBtn(
|
|
1822
|
-
doubleChevronRight
|
|
1835
|
+
doubleChevronRight,
|
|
1823
1836
|
activePage === maxPage,
|
|
1824
1837
|
() => onPageChange(maxPage)
|
|
1825
1838
|
),
|
|
@@ -1844,6 +1857,7 @@ function Pagination({
|
|
|
1844
1857
|
function Table({
|
|
1845
1858
|
columns = [],
|
|
1846
1859
|
rows = [],
|
|
1860
|
+
getRowKey = defaultGetRowKey,
|
|
1847
1861
|
pagination = DEFAULT_PAGINATION,
|
|
1848
1862
|
expandRow = DEFAULT_EXPAND,
|
|
1849
1863
|
hasSearch = true,
|
|
@@ -1856,8 +1870,20 @@ function Table({
|
|
|
1856
1870
|
typeof pagination.perPage === "number" ? pagination.perPage : 15
|
|
1857
1871
|
);
|
|
1858
1872
|
const [activePage, setActivePage] = useState(0);
|
|
1859
|
-
const [datasets, setDatasets] = useState([]);
|
|
1860
1873
|
const isServerSide = !!(pagination.enabled && pagination.serverSide);
|
|
1874
|
+
const filteredRows = useMemo(() => {
|
|
1875
|
+
if (isServerSide || !searchTerm) return rows;
|
|
1876
|
+
const term = searchTerm.toLowerCase();
|
|
1877
|
+
return rows.filter(
|
|
1878
|
+
(row) => Object.values(row).some(
|
|
1879
|
+
(v) => v != null && String(v).toLowerCase().includes(term)
|
|
1880
|
+
)
|
|
1881
|
+
);
|
|
1882
|
+
}, [rows, searchTerm, isServerSide]);
|
|
1883
|
+
const datasets = useMemo(() => {
|
|
1884
|
+
if (isServerSide) return [rows];
|
|
1885
|
+
return createDatasets(filteredRows, pagination.enabled ? perPage : null);
|
|
1886
|
+
}, [filteredRows, perPage, pagination.enabled, isServerSide, rows]);
|
|
1861
1887
|
const MAX_PAGE = useMemo(() => {
|
|
1862
1888
|
if (isServerSide && typeof pagination.maxPage === "number") return Math.max(0, pagination.maxPage);
|
|
1863
1889
|
if (isServerSide && typeof pagination.totalCount === "number")
|
|
@@ -1866,32 +1892,22 @@ function Table({
|
|
|
1866
1892
|
}, [isServerSide, pagination.maxPage, pagination.totalCount, perPage, datasets.length]);
|
|
1867
1893
|
const currentPageRows = useMemo(() => {
|
|
1868
1894
|
if (isServerSide) return rows;
|
|
1869
|
-
return datasets
|
|
1895
|
+
return datasets[activePage] ?? [];
|
|
1870
1896
|
}, [isServerSide, rows, datasets, activePage]);
|
|
1871
1897
|
useEffect(() => {
|
|
1872
|
-
if (pagination.enabled && !isServerSide
|
|
1873
|
-
|
|
1898
|
+
if (pagination.enabled && !isServerSide && typeof pagination.perPage === "number") {
|
|
1899
|
+
setPerPage(pagination.perPage);
|
|
1900
|
+
}
|
|
1901
|
+
}, [pagination.enabled, pagination.perPage, isServerSide]);
|
|
1874
1902
|
useEffect(() => {
|
|
1875
1903
|
if (isServerSide && typeof pagination.perPage === "number") setPerPage(pagination.perPage);
|
|
1876
1904
|
}, [isServerSide, pagination.perPage]);
|
|
1877
|
-
useEffect(() => {
|
|
1878
|
-
if (isServerSide) return;
|
|
1879
|
-
setDatasets(createDatasets(rows, pagination.enabled ? perPage : null));
|
|
1880
|
-
}, [rows, perPage, pagination, isServerSide]);
|
|
1881
1905
|
useEffect(() => {
|
|
1882
1906
|
if (isServerSide && typeof pagination.page === "number" && pagination.page >= 1)
|
|
1883
1907
|
setActivePage(pagination.page - 1);
|
|
1884
1908
|
}, [isServerSide, pagination.page]);
|
|
1885
1909
|
const onSearchChange = (e) => {
|
|
1886
|
-
|
|
1887
|
-
setSearchTerm(term);
|
|
1888
|
-
if (isServerSide) return;
|
|
1889
|
-
const filtered = rows.filter(
|
|
1890
|
-
(row) => Object.values(row).some(
|
|
1891
|
-
(v) => !!v && String(v).toLowerCase().includes(term.toLowerCase())
|
|
1892
|
-
)
|
|
1893
|
-
);
|
|
1894
|
-
setDatasets(createDatasets(filtered, pagination.enabled ? perPage : null));
|
|
1910
|
+
setSearchTerm(e.target.value);
|
|
1895
1911
|
setActivePage(0);
|
|
1896
1912
|
};
|
|
1897
1913
|
const onPaginationChange = (perPageValue) => {
|
|
@@ -1930,9 +1946,17 @@ function Table({
|
|
|
1930
1946
|
)
|
|
1931
1947
|
] }),
|
|
1932
1948
|
/* @__PURE__ */ jsx("div", { children: header }),
|
|
1933
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
1934
|
-
/* @__PURE__ */ jsx(TableHeader, { columns }),
|
|
1935
|
-
/* @__PURE__ */ jsx(
|
|
1949
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse", children: [
|
|
1950
|
+
/* @__PURE__ */ jsx(TableHeader, { columns, hasExpand: !!expandRow.enabled }),
|
|
1951
|
+
/* @__PURE__ */ jsx(
|
|
1952
|
+
TableBody,
|
|
1953
|
+
{
|
|
1954
|
+
columns,
|
|
1955
|
+
rows: currentPageRows,
|
|
1956
|
+
expandRow,
|
|
1957
|
+
getRowKey
|
|
1958
|
+
}
|
|
1959
|
+
)
|
|
1936
1960
|
] }) }),
|
|
1937
1961
|
/* @__PURE__ */ jsx("div", { children: footer })
|
|
1938
1962
|
] });
|