laif-ds
Version:
Design System di Laif con componenti React basati su principi di Atomic Design
578 lines (577 loc) • 19.3 kB
JavaScript
"use client";
import { jsx as c, jsxs as ie } from "react/jsx-runtime";
import { useReactTable as at } from "../../../../node_modules/@tanstack/react-table/build/lib/index.js";
import { cn as it } from "../../../../lib/utils.js";
import { useRef as f, useState as d, useEffect as H, useMemo as F } from "react";
import { Button as st } from "../../button.js";
import { Checkbox as ye } from "../../checkbox.js";
import { DataTableBody as lt } from "./components/data-table-body.js";
import { DataTableColumnVisibility as ct } from "./components/data-table-column-visibility.js";
import { DataTableFilters as dt } from "./components/data-table-filters.js";
import { DataTablePaginationComponent as ut } from "./components/data-table-pagination.js";
import { DataTableSearchbar as gt } from "./components/data-table-searchbar.js";
import { DataTableSortingComponent as mt } from "./components/data-table-sorting.js";
import { applySearchFilterToRow as we, debounce as pt, buildSearchFilter as ft, updatePageSizeFromContainer as ht, createDefaultAdvancedFilter as St, createBadgeFilterFromHeader as bt } from "./data-table.service.js";
import { DataTableActionsComponent as vt } from "./components/data-table-actions.js";
import { defaultDataTableI18n as Ft } from "./data-table-i18n.js";
import { getPaginationRowModel as Ct, getFilteredRowModel as xt, getSortedRowModel as yt, getCoreRowModel as wt } from "../../../../node_modules/@tanstack/table-core/build/lib/index.js";
function Pt({
columns: Y,
data: j,
loading: z = !1,
emptyComponent: Re,
className: Ie,
rowSelection: Te = {},
onRowSelectionChange: se,
checkable: P = !1,
onCheckedRowsChange: Z,
actions: ze = [],
customComponentsLeft: De,
customComponentsRight: Be,
hidePagination: _e = !1,
hideActionsRow: Me = !1,
i18n: h = Ft,
maxSortedColumns: le = 2,
initialState: u,
// New mode-based API
serverMode: He = !1,
serverConfig: Ne,
disableAutoPageSize: b = !1,
// Test & Accessibility
id: Oe,
"data-testid": Le
}) {
const q = f(null), a = He === !0, g = a ? Ne : void 0, ce = (e) => !e || !e.sort_by || !e.sort_order ? [] : e.sort_by.map((t, o) => ({
id: t,
desc: e.sort_order[o] === "desc"
})), Ge = (e) => {
const t = ce(e?.sorting), o = {
sort_by: t.map((s) => s.id),
sort_order: t.map((s) => s.desc ? "desc" : "asc")
};
return {
computedSorting: t.length > 0 ? o : void 0,
computedFilter: e?.computedFilter
// Use provided value or undefined
};
}, [N, ke] = d(() => ce(u?.sorting)), [Ae] = d([]), [Ve, je] = d(
() => u?.columnVisibility ?? {}
), [m, Pe] = d(() => u?.filters?.searchbarFilter), [K, O] = d(() => u?.pagination ?? { pageIndex: 0, pageSize: 10 }), de = f(g);
de.current = g;
const E = f(g?.onStateChange);
E.current = g?.onStateChange;
const W = f(null), D = f(null), qe = f(0), ue = f(!1), ge = f(null), J = f({}), me = f(null), $ = f(z);
$.current = z;
const L = (e) => {
e.computedFilter && (J.current.computedFilter = e.computedFilter), e.computedSorting && (J.current.computedSorting = e.computedSorting);
const t = {
...e,
// Use new computed values if available, otherwise use last known values
computedFilter: e.computedFilter || J.current.computedFilter,
computedSorting: e.computedSorting || J.current.computedSorting
};
W.current = t, D.current && clearTimeout(D.current), D.current = setTimeout(() => {
W.current && E.current && (qe.current = Date.now(), E.current(W.current), W.current = null, D.current = null);
}, 400);
};
H(() => {
const e = setTimeout(() => {
ue.current = !0;
}, 100);
return () => {
clearTimeout(e), D.current && clearTimeout(D.current);
};
}, []);
const [r, G] = d(() => {
const { computedSorting: e, computedFilter: t } = Ge(u);
return {
pagination: u?.pagination ?? { pageIndex: 0, pageSize: 10 },
sorting: u?.sorting,
filters: u?.filters,
computedFilter: u?.computedFilter ?? t,
computedSorting: u?.computedSorting ?? e
};
});
a && !g && console.warn("DataTable: Server mode requires serverConfig");
const [Ke, pe] = d(0), [Ee, fe] = d(0), [We, Je] = d({}), he = se ? Te : We, Ue = se || Je, [C, ee] = d(
() => u?.filters?.filterBadges ?? []
), [x, te] = d(() => u?.filters?.advancedFilterBadge), [U, Xe] = d(""), [Se, be] = d([]), ve = F(() => P ? [
{
id: "data-table-integrated-checkbox-column",
size: 24,
minSize: 24,
maxSize: 24,
header: ({ table: e }) => /* @__PURE__ */ c(
"div",
{
className: "flex w-6 max-w-6 min-w-6 items-center justify-center",
style: { width: "24px", minWidth: "24px", maxWidth: "24px" },
children: /* @__PURE__ */ c(
ye,
{
className: "cursor-pointer",
checked: e.getIsAllPageRowsSelected(),
onCheckedChange: (t) => e.toggleAllPageRowsSelected(!!t),
"aria-label": h.selectAll
}
)
}
),
cell: ({ row: e }) => /* @__PURE__ */ c(
"div",
{
className: "flex w-6 max-w-6 min-w-6 items-center justify-center",
style: { width: "24px", minWidth: "24px", maxWidth: "24px" },
children: /* @__PURE__ */ c(
ye,
{
className: "cursor-pointer",
checked: e.getIsSelected(),
onCheckedChange: (t) => e.toggleSelected(!!t),
"aria-label": h.selectRow
}
)
}
),
enableSorting: !1,
enableHiding: !1,
enableResizing: !1,
meta: {
pinned: "left",
sortable: !1,
searchable: !1,
filterable: !1,
type: "other",
listOptions: []
}
},
...Y
] : Y, [Y, P]), I = F(() => ve.map(
(e) => e
), [ve]), X = (e) => {
if (e.id) return e.id;
if ("accessorKey" in e && typeof e.accessorKey == "string")
return e.accessorKey;
}, Qe = (e) => {
const t = e.meta?.headerLabel;
return t || (typeof e.header == "string" ? e.header : X(e) ?? "-");
};
H(() => {
const e = (I ?? []).map(X).filter((l) => !!l), t = new Set(Se), o = new Set(e);
t.size === o.size && [...t].every((l) => o.has(l)) || be(e);
}, [I]);
const B = F(() => I.filter((e) => !!e.meta?.searchable), [I]), T = F(() => B.map((e) => "accessorKey" in e && typeof e.accessorKey == "string" ? e.accessorKey : e.id).filter((e) => !!e), [B]), [Q, Ye] = d(() => u?.computedFilter ?? {}), Ze = {
data: F(() => a || Object.keys(Q).length === 0 ? j : j.filter((e) => we({
original: e,
getValue: (o) => e[o]
}, Q)), [j, Q, a]),
columns: I,
getCoreRowModel: wt(),
onSortingChange: (e) => {
const t = typeof e == "function" ? e(N) : e;
ke(t);
},
getSortedRowModel: yt(),
manualSorting: a,
onColumnVisibilityChange: je,
onRowSelectionChange: Ue,
onColumnOrderChange: be,
getFilteredRowModel: xt(),
manualFiltering: a,
globalFilterFn: (e, t, o) => a || !o ? !0 : (T ?? []).some((s) => {
const l = e.getValue(s);
return Array.isArray(l) ? l.some(
(p) => String(p).toLowerCase().includes(o.toLowerCase())
) : String(l).toLowerCase().includes(o.toLowerCase());
}) ?? !1,
filterFns: {
advancedFilter: (e) => a ? !0 : we(e, Q)
},
onPaginationChange: (e) => {
if (a && g) {
if (typeof e == "object") {
const t = b ? {
...r.pagination,
pageIndex: e.pageIndex
} : {
...r.pagination,
pageIndex: e.pageIndex,
pageSize: e.pageSize
}, o = {
...r,
pagination: t,
// Preserve computed values if they exist
computedFilter: r.computedFilter,
computedSorting: r.computedSorting
};
G(o), L(o);
}
} else
O(
typeof e == "object" ? (t) => b ? { ...t, pageIndex: e.pageIndex } : {
pageIndex: e.pageIndex,
pageSize: e.pageSize
} : e
);
},
getPaginationRowModel: Ct(),
manualPagination: a,
pageCount: a && z ? Ee : Ke,
state: {
sorting: N,
columnFilters: Ae,
columnVisibility: Ve,
rowSelection: he,
globalFilter: m,
pagination: a ? r.pagination : K,
columnOrder: Se
},
// Prevent implicit resets on data/columns changes so filters/sorting persist
autoResetPageIndex: !1
}, i = at(Ze), re = i.getFilteredRowModel();
H(() => {
if (a && g) {
const e = Math.ceil(
g.totalItems / (r.pagination.pageSize || 10)
);
pe(e), !z && e > 0 && fe(e);
} else {
const e = re.rows.length, t = Math.ceil(e / K.pageSize);
pe(t), fe(t);
}
}, [
a,
g?.totalItems,
r.pagination.pageSize,
r.pagination.pageIndex,
i,
re,
K.pageSize,
z
]), H(() => {
if (b) return;
const e = () => {
const y = q.current;
if (!y) return;
const _ = y.querySelector(
"thead tr"
), n = y.querySelector(
"tbody tr"
), w = _?.getBoundingClientRect().height ?? 40;
if (!!!n?.querySelector("td")) return;
const A = n?.getBoundingClientRect().height ?? 32.5;
ht(y, {
rowHeight: A,
headerHeight: w,
onPageChange: a ? (R, v) => {
if (g && ue.current) {
const S = b ? {
...r.pagination,
pageIndex: R
} : {
...r.pagination,
pageIndex: R,
pageSize: v
}, oe = S.pageIndex === r.pagination.pageIndex, ae = b || S.pageSize === r.pagination.pageSize;
if (oe && ae)
return;
const V = {
...r,
pagination: S,
// Preserve computed values if they exist
computedFilter: r.computedFilter,
computedSorting: r.computedSorting
};
G(V), $.current || L(V);
}
} : (R, v) => {
O(
(S) => b ? { ...S, pageIndex: R } : { pageIndex: R, pageSize: v }
);
},
setPagination: (R) => {
const v = typeof R == "function" ? R(r.pagination) : R;
if (a && g) {
const S = b ? {
...r.pagination,
pageIndex: v.pageIndex
} : {
...r.pagination,
pageIndex: v.pageIndex,
pageSize: v.pageSize
}, oe = S.pageIndex === r.pagination.pageIndex, ae = b || S.pageSize === r.pagination.pageSize;
if (oe && ae)
return;
const V = {
...r,
pagination: S,
// Preserve computed values if they exist
computedFilter: r.computedFilter,
computedSorting: r.computedSorting
};
G(V), $.current || L(V);
} else
O(
(S) => b ? { ...S, pageIndex: v.pageIndex } : {
pageIndex: v.pageIndex,
pageSize: v.pageSize
}
);
}
});
}, t = pt(() => {
requestAnimationFrame(() => {
e();
});
}, 200);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
e();
});
});
const o = setTimeout(e, 200), s = document.fonts;
s && typeof s.ready?.then == "function" && s.ready.then(() => e()), window.addEventListener("resize", t);
const l = q.current, p = typeof ResizeObserver < "u" ? new ResizeObserver((y) => {
const _ = y[0];
if (!_) return;
const n = _.contentRect.height, w = me.current;
(w === null || Math.abs(n - w) > 0.5) && (me.current = n, t());
}) : null;
return l && p && p.observe(l), () => {
window.removeEventListener("resize", t), clearTimeout(o), p && p.disconnect(), clearTimeout(o);
};
}, [
a,
q,
b,
// Recalculate when the rendered rows count changes; helps when data arrives async
re.rows.length
]), H(() => {
if (Z && P) {
const e = i.getFilteredSelectedRowModel().rows.map((t) => t.original);
Z(e);
}
}, [i, Z, P, he]);
const $e = F(() => {
const e = i.getHeaderGroups()[0], t = e ? e.headers : [];
return (i.getState().sorting || []).map((l) => t.find((p) => p.column.id === l.id)).filter(Boolean);
}, [
i.getHeaderGroups,
i.getState().sorting,
I
]), ne = F(() => i.getHeaderGroups()[0].headers.filter((e) => e.column.columnDef.meta?.sortable), [i.getHeaderGroups, I]), k = F(() => i.getHeaderGroups()[0].headers.filter((e) => e.column.columnDef.meta?.filterable), [i.getHeaderGroups, I]), et = F(() => U ? k.filter((e) => (e.column.columnDef.meta?.headerLabel ?? (typeof e.column.columnDef.header == "string" ? e.column.columnDef.header : void 0) ?? e.column.id).toLowerCase().includes(U.toLowerCase())) : k, [k, U]), Fe = (e) => {
ee((t) => [...t, bt(e)]);
}, tt = () => {
te(St());
}, rt = F(() => C.sort((e, t) => e.value === void 0 || e.value === "" ? 1 : t.value === void 0 || t.value === "" ? -1 : 1), [C]), Ce = f({
filterBadges: [],
advancedFilterBadge: void 0,
searchbarGlobalFilter: void 0
});
H(() => {
const e = ft(
C,
x ?? void 0
), t = m && T.length > 0 ? T.length === 1 ? (() => {
const n = T[0], M = B.find(
(A) => X(A) === n
)?.meta?.type;
return M === "list_multi_select" || M === "list_single_select" ? {
[n]: {
operator: "array_overlap",
value: [m]
}
} : {
[n]: {
operator: "like",
value: m
}
};
})() : {
_or: T.map((n) => {
const M = B.find(
(A) => X(A) === n
)?.meta?.type;
return M === "list_multi_select" || M === "list_single_select" ? {
[n]: {
operator: "array_overlap",
value: [m]
}
} : {
[n]: {
operator: "like",
value: m
}
};
})
} : null, o = [
...e && Object.keys(e).length > 0 ? [e] : [],
...t ? [t] : []
], s = o.length === 0 ? {} : o.length === 1 ? o[0] : { _and: o }, l = {
sort_by: N.map((n) => n.id),
sort_order: N.map((n) => n.desc ? "desc" : "asc")
}, p = Ce.current, y = JSON.stringify(C) !== JSON.stringify(p.filterBadges) || JSON.stringify(x) !== JSON.stringify(p.advancedFilterBadge) || m !== p.searchbarGlobalFilter;
Ce.current = {
filterBadges: [...C],
advancedFilterBadge: x ? { ...x } : void 0,
searchbarGlobalFilter: m
};
const _ = de.current;
if (Ye(s), a && E.current && _) {
const n = {
...r,
computedFilter: s,
// Emit only computedSorting. Use empty arrays to signal "no sorting" when cleared.
computedSorting: l,
filters: {
filterBadges: C,
advancedFilterBadge: x,
searchbarFilter: m
},
pagination: {
...r.pagination,
// Only reset pageIndex to 0 when filters actually changed, not when just sorting changed
pageIndex: y ? 0 : r.pagination.pageIndex
}
};
G(n);
const w = JSON.stringify({
computedFilter: n.computedFilter,
computedSorting: n.computedSorting,
filters: n.filters,
pagination: n.pagination
});
ge.current !== w && (ge.current = w, L(n));
} else
y && O((n) => ({
...n,
pageIndex: 0
}));
}, [
C,
x,
m,
T,
B,
N,
a
]);
const xe = i.getAllLeafColumns(), nt = xe.filter((e) => e.getIsVisible()), ot = xe.filter((e) => !e.getIsVisible());
return /* @__PURE__ */ ie(
"div",
{
id: Oe,
"data-testid": Le,
className: it(
"flex h-full max-h-full min-h-[250px] w-full max-w-full min-w-0 flex-col gap-2",
Ie
),
children: [
!Me && /* @__PURE__ */ ie("div", { className: "flex w-full items-center justify-between gap-1", children: [
/* @__PURE__ */ ie("div", { className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
ne.length > 0 && /* @__PURE__ */ c(
mt,
{
table: i,
sortedColumns: $e,
sortableColumns: ne,
i18n: h,
maxSortedColumns: le
}
),
ne.length > 0 && k.length > 0 && /* @__PURE__ */ c("div", { className: "border-d-border h-4 min-h-4 w-[1px] border-r" }),
De,
/* @__PURE__ */ c(
dt,
{
advancedFilterBadge: x,
setAdvancedFilterBadge: te,
filterableColumns: k,
sortedFilterBadges: rt,
setFilterBadges: ee,
filterSearch: U,
setFilterSearch: Xe,
filteredColumns: et,
handleAddFilter: Fe,
handleAddAdvancedFilter: tt,
i18n: h
}
)
] }),
/* @__PURE__ */ c("div", { className: "border-d-border h-4 min-h-4 w-[1px] border-r" }),
Be,
(C.length || x) && /* @__PURE__ */ c(
st,
{
className: "h-6 text-xs",
iconLeft: "FunnelX",
size: "sm",
variant: "ghost-destructive",
onClick: () => {
ee([]), te(void 0);
},
children: h.reset
}
),
T.length > 0 && /* @__PURE__ */ c(
gt,
{
debounceMs: 300,
onSearch: Pe,
i18n: h,
initialValue: m ?? "",
searchableColumnsHeaders: B.map(
(e) => Qe(e)
)
}
),
/* @__PURE__ */ c(
ct,
{
table: i,
visibleColumns: nt,
hiddenColumns: ot,
i18n: h
}
),
/* @__PURE__ */ c(vt, { actions: ze, i18n: h })
] }),
/* @__PURE__ */ c(
lt,
{
table: i,
tableContainerRef: q,
loading: z,
data: j,
emptyComponent: Re,
notFoundMessage: h?.notFoundMessage ?? "N/A",
onAddFilter: Fe,
maxSortedColumns: le,
i18n: h,
isServerSide: a,
filterBadges: C,
advancedFilterBadge: x,
searchbarGlobalFilter: m
}
),
!_e && /* @__PURE__ */ c(
ut,
{
table: i,
isServerSide: a,
clientPagination: K,
serverState: a ? r : void 0,
onServerStateChange: a && g ? (e) => {
G(e), L(e);
} : void 0,
totalItems: g?.totalItems,
i18n: h
}
)
]
}
);
}
export {
Pt as DataTable
};