@dynostack/react-grid 0.1.0 → 0.2.0
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/README.md +305 -18
- package/dist/index.cjs +375 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -43
- package/dist/index.d.ts +142 -43
- package/dist/index.js +371 -99
- package/dist/index.js.map +1 -1
- package/dist/page.css +24 -0
- package/dist/styles.css +145 -46
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useState, useRef, useEffect, useMemo, useContext } from 'react';
|
|
1
|
+
import { createContext, useState, useRef, useEffect, useMemo, useLayoutEffect, useId, useContext } from 'react';
|
|
2
2
|
import { useReactTable, getPaginationRowModel, getExpandedRowModel, getSortedRowModel, getFilteredRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
3
3
|
import { Trash2Icon, XIcon, SearchIcon, RefreshCwIcon, ColumnsIcon, DownloadIcon, FileTextIcon, FileSpreadsheetIcon, PlusIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon, ArrowDownIcon, ArrowUpIcon, ChevronsUpDownIcon, PinOffIcon, PinIcon, EyeOffIcon, FilterIcon, CheckIcon, MoreHorizontalIcon, ChevronDownIcon, GripVerticalIcon, Loader2Icon, MinusIcon, CopyIcon, PencilIcon, EyeIcon, ChevronUpIcon } from 'lucide-react';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
@@ -6,6 +6,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
6
6
|
import { Slot, Separator as Separator$1, Popover as Popover$1, Checkbox as Checkbox$1, DropdownMenu as DropdownMenu$1, Select as Select$1 } from 'radix-ui';
|
|
7
7
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
8
8
|
import { cva } from 'class-variance-authority';
|
|
9
|
+
import { createPortal } from 'react-dom';
|
|
9
10
|
|
|
10
11
|
function cn(...inputs) {
|
|
11
12
|
return twMerge(clsx(inputs));
|
|
@@ -1715,14 +1716,34 @@ function DataTableRowActions({
|
|
|
1715
1716
|
onCancelEdit
|
|
1716
1717
|
}) {
|
|
1717
1718
|
const [open, setOpen] = useState(false);
|
|
1719
|
+
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
|
|
1720
|
+
const triggerRef = useRef(null);
|
|
1718
1721
|
const menuRef = useRef(null);
|
|
1722
|
+
useLayoutEffect(() => {
|
|
1723
|
+
if (!open || !triggerRef.current) return;
|
|
1724
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
1725
|
+
setMenuPosition({
|
|
1726
|
+
top: rect.bottom + 4,
|
|
1727
|
+
left: Math.max(8, rect.right - 160)
|
|
1728
|
+
});
|
|
1729
|
+
}, [open]);
|
|
1719
1730
|
useEffect(() => {
|
|
1720
1731
|
if (!open) return;
|
|
1721
1732
|
const onPointerDown = (event) => {
|
|
1722
|
-
|
|
1733
|
+
const target = event.target;
|
|
1734
|
+
if (!menuRef.current?.contains(target) && !triggerRef.current?.contains(target)) {
|
|
1735
|
+
setOpen(false);
|
|
1736
|
+
}
|
|
1723
1737
|
};
|
|
1738
|
+
const onDismiss = () => setOpen(false);
|
|
1724
1739
|
document.addEventListener("pointerdown", onPointerDown);
|
|
1725
|
-
|
|
1740
|
+
window.addEventListener("scroll", onDismiss, true);
|
|
1741
|
+
window.addEventListener("resize", onDismiss);
|
|
1742
|
+
return () => {
|
|
1743
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
1744
|
+
window.removeEventListener("scroll", onDismiss, true);
|
|
1745
|
+
window.removeEventListener("resize", onDismiss);
|
|
1746
|
+
};
|
|
1726
1747
|
}, [open]);
|
|
1727
1748
|
if (isEditing) {
|
|
1728
1749
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1", children: [
|
|
@@ -1753,6 +1774,7 @@ function DataTableRowActions({
|
|
|
1753
1774
|
/* @__PURE__ */ jsx(
|
|
1754
1775
|
Button,
|
|
1755
1776
|
{
|
|
1777
|
+
ref: triggerRef,
|
|
1756
1778
|
variant: "ghost",
|
|
1757
1779
|
size: "icon-xs",
|
|
1758
1780
|
"aria-label": "Open row actions",
|
|
@@ -1761,41 +1783,52 @@ function DataTableRowActions({
|
|
|
1761
1783
|
children: /* @__PURE__ */ jsx(MoreHorizontalIcon, {})
|
|
1762
1784
|
}
|
|
1763
1785
|
),
|
|
1764
|
-
open &&
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
{
|
|
1768
|
-
danger: a === "delete",
|
|
1769
|
-
onClick: () => {
|
|
1770
|
-
setOpen(false);
|
|
1771
|
-
onAction?.(a, row);
|
|
1772
|
-
},
|
|
1773
|
-
children: [
|
|
1774
|
-
builtinIcons[a],
|
|
1775
|
-
" ",
|
|
1776
|
-
builtinLabels[a]
|
|
1777
|
-
]
|
|
1778
|
-
},
|
|
1779
|
-
a
|
|
1780
|
-
)),
|
|
1781
|
-
customActions.length > 0 && actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "-mx-1 my-1 h-px bg-border" }),
|
|
1782
|
-
customActions.filter((c) => c.show ? c.show(row) : true).map((c) => /* @__PURE__ */ jsxs(
|
|
1783
|
-
RowActionButton,
|
|
1786
|
+
open && createPortal(
|
|
1787
|
+
/* @__PURE__ */ jsxs(
|
|
1788
|
+
"div",
|
|
1784
1789
|
{
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
onAction?.(c.id, row);
|
|
1789
|
-
},
|
|
1790
|
+
ref: menuRef,
|
|
1791
|
+
className: "fixed z-[1000] w-40 rounded-md border bg-popover p-1 text-popover-foreground shadow-lg",
|
|
1792
|
+
style: { top: menuPosition.top, left: menuPosition.left },
|
|
1790
1793
|
children: [
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
+
actions.map((a) => /* @__PURE__ */ jsxs(
|
|
1795
|
+
RowActionButton,
|
|
1796
|
+
{
|
|
1797
|
+
danger: a === "delete",
|
|
1798
|
+
onClick: () => {
|
|
1799
|
+
setOpen(false);
|
|
1800
|
+
onAction?.(a, row);
|
|
1801
|
+
},
|
|
1802
|
+
children: [
|
|
1803
|
+
builtinIcons[a],
|
|
1804
|
+
" ",
|
|
1805
|
+
builtinLabels[a]
|
|
1806
|
+
]
|
|
1807
|
+
},
|
|
1808
|
+
a
|
|
1809
|
+
)),
|
|
1810
|
+
customActions.length > 0 && actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "-mx-1 my-1 h-px bg-border" }),
|
|
1811
|
+
customActions.filter((c) => c.show ? c.show(row) : true).map((c) => /* @__PURE__ */ jsxs(
|
|
1812
|
+
RowActionButton,
|
|
1813
|
+
{
|
|
1814
|
+
danger: c.danger,
|
|
1815
|
+
onClick: () => {
|
|
1816
|
+
setOpen(false);
|
|
1817
|
+
onAction?.(c.id, row);
|
|
1818
|
+
},
|
|
1819
|
+
children: [
|
|
1820
|
+
c.icon,
|
|
1821
|
+
" ",
|
|
1822
|
+
c.label
|
|
1823
|
+
]
|
|
1824
|
+
},
|
|
1825
|
+
c.id
|
|
1826
|
+
))
|
|
1794
1827
|
]
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1828
|
+
}
|
|
1829
|
+
),
|
|
1830
|
+
document.body
|
|
1831
|
+
)
|
|
1799
1832
|
] });
|
|
1800
1833
|
}
|
|
1801
1834
|
function RowActionButton({
|
|
@@ -1991,57 +2024,148 @@ var TOKEN_TO_VAR = {
|
|
|
1991
2024
|
radius: "--radius",
|
|
1992
2025
|
fontFamily: "--font-family"
|
|
1993
2026
|
};
|
|
1994
|
-
function
|
|
1995
|
-
if (!theme) return
|
|
2027
|
+
function isModed(theme) {
|
|
2028
|
+
if (!theme) return false;
|
|
2029
|
+
return "light" in theme || "dark" in theme;
|
|
2030
|
+
}
|
|
2031
|
+
function tokensToStyle(tokens) {
|
|
2032
|
+
if (!tokens) return {};
|
|
1996
2033
|
const out = {};
|
|
1997
|
-
for (const [k, v] of Object.entries(
|
|
2034
|
+
for (const [k, v] of Object.entries(tokens)) {
|
|
1998
2035
|
if (v == null) continue;
|
|
1999
2036
|
const cssVar = TOKEN_TO_VAR[k];
|
|
2000
2037
|
if (cssVar) out[cssVar] = v;
|
|
2001
2038
|
}
|
|
2002
2039
|
return out;
|
|
2003
2040
|
}
|
|
2004
|
-
|
|
2041
|
+
function themeToStyle(theme) {
|
|
2042
|
+
if (!theme) return {};
|
|
2043
|
+
if (isModed(theme)) return tokensToStyle(theme.light);
|
|
2044
|
+
return tokensToStyle(theme);
|
|
2045
|
+
}
|
|
2046
|
+
function splitTheme(theme) {
|
|
2047
|
+
if (!theme) return { light: void 0, dark: void 0 };
|
|
2048
|
+
if (isModed(theme)) return { light: theme.light, dark: theme.dark };
|
|
2049
|
+
return { light: theme, dark: void 0 };
|
|
2050
|
+
}
|
|
2051
|
+
function buildPreset(hue, chroma = 0.03) {
|
|
2052
|
+
const c = chroma;
|
|
2053
|
+
return {
|
|
2054
|
+
light: {
|
|
2055
|
+
background: `oklch(0.99 ${c * 0.2} ${hue})`,
|
|
2056
|
+
foreground: `oklch(0.18 ${c * 1.2} ${hue})`,
|
|
2057
|
+
card: `oklch(1 0 0)`,
|
|
2058
|
+
cardForeground: `oklch(0.18 ${c * 1.2} ${hue})`,
|
|
2059
|
+
popover: `oklch(1 0 0)`,
|
|
2060
|
+
popoverForeground: `oklch(0.18 ${c * 1.2} ${hue})`,
|
|
2061
|
+
primary: `oklch(0.55 0.2 ${hue})`,
|
|
2062
|
+
primaryForeground: `oklch(0.99 0 0)`,
|
|
2063
|
+
secondary: `oklch(0.96 ${c} ${hue})`,
|
|
2064
|
+
secondaryForeground: `oklch(0.25 ${c * 2} ${hue})`,
|
|
2065
|
+
muted: `oklch(0.96 ${c} ${hue})`,
|
|
2066
|
+
mutedForeground: `oklch(0.5 ${c * 1.5} ${hue})`,
|
|
2067
|
+
accent: `oklch(0.94 ${c * 1.2} ${hue})`,
|
|
2068
|
+
accentForeground: `oklch(0.3 ${c * 3} ${hue})`,
|
|
2069
|
+
destructive: `oklch(0.577 0.245 27.325)`,
|
|
2070
|
+
destructiveForeground: `oklch(0.985 0 0)`,
|
|
2071
|
+
border: `oklch(0.9 ${c * 0.8} ${hue})`,
|
|
2072
|
+
input: `oklch(0.9 ${c * 0.8} ${hue})`,
|
|
2073
|
+
ring: `oklch(0.55 0.2 ${hue} / 0.5)`,
|
|
2074
|
+
radius: "0.625rem"
|
|
2075
|
+
},
|
|
2076
|
+
dark: {
|
|
2077
|
+
background: `oklch(0.16 ${c * 0.6} ${hue})`,
|
|
2078
|
+
foreground: `oklch(0.97 ${c * 0.2} ${hue})`,
|
|
2079
|
+
card: `oklch(0.21 ${c * 0.8} ${hue})`,
|
|
2080
|
+
cardForeground: `oklch(0.97 ${c * 0.2} ${hue})`,
|
|
2081
|
+
popover: `oklch(0.21 ${c * 0.8} ${hue})`,
|
|
2082
|
+
popoverForeground: `oklch(0.97 ${c * 0.2} ${hue})`,
|
|
2083
|
+
primary: `oklch(0.7 0.18 ${hue})`,
|
|
2084
|
+
primaryForeground: `oklch(0.16 ${c * 0.6} ${hue})`,
|
|
2085
|
+
secondary: `oklch(0.27 ${c * 0.8} ${hue})`,
|
|
2086
|
+
secondaryForeground: `oklch(0.97 ${c * 0.2} ${hue})`,
|
|
2087
|
+
muted: `oklch(0.27 ${c * 0.8} ${hue})`,
|
|
2088
|
+
mutedForeground: `oklch(0.7 ${c * 0.5} ${hue})`,
|
|
2089
|
+
accent: `oklch(0.3 ${c * 1.5} ${hue})`,
|
|
2090
|
+
accentForeground: `oklch(0.97 ${c * 0.2} ${hue})`,
|
|
2091
|
+
destructive: `oklch(0.577 0.245 27.325 / 0.6)`,
|
|
2092
|
+
destructiveForeground: `oklch(0.985 0 0)`,
|
|
2093
|
+
border: `oklch(0.27 ${c * 0.8} ${hue})`,
|
|
2094
|
+
input: `oklch(0.27 ${c * 0.8} ${hue})`,
|
|
2095
|
+
ring: `oklch(0.7 0.18 ${hue} / 0.5)`,
|
|
2096
|
+
radius: "0.625rem"
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
2100
|
+
function tokensToCssBlock(tokens) {
|
|
2101
|
+
if (!tokens) return "";
|
|
2102
|
+
const parts = [];
|
|
2103
|
+
for (const [k, v] of Object.entries(tokens)) {
|
|
2104
|
+
if (v == null) continue;
|
|
2105
|
+
const cssVar = TOKEN_TO_VAR[k];
|
|
2106
|
+
if (cssVar) parts.push(`${cssVar}:${v}`);
|
|
2107
|
+
}
|
|
2108
|
+
return parts.join(";");
|
|
2109
|
+
}
|
|
2110
|
+
var neutral = {
|
|
2005
2111
|
light: {
|
|
2006
2112
|
background: "oklch(1 0 0)",
|
|
2007
2113
|
foreground: "oklch(0.145 0 0)",
|
|
2008
2114
|
card: "oklch(1 0 0)",
|
|
2009
2115
|
cardForeground: "oklch(0.145 0 0)",
|
|
2116
|
+
popover: "oklch(1 0 0)",
|
|
2117
|
+
popoverForeground: "oklch(0.145 0 0)",
|
|
2010
2118
|
primary: "oklch(0.205 0 0)",
|
|
2011
2119
|
primaryForeground: "oklch(0.985 0 0)",
|
|
2012
|
-
|
|
2120
|
+
secondary: "oklch(0.97 0 0)",
|
|
2121
|
+
secondaryForeground: "oklch(0.205 0 0)",
|
|
2122
|
+
muted: "oklch(0.97 0 0)",
|
|
2123
|
+
mutedForeground: "oklch(0.556 0 0)",
|
|
2124
|
+
accent: "oklch(0.97 0 0)",
|
|
2125
|
+
accentForeground: "oklch(0.205 0 0)",
|
|
2126
|
+
destructive: "oklch(0.577 0.245 27.325)",
|
|
2127
|
+
destructiveForeground: "oklch(0.985 0 0)",
|
|
2128
|
+
border: "oklch(0.922 0 0)",
|
|
2129
|
+
input: "oklch(0.922 0 0)",
|
|
2130
|
+
ring: "oklch(0.708 0 0)",
|
|
2131
|
+
radius: "0.625rem"
|
|
2013
2132
|
},
|
|
2014
2133
|
dark: {
|
|
2015
2134
|
background: "oklch(0.145 0 0)",
|
|
2016
2135
|
foreground: "oklch(0.985 0 0)",
|
|
2017
2136
|
card: "oklch(0.205 0 0)",
|
|
2018
2137
|
cardForeground: "oklch(0.985 0 0)",
|
|
2138
|
+
popover: "oklch(0.205 0 0)",
|
|
2139
|
+
popoverForeground: "oklch(0.985 0 0)",
|
|
2019
2140
|
primary: "oklch(0.985 0 0)",
|
|
2020
2141
|
primaryForeground: "oklch(0.205 0 0)",
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
accent: "oklch(0.94 0.04 285)",
|
|
2034
|
-
accentForeground: "oklch(0.3 0.12 285)",
|
|
2035
|
-
ring: "oklch(0.55 0.22 285 / 0.5)"
|
|
2036
|
-
},
|
|
2037
|
-
amber: {
|
|
2038
|
-
primary: "oklch(0.7 0.18 65)",
|
|
2039
|
-
primaryForeground: "oklch(0.2 0 0)",
|
|
2040
|
-
accent: "oklch(0.94 0.05 65)",
|
|
2041
|
-
accentForeground: "oklch(0.3 0.12 65)",
|
|
2042
|
-
ring: "oklch(0.7 0.18 65 / 0.5)"
|
|
2142
|
+
secondary: "oklch(0.269 0 0)",
|
|
2143
|
+
secondaryForeground: "oklch(0.985 0 0)",
|
|
2144
|
+
muted: "oklch(0.269 0 0)",
|
|
2145
|
+
mutedForeground: "oklch(0.708 0 0)",
|
|
2146
|
+
accent: "oklch(0.269 0 0)",
|
|
2147
|
+
accentForeground: "oklch(0.985 0 0)",
|
|
2148
|
+
destructive: "oklch(0.577 0.245 27.325 / 0.6)",
|
|
2149
|
+
destructiveForeground: "oklch(0.985 0 0)",
|
|
2150
|
+
border: "oklch(0.269 0 0)",
|
|
2151
|
+
input: "oklch(0.269 0 0)",
|
|
2152
|
+
ring: "oklch(0.439 0 0)",
|
|
2153
|
+
radius: "0.625rem"
|
|
2043
2154
|
}
|
|
2044
2155
|
};
|
|
2156
|
+
var themePresets = {
|
|
2157
|
+
neutral,
|
|
2158
|
+
light: { light: neutral.light },
|
|
2159
|
+
dark: { light: neutral.dark },
|
|
2160
|
+
violet: buildPreset(285),
|
|
2161
|
+
emerald: buildPreset(162),
|
|
2162
|
+
amber: buildPreset(65),
|
|
2163
|
+
rose: buildPreset(15),
|
|
2164
|
+
sky: buildPreset(235),
|
|
2165
|
+
slate: buildPreset(240, 0.015)
|
|
2166
|
+
};
|
|
2167
|
+
var ISOLATE_LIGHT_TOKENS = neutral.light;
|
|
2168
|
+
var ISOLATE_DARK_TOKENS = neutral.dark;
|
|
2045
2169
|
function getPinningStyles(column) {
|
|
2046
2170
|
const isPinned = column.getIsPinned();
|
|
2047
2171
|
if (!isPinned) return {};
|
|
@@ -2164,6 +2288,8 @@ var DEFAULT_LABELS = {
|
|
|
2164
2288
|
total: "Total",
|
|
2165
2289
|
noData: "No data.",
|
|
2166
2290
|
noResults: "No rows match the current filters.",
|
|
2291
|
+
loadError: "Could not load rows.",
|
|
2292
|
+
retry: "Retry",
|
|
2167
2293
|
refreshing: "Refreshing",
|
|
2168
2294
|
rowsPerPage: "Rows per page",
|
|
2169
2295
|
page: "Page",
|
|
@@ -2177,6 +2303,7 @@ var DENSITY_CLASS = {
|
|
|
2177
2303
|
function DataTable({
|
|
2178
2304
|
data,
|
|
2179
2305
|
columns,
|
|
2306
|
+
dataSource,
|
|
2180
2307
|
isLoading,
|
|
2181
2308
|
isFetching,
|
|
2182
2309
|
onRefresh,
|
|
@@ -2203,12 +2330,13 @@ function DataTable({
|
|
|
2203
2330
|
features,
|
|
2204
2331
|
labels: labelsProp,
|
|
2205
2332
|
density = "default",
|
|
2206
|
-
theme
|
|
2333
|
+
theme,
|
|
2334
|
+
isolate = false
|
|
2207
2335
|
}) {
|
|
2208
2336
|
const labels = { ...DEFAULT_LABELS, ...labelsProp };
|
|
2209
2337
|
const f = {
|
|
2210
2338
|
search: features?.search ?? true,
|
|
2211
|
-
refresh: features?.refresh ?? !!onRefresh,
|
|
2339
|
+
refresh: features?.refresh ?? !!(onRefresh || dataSource),
|
|
2212
2340
|
columnVisibility: features?.columnVisibility ?? true,
|
|
2213
2341
|
export: features?.export ?? true,
|
|
2214
2342
|
addRow: features?.addRow ?? !!onAddRow,
|
|
@@ -2219,7 +2347,20 @@ function DataTable({
|
|
|
2219
2347
|
reordering: features?.reordering ?? true,
|
|
2220
2348
|
pinning: features?.pinning ?? true
|
|
2221
2349
|
};
|
|
2222
|
-
const
|
|
2350
|
+
const rawInstanceId = useId();
|
|
2351
|
+
const instanceId = useMemo(
|
|
2352
|
+
() => `dyno-grid-${rawInstanceId.replace(/[^a-zA-Z0-9]/g, "")}`,
|
|
2353
|
+
[rawInstanceId]
|
|
2354
|
+
);
|
|
2355
|
+
const { lightStyle, darkCss } = useMemo(() => {
|
|
2356
|
+
const { light, dark } = splitTheme(theme);
|
|
2357
|
+
const lightTokens = isolate ? { ...ISOLATE_LIGHT_TOKENS, ...light ?? {} } : light;
|
|
2358
|
+
const darkTokens = isolate ? { ...ISOLATE_DARK_TOKENS, ...dark ?? light ?? {} } : dark;
|
|
2359
|
+
return {
|
|
2360
|
+
lightStyle: tokensToStyle(lightTokens),
|
|
2361
|
+
darkCss: darkTokens ? tokensToCssBlock(darkTokens) : null
|
|
2362
|
+
};
|
|
2363
|
+
}, [theme, isolate]);
|
|
2223
2364
|
const [sorting, setSorting] = useState([]);
|
|
2224
2365
|
const [columnFilters, setColumnFilters] = useState([]);
|
|
2225
2366
|
const [internalGlobalFilter, setInternalGlobalFilter] = useState("");
|
|
@@ -2252,14 +2393,80 @@ function DataTable({
|
|
|
2252
2393
|
pageIndex: 0,
|
|
2253
2394
|
pageSize: initialPageSize
|
|
2254
2395
|
});
|
|
2396
|
+
const [sourceRows, setSourceRows] = useState(
|
|
2397
|
+
() => dataSource?.initialData ?? []
|
|
2398
|
+
);
|
|
2399
|
+
const [sourceTotalRecords, setSourceTotalRecords] = useState(void 0);
|
|
2400
|
+
const [sourceError, setSourceError] = useState(null);
|
|
2401
|
+
const [sourceLoading, setSourceLoading] = useState(false);
|
|
2402
|
+
const [sourceFetching, setSourceFetching] = useState(false);
|
|
2403
|
+
const [sourceRefreshKey, setSourceRefreshKey] = useState(0);
|
|
2255
2404
|
const [editingCell, setEditingCell] = useState(null);
|
|
2256
2405
|
const [editingRowId, setEditingRowId] = useState(null);
|
|
2257
2406
|
const [rowDraft, setRowDraft] = useState({});
|
|
2407
|
+
const dataSourceEnabled = !!dataSource && dataSource.enabled !== false;
|
|
2408
|
+
const dataSourceMode = dataSource?.mode ?? "client";
|
|
2409
|
+
const isServerSideDataSource = dataSourceEnabled && dataSourceMode === "server";
|
|
2410
|
+
const dataSourceDeps = dataSource?.deps ?? [];
|
|
2411
|
+
useEffect(() => {
|
|
2412
|
+
if (!dataSourceEnabled || !dataSource) return;
|
|
2413
|
+
let cancelled = false;
|
|
2414
|
+
const isInitialLoad = sourceRows.length === 0;
|
|
2415
|
+
setSourceError(null);
|
|
2416
|
+
setSourceLoading(isInitialLoad);
|
|
2417
|
+
setSourceFetching(!isInitialLoad);
|
|
2418
|
+
dataSource.fetchRows({
|
|
2419
|
+
pageIndex: pagination.pageIndex,
|
|
2420
|
+
pageSize: pagination.pageSize,
|
|
2421
|
+
sorting,
|
|
2422
|
+
columnFilters,
|
|
2423
|
+
globalFilter
|
|
2424
|
+
}).then((result) => {
|
|
2425
|
+
if (cancelled) return;
|
|
2426
|
+
const rows2 = Array.isArray(result) ? result : result.rows;
|
|
2427
|
+
setSourceRows(rows2);
|
|
2428
|
+
setSourceTotalRecords(
|
|
2429
|
+
Array.isArray(result) ? rows2.length : result.totalRecords ?? rows2.length
|
|
2430
|
+
);
|
|
2431
|
+
}).catch((error) => {
|
|
2432
|
+
if (cancelled) return;
|
|
2433
|
+
setSourceError(error);
|
|
2434
|
+
dataSource.onError?.(error, {
|
|
2435
|
+
type: isInitialLoad ? "load" : "refresh",
|
|
2436
|
+
message: isInitialLoad ? labels.loadError : labels.refreshing
|
|
2437
|
+
});
|
|
2438
|
+
}).finally(() => {
|
|
2439
|
+
if (cancelled) return;
|
|
2440
|
+
setSourceLoading(false);
|
|
2441
|
+
setSourceFetching(false);
|
|
2442
|
+
});
|
|
2443
|
+
return () => {
|
|
2444
|
+
cancelled = true;
|
|
2445
|
+
};
|
|
2446
|
+
}, [
|
|
2447
|
+
dataSourceEnabled,
|
|
2448
|
+
dataSource,
|
|
2449
|
+
sourceRefreshKey,
|
|
2450
|
+
pagination.pageIndex,
|
|
2451
|
+
pagination.pageSize,
|
|
2452
|
+
sorting,
|
|
2453
|
+
columnFilters,
|
|
2454
|
+
globalFilter,
|
|
2455
|
+
labels.loadError,
|
|
2456
|
+
labels.refreshing,
|
|
2457
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2458
|
+
...dataSourceDeps
|
|
2459
|
+
]);
|
|
2460
|
+
const baseData = dataSourceEnabled ? sourceRows : data ?? [];
|
|
2461
|
+
const effectiveIsLoading = dataSourceEnabled ? sourceLoading : isLoading;
|
|
2462
|
+
const effectiveIsFetching = dataSourceEnabled ? sourceFetching : isFetching;
|
|
2463
|
+
const effectiveOnRefresh = dataSourceEnabled ? () => setSourceRefreshKey((key) => key + 1) : onRefresh;
|
|
2258
2464
|
const [extraRows, setExtraRows] = useState([]);
|
|
2259
2465
|
const mergedData = useMemo(
|
|
2260
|
-
() => extraRows.length ? [...extraRows, ...
|
|
2261
|
-
[extraRows,
|
|
2466
|
+
() => extraRows.length ? [...extraRows, ...baseData] : baseData,
|
|
2467
|
+
[extraRows, baseData]
|
|
2262
2468
|
);
|
|
2469
|
+
const effectiveTotalRecords = totalRecords ?? (dataSourceEnabled ? sourceTotalRecords ?? mergedData.length : mergedData.length);
|
|
2263
2470
|
const augmentedColumns = useMemo(() => {
|
|
2264
2471
|
const wrap = (col) => {
|
|
2265
2472
|
const meta = col.meta;
|
|
@@ -2409,6 +2616,10 @@ function DataTable({
|
|
|
2409
2616
|
enableRowSelection: true,
|
|
2410
2617
|
enableExpanding: !!(renderSubRow || getSubRows),
|
|
2411
2618
|
enablePinning: f.pinning,
|
|
2619
|
+
manualPagination: isServerSideDataSource,
|
|
2620
|
+
manualSorting: isServerSideDataSource,
|
|
2621
|
+
manualFiltering: isServerSideDataSource,
|
|
2622
|
+
pageCount: isServerSideDataSource ? Math.max(1, Math.ceil(effectiveTotalRecords / pagination.pageSize)) : void 0,
|
|
2412
2623
|
getRowId: (row) => String(row.id),
|
|
2413
2624
|
getSubRows,
|
|
2414
2625
|
getRowCanExpand: (row) => {
|
|
@@ -2433,27 +2644,56 @@ function DataTable({
|
|
|
2433
2644
|
getExpandedRowModel: getExpandedRowModel(),
|
|
2434
2645
|
getPaginationRowModel: getPaginationRowModel()
|
|
2435
2646
|
});
|
|
2436
|
-
const
|
|
2437
|
-
const
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2647
|
+
const reorderState = useRef(null);
|
|
2648
|
+
const [activeReorderId, setActiveReorderId] = useState(null);
|
|
2649
|
+
const [dragOverColId, setDragOverColId] = useState(null);
|
|
2650
|
+
const isInteractiveTarget = (target) => {
|
|
2651
|
+
const el = target;
|
|
2652
|
+
if (!el || !el.closest) return false;
|
|
2653
|
+
return !!el.closest(
|
|
2654
|
+
'button, a, input, select, textarea, [role="menuitem"], [data-no-drag]'
|
|
2655
|
+
);
|
|
2441
2656
|
};
|
|
2442
|
-
const
|
|
2443
|
-
e.
|
|
2444
|
-
e.
|
|
2657
|
+
const onHeaderPointerDown = (id) => (e) => {
|
|
2658
|
+
if (e.button !== 0) return;
|
|
2659
|
+
if (isInteractiveTarget(e.target)) return;
|
|
2660
|
+
reorderState.current = { x: e.clientX, y: e.clientY, id };
|
|
2445
2661
|
};
|
|
2446
|
-
const
|
|
2447
|
-
const
|
|
2448
|
-
|
|
2449
|
-
if (!
|
|
2662
|
+
const onHeaderPointerMove = (e) => {
|
|
2663
|
+
const start = reorderState.current;
|
|
2664
|
+
if (!start) return;
|
|
2665
|
+
if (!activeReorderId) {
|
|
2666
|
+
const dx = e.clientX - start.x;
|
|
2667
|
+
const dy = e.clientY - start.y;
|
|
2668
|
+
if (Math.hypot(dx, dy) < 6) return;
|
|
2669
|
+
setActiveReorderId(start.id);
|
|
2670
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2671
|
+
}
|
|
2672
|
+
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
2673
|
+
const th = el ? el.closest("th[data-col-id]") : null;
|
|
2674
|
+
const overId = th?.dataset.colId ?? null;
|
|
2675
|
+
const next = overId && overId !== start.id ? overId : null;
|
|
2676
|
+
if (next !== dragOverColId) setDragOverColId(next);
|
|
2677
|
+
};
|
|
2678
|
+
const onHeaderPointerUp = (e) => {
|
|
2679
|
+
const start = reorderState.current;
|
|
2680
|
+
reorderState.current = null;
|
|
2681
|
+
if (!activeReorderId) return;
|
|
2682
|
+
try {
|
|
2683
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
2684
|
+
} catch {
|
|
2685
|
+
}
|
|
2686
|
+
const target = dragOverColId;
|
|
2687
|
+
setActiveReorderId(null);
|
|
2688
|
+
setDragOverColId(null);
|
|
2689
|
+
if (!start || !target || target === start.id) return;
|
|
2450
2690
|
setColumnOrder((order) => {
|
|
2451
2691
|
const next = [...order];
|
|
2452
|
-
const from = next.indexOf(
|
|
2453
|
-
const to = next.indexOf(
|
|
2692
|
+
const from = next.indexOf(start.id);
|
|
2693
|
+
const to = next.indexOf(target);
|
|
2454
2694
|
if (from === -1 || to === -1) return order;
|
|
2455
2695
|
next.splice(from, 1);
|
|
2456
|
-
next.splice(to, 0,
|
|
2696
|
+
next.splice(to, 0, start.id);
|
|
2457
2697
|
return next;
|
|
2458
2698
|
});
|
|
2459
2699
|
};
|
|
@@ -2499,20 +2739,26 @@ function DataTable({
|
|
|
2499
2739
|
children: /* @__PURE__ */ jsxs(
|
|
2500
2740
|
"div",
|
|
2501
2741
|
{
|
|
2742
|
+
"data-dyno-grid": instanceId,
|
|
2502
2743
|
className: cn(
|
|
2503
2744
|
"flex flex-col rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
2504
2745
|
DENSITY_CLASS[density],
|
|
2505
2746
|
className
|
|
2506
2747
|
),
|
|
2507
|
-
style:
|
|
2748
|
+
style: lightStyle,
|
|
2508
2749
|
children: [
|
|
2750
|
+
darkCss && /* @__PURE__ */ jsxs("style", { children: [
|
|
2751
|
+
`@media (prefers-color-scheme: dark){[data-dyno-grid="${instanceId}"]{${darkCss}}}`,
|
|
2752
|
+
`.dark [data-dyno-grid="${instanceId}"]{${darkCss}}`,
|
|
2753
|
+
`[data-dyno-grid="${instanceId}"].dark{${darkCss}}`
|
|
2754
|
+
] }),
|
|
2509
2755
|
/* @__PURE__ */ jsx(
|
|
2510
2756
|
DataTableToolbar,
|
|
2511
2757
|
{
|
|
2512
2758
|
table,
|
|
2513
|
-
totalRecords:
|
|
2514
|
-
isFetching,
|
|
2515
|
-
onRefresh: f.refresh ?
|
|
2759
|
+
totalRecords: effectiveTotalRecords,
|
|
2760
|
+
isFetching: effectiveIsFetching,
|
|
2761
|
+
onRefresh: f.refresh ? effectiveOnRefresh : void 0,
|
|
2516
2762
|
onAddRow: f.addRow ? handleAddRow : void 0,
|
|
2517
2763
|
onBulkDelete,
|
|
2518
2764
|
exportFileName,
|
|
@@ -2540,32 +2786,38 @@ function DataTable({
|
|
|
2540
2786
|
const meta = header.column.columnDef.meta;
|
|
2541
2787
|
const isUtility = header.column.id === "__select" || header.column.id === "__expand" || header.column.id === "__actions";
|
|
2542
2788
|
const isPinned = !!header.column.getIsPinned();
|
|
2789
|
+
const canReorder = !isUtility && f.reordering;
|
|
2790
|
+
const isDropTarget = canReorder && dragOverColId === header.column.id;
|
|
2791
|
+
const isBeingDragged = canReorder && activeReorderId === header.column.id;
|
|
2543
2792
|
return /* @__PURE__ */ jsxs(
|
|
2544
2793
|
"th",
|
|
2545
2794
|
{
|
|
2546
2795
|
colSpan: header.colSpan,
|
|
2796
|
+
"data-col-id": header.column.id,
|
|
2797
|
+
onPointerDown: canReorder ? onHeaderPointerDown(header.column.id) : void 0,
|
|
2798
|
+
onPointerMove: canReorder ? onHeaderPointerMove : void 0,
|
|
2799
|
+
onPointerUp: canReorder ? onHeaderPointerUp : void 0,
|
|
2800
|
+
onPointerCancel: canReorder ? onHeaderPointerUp : void 0,
|
|
2547
2801
|
style: {
|
|
2548
2802
|
width: header.getSize(),
|
|
2549
2803
|
...getPinningStyles(header.column),
|
|
2550
2804
|
...isPinned ? { zIndex: 2 } : {}
|
|
2551
2805
|
},
|
|
2552
2806
|
className: cn(
|
|
2553
|
-
"group/th relative h-9 px-2 text-left align-middle text-xs font-medium text-muted-foreground",
|
|
2807
|
+
"group/th relative h-9 px-2 text-left align-middle text-xs font-medium text-muted-foreground select-none",
|
|
2808
|
+
canReorder && "cursor-grab active:cursor-grabbing",
|
|
2554
2809
|
isPinned && "bg-card",
|
|
2810
|
+
isBeingDragged && "opacity-50",
|
|
2811
|
+
isDropTarget && "bg-primary/10 ring-2 ring-inset ring-primary/40",
|
|
2555
2812
|
meta?.headerClassName
|
|
2556
2813
|
),
|
|
2557
2814
|
children: [
|
|
2558
2815
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
2559
|
-
|
|
2560
|
-
|
|
2816
|
+
canReorder && /* @__PURE__ */ jsx(
|
|
2817
|
+
GripVerticalIcon,
|
|
2561
2818
|
{
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
onDragOver: onHeaderDragOver,
|
|
2565
|
-
onDrop: () => onHeaderDrop(header.column.id),
|
|
2566
|
-
className: "-ml-1 cursor-grab rounded p-0.5 text-muted-foreground/40 opacity-0 transition group-hover/th:opacity-100 hover:bg-muted hover:text-foreground active:cursor-grabbing",
|
|
2567
|
-
title: "Drag to reorder",
|
|
2568
|
-
children: /* @__PURE__ */ jsx(GripVerticalIcon, { className: "size-3" })
|
|
2819
|
+
className: "-ml-1 size-3 shrink-0 text-muted-foreground/40 opacity-0 transition group-hover/th:opacity-100",
|
|
2820
|
+
"aria-hidden": "true"
|
|
2569
2821
|
}
|
|
2570
2822
|
),
|
|
2571
2823
|
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) })
|
|
@@ -2573,6 +2825,8 @@ function DataTable({
|
|
|
2573
2825
|
header.column.getCanResize() && /* @__PURE__ */ jsx(
|
|
2574
2826
|
"span",
|
|
2575
2827
|
{
|
|
2828
|
+
"data-no-drag": true,
|
|
2829
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
2576
2830
|
onMouseDown: header.getResizeHandler(),
|
|
2577
2831
|
onTouchStart: header.getResizeHandler(),
|
|
2578
2832
|
onDoubleClick: () => header.column.resetSize(),
|
|
@@ -2587,7 +2841,25 @@ function DataTable({
|
|
|
2587
2841
|
header.id
|
|
2588
2842
|
);
|
|
2589
2843
|
}) }, hg.id)) }),
|
|
2590
|
-
/* @__PURE__ */ jsx("tbody", { children:
|
|
2844
|
+
/* @__PURE__ */ jsx("tbody", { children: effectiveIsLoading ? renderSkeleton(visibleLeafCount, pagination.pageSize) : sourceError && rows.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
2845
|
+
"td",
|
|
2846
|
+
{
|
|
2847
|
+
colSpan: visibleLeafCount,
|
|
2848
|
+
className: "h-32 text-center text-sm text-muted-foreground",
|
|
2849
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
2850
|
+
/* @__PURE__ */ jsx("span", { children: labels.loadError }),
|
|
2851
|
+
effectiveOnRefresh && /* @__PURE__ */ jsx(
|
|
2852
|
+
"button",
|
|
2853
|
+
{
|
|
2854
|
+
type: "button",
|
|
2855
|
+
onClick: effectiveOnRefresh,
|
|
2856
|
+
className: "rounded-md border px-2 py-1 text-xs text-foreground hover:bg-muted",
|
|
2857
|
+
children: labels.retry
|
|
2858
|
+
}
|
|
2859
|
+
)
|
|
2860
|
+
] })
|
|
2861
|
+
}
|
|
2862
|
+
) }) : rows.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
2591
2863
|
"td",
|
|
2592
2864
|
{
|
|
2593
2865
|
colSpan: visibleLeafCount,
|
|
@@ -2606,7 +2878,7 @@ function DataTable({
|
|
|
2606
2878
|
]
|
|
2607
2879
|
}
|
|
2608
2880
|
),
|
|
2609
|
-
|
|
2881
|
+
effectiveIsFetching && !effectiveIsLoading && /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute top-1.5 right-2 flex items-center gap-1.5 rounded-md bg-background/80 px-2 py-1 text-xs text-muted-foreground shadow-sm backdrop-blur", children: [
|
|
2610
2882
|
/* @__PURE__ */ jsx(Loader2Icon, { className: "size-3 animate-spin" }),
|
|
2611
2883
|
" ",
|
|
2612
2884
|
labels.refreshing
|
|
@@ -2666,6 +2938,6 @@ function renderSkeleton(cols, rows) {
|
|
|
2666
2938
|
return Array.from({ length: rows }).map((_, r) => /* @__PURE__ */ jsx("tr", { className: "border-b", children: Array.from({ length: cols }).map((__, c) => /* @__PURE__ */ jsx("td", { className: "px-2 py-2", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, c)) }, r));
|
|
2667
2939
|
}
|
|
2668
2940
|
|
|
2669
|
-
export { ColumnFilterPanel, DataTable, DataTableColumnHeader, DataTablePagination, DataTableRowActions, DataTableToolbar, EditableCell, booleanFilterFn, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, setFilterFn, textFilterFn, themePresets, themeToStyle };
|
|
2941
|
+
export { ColumnFilterPanel, DataTable, DataTableColumnHeader, DataTablePagination, DataTableRowActions, DataTableToolbar, EditableCell, ISOLATE_DARK_TOKENS, ISOLATE_LIGHT_TOKENS, booleanFilterFn, buildPreset, dateFilterFn, exportToCsv, exportToExcel, isFilterActive, numberFilterFn, setFilterFn, splitTheme, textFilterFn, themePresets, themeToStyle, tokensToCssBlock, tokensToStyle };
|
|
2670
2942
|
//# sourceMappingURL=index.js.map
|
|
2671
2943
|
//# sourceMappingURL=index.js.map
|