UNPKG

laif-ds

Version:

Design System di Laif con componenti React basati su principi di Atomic Design

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