@dimaan/ui 0.0.18 → 0.0.20
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 +145 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +203 -144
- package/dist/index.d.ts +203 -144
- package/dist/index.js +146 -166
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1724,12 +1724,26 @@ var formPageBodyClass = "flex-1";
|
|
|
1724
1724
|
var formPageActionsBarClass = "sticky bottom-0 -mx-6 -mb-6 mt-6 flex items-center justify-end gap-2 border-t border-border bg-background/95 px-6 py-3 backdrop-blur supports-[backdrop-filter]:bg-background/80";
|
|
1725
1725
|
var formPageSkeletonRowClass = "h-10 w-full animate-pulse rounded-md bg-muted";
|
|
1726
1726
|
var DEFAULT_SKELETON_ROW_COUNT2 = 6;
|
|
1727
|
+
var DEFAULT_LABELS_LTR = {
|
|
1728
|
+
back: "Back",
|
|
1729
|
+
cancel: "Cancel",
|
|
1730
|
+
save: "Save",
|
|
1731
|
+
saving: "Saving\u2026"
|
|
1732
|
+
};
|
|
1733
|
+
var DEFAULT_LABELS_RTL = {
|
|
1734
|
+
back: "\u0631\u062C\u0648\u0639",
|
|
1735
|
+
cancel: "\u0625\u0644\u063A\u0627\u0621",
|
|
1736
|
+
save: "\u062D\u0641\u0638",
|
|
1737
|
+
saving: "\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026"
|
|
1738
|
+
};
|
|
1727
1739
|
function FormPage({
|
|
1728
1740
|
title,
|
|
1729
1741
|
description,
|
|
1730
|
-
back,
|
|
1731
1742
|
bordered = true,
|
|
1732
1743
|
onSubmit,
|
|
1744
|
+
onCancel,
|
|
1745
|
+
isSubmitting,
|
|
1746
|
+
labels: labelsProp,
|
|
1733
1747
|
isLoading = false,
|
|
1734
1748
|
loadingRowCount = DEFAULT_SKELETON_ROW_COUNT2,
|
|
1735
1749
|
actions,
|
|
@@ -1739,8 +1753,23 @@ function FormPage({
|
|
|
1739
1753
|
bodyClassName,
|
|
1740
1754
|
actionsClassName
|
|
1741
1755
|
}) {
|
|
1756
|
+
const navigate = reactRouterDom.useNavigate();
|
|
1757
|
+
const dir = useDirection();
|
|
1758
|
+
const formContext = reactHookForm.useFormContext();
|
|
1759
|
+
const submitting = isSubmitting ?? formContext?.formState?.isSubmitting ?? false;
|
|
1760
|
+
const defaults = dir === "rtl" ? DEFAULT_LABELS_RTL : DEFAULT_LABELS_LTR;
|
|
1761
|
+
const labels = { ...defaults, ...labelsProp };
|
|
1762
|
+
const goBack = () => navigate(-1);
|
|
1742
1763
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "form-page", className: cn(formPageBaseClass, className), children: [
|
|
1743
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1764
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1765
|
+
PageHeader,
|
|
1766
|
+
{
|
|
1767
|
+
title,
|
|
1768
|
+
description,
|
|
1769
|
+
back: { label: labels.back, onClick: goBack },
|
|
1770
|
+
bordered
|
|
1771
|
+
}
|
|
1772
|
+
),
|
|
1744
1773
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1745
1774
|
"form",
|
|
1746
1775
|
{
|
|
@@ -1751,14 +1780,27 @@ function FormPage({
|
|
|
1751
1780
|
className: cn("flex flex-1 flex-col gap-6", formClassName),
|
|
1752
1781
|
children: [
|
|
1753
1782
|
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "form-page-body", className: cn(formPageBodyClass, bodyClassName), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(FormPageSkeleton, { rowCount: loadingRowCount }) : children }),
|
|
1754
|
-
|
|
1783
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1755
1784
|
"div",
|
|
1756
1785
|
{
|
|
1757
1786
|
"data-slot": "form-page-actions",
|
|
1758
1787
|
className: cn(formPageActionsBarClass, actionsClassName),
|
|
1759
|
-
children:
|
|
1788
|
+
children: [
|
|
1789
|
+
actions,
|
|
1790
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "outline", onClick: onCancel ?? goBack, children: labels.cancel }),
|
|
1791
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1792
|
+
Button,
|
|
1793
|
+
{
|
|
1794
|
+
type: "submit",
|
|
1795
|
+
loading: submitting,
|
|
1796
|
+
loadingText: labels.saving,
|
|
1797
|
+
disabled: isLoading,
|
|
1798
|
+
children: labels.save
|
|
1799
|
+
}
|
|
1800
|
+
)
|
|
1801
|
+
]
|
|
1760
1802
|
}
|
|
1761
|
-
)
|
|
1803
|
+
)
|
|
1762
1804
|
]
|
|
1763
1805
|
}
|
|
1764
1806
|
)
|
|
@@ -2009,15 +2051,35 @@ var SelectItem = react.forwardRef(function SelectItem2({ className, children, ..
|
|
|
2009
2051
|
/* @__PURE__ */ jsxRuntime.jsx(RadixSelect__namespace.ItemText, { children })
|
|
2010
2052
|
] });
|
|
2011
2053
|
});
|
|
2054
|
+
var EN_LABELS = {
|
|
2055
|
+
rowsPerPage: "Rows per page",
|
|
2056
|
+
pageRangeOf: "of",
|
|
2057
|
+
previousPage: "Previous page",
|
|
2058
|
+
nextPage: "Next page"
|
|
2059
|
+
};
|
|
2060
|
+
var AR_LABELS = {
|
|
2061
|
+
rowsPerPage: "\u0635\u0641\u0648\u0641 \u0644\u0643\u0644 \u0635\u0641\u062D\u0629",
|
|
2062
|
+
pageRangeOf: "\u0645\u0646",
|
|
2063
|
+
previousPage: "\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
|
|
2064
|
+
nextPage: "\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629"
|
|
2065
|
+
};
|
|
2012
2066
|
function Pagination({
|
|
2013
2067
|
pageIndex,
|
|
2014
2068
|
pageSize,
|
|
2015
2069
|
pageCount,
|
|
2016
2070
|
totalRowCount,
|
|
2017
2071
|
pageSizeOptions,
|
|
2018
|
-
onChange
|
|
2072
|
+
onChange,
|
|
2073
|
+
labels: labelsProp
|
|
2019
2074
|
}) {
|
|
2020
2075
|
const dir = useDirection();
|
|
2076
|
+
const localeDefaults = dir === "rtl" ? AR_LABELS : EN_LABELS;
|
|
2077
|
+
const labels = {
|
|
2078
|
+
rowsPerPage: labelsProp?.rowsPerPage ?? localeDefaults.rowsPerPage,
|
|
2079
|
+
pageRangeOf: labelsProp?.pageRangeOf ?? localeDefaults.pageRangeOf,
|
|
2080
|
+
previousPage: labelsProp?.previousPage ?? localeDefaults.previousPage,
|
|
2081
|
+
nextPage: labelsProp?.nextPage ?? localeDefaults.nextPage
|
|
2082
|
+
};
|
|
2021
2083
|
const isRtl = dir === "rtl";
|
|
2022
2084
|
const isFirst = pageIndex <= 0;
|
|
2023
2085
|
const isLast = pageIndex >= pageCount - 1;
|
|
@@ -2031,7 +2093,7 @@ function Pagination({
|
|
|
2031
2093
|
const end = Math.min(totalRowCount, (pageIndex + 1) * pageSize);
|
|
2032
2094
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 text-sm text-muted-foreground", children: [
|
|
2033
2095
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
|
|
2034
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
2096
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.rowsPerPage }),
|
|
2035
2097
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2036
2098
|
"select",
|
|
2037
2099
|
{
|
|
@@ -2050,7 +2112,9 @@ function Pagination({
|
|
|
2050
2112
|
start,
|
|
2051
2113
|
"\u2013",
|
|
2052
2114
|
end,
|
|
2053
|
-
"
|
|
2115
|
+
" ",
|
|
2116
|
+
labels.pageRangeOf,
|
|
2117
|
+
" ",
|
|
2054
2118
|
totalRowCount
|
|
2055
2119
|
] }),
|
|
2056
2120
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
@@ -2062,7 +2126,7 @@ function Pagination({
|
|
|
2062
2126
|
size: "sm",
|
|
2063
2127
|
disabled: isFirst,
|
|
2064
2128
|
onClick: goPrev,
|
|
2065
|
-
"aria-label":
|
|
2129
|
+
"aria-label": labels.previousPage,
|
|
2066
2130
|
children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
|
|
2067
2131
|
}
|
|
2068
2132
|
),
|
|
@@ -2079,7 +2143,7 @@ function Pagination({
|
|
|
2079
2143
|
size: "sm",
|
|
2080
2144
|
disabled: isLast,
|
|
2081
2145
|
onClick: goNext,
|
|
2082
|
-
"aria-label":
|
|
2146
|
+
"aria-label": labels.nextPage,
|
|
2083
2147
|
children: isRtl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
|
|
2084
2148
|
}
|
|
2085
2149
|
)
|
|
@@ -2132,71 +2196,37 @@ var alignClass = {
|
|
|
2132
2196
|
end: "text-end"
|
|
2133
2197
|
};
|
|
2134
2198
|
var EMPTY_SELECTION = /* @__PURE__ */ new Set();
|
|
2135
|
-
var NO_SORT = { columnId: null, direction: "asc" };
|
|
2136
2199
|
function useTableState(props) {
|
|
2137
2200
|
const {
|
|
2138
|
-
defaultSort,
|
|
2139
|
-
sort: sortProp,
|
|
2140
|
-
onSortChange,
|
|
2141
|
-
defaultPagination,
|
|
2142
|
-
pagination: paginationProp,
|
|
2143
|
-
onPaginationChange,
|
|
2144
|
-
pageSizeOptions,
|
|
2145
2201
|
defaultSelectedRowIds,
|
|
2146
2202
|
selectedRowIds: selectedRowIdsProp,
|
|
2147
|
-
onSelectedRowIdsChange
|
|
2148
|
-
totalCount
|
|
2203
|
+
onSelectedRowIdsChange
|
|
2149
2204
|
} = props;
|
|
2150
|
-
const [internalSort, setInternalSort] = react.useState(defaultSort ?? NO_SORT);
|
|
2151
|
-
const isSortControlled = sortProp !== void 0;
|
|
2152
|
-
const sort = isSortControlled ? sortProp : internalSort;
|
|
2153
|
-
const setSort = react.useCallback(
|
|
2154
|
-
(next) => {
|
|
2155
|
-
if (!isSortControlled) setInternalSort(next);
|
|
2156
|
-
onSortChange?.(next);
|
|
2157
|
-
},
|
|
2158
|
-
[isSortControlled, onSortChange]
|
|
2159
|
-
);
|
|
2160
|
-
const [internalPagination, setInternalPagination] = react.useState(
|
|
2161
|
-
defaultPagination ?? { pageIndex: 0, pageSize: pageSizeOptions?.[0] ?? 10 }
|
|
2162
|
-
);
|
|
2163
|
-
const isPaginationControlled = paginationProp !== void 0;
|
|
2164
|
-
const pagination = isPaginationControlled ? paginationProp : internalPagination;
|
|
2165
|
-
const setPagination = react.useCallback(
|
|
2166
|
-
(next) => {
|
|
2167
|
-
if (!isPaginationControlled) setInternalPagination(next);
|
|
2168
|
-
onPaginationChange?.(next);
|
|
2169
|
-
},
|
|
2170
|
-
[isPaginationControlled, onPaginationChange]
|
|
2171
|
-
);
|
|
2172
2205
|
const [internalSelected, setInternalSelected] = react.useState(
|
|
2173
2206
|
defaultSelectedRowIds ?? EMPTY_SELECTION
|
|
2174
2207
|
);
|
|
2175
|
-
const
|
|
2176
|
-
const selected =
|
|
2208
|
+
const isControlled = selectedRowIdsProp !== void 0;
|
|
2209
|
+
const selected = isControlled ? selectedRowIdsProp : internalSelected;
|
|
2177
2210
|
const setSelected = react.useCallback(
|
|
2178
2211
|
(next) => {
|
|
2179
|
-
if (!
|
|
2212
|
+
if (!isControlled) setInternalSelected(next);
|
|
2180
2213
|
onSelectedRowIdsChange?.(next);
|
|
2181
2214
|
},
|
|
2182
|
-
[
|
|
2215
|
+
[isControlled, onSelectedRowIdsChange]
|
|
2183
2216
|
);
|
|
2184
|
-
return {
|
|
2185
|
-
sort,
|
|
2186
|
-
setSort,
|
|
2187
|
-
pagination,
|
|
2188
|
-
setPagination,
|
|
2189
|
-
selected,
|
|
2190
|
-
setSelected,
|
|
2191
|
-
isServerSide: totalCount !== void 0
|
|
2192
|
-
};
|
|
2217
|
+
return { selected, setSelected };
|
|
2193
2218
|
}
|
|
2194
2219
|
var DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50];
|
|
2220
|
+
var DEFAULT_PAGE_SIZE = 10;
|
|
2221
|
+
function defaultGetRowId(row, index) {
|
|
2222
|
+
const rowId = row.id;
|
|
2223
|
+
return rowId === void 0 || rowId === null ? String(index) : String(rowId);
|
|
2224
|
+
}
|
|
2195
2225
|
function Table(props) {
|
|
2196
2226
|
const {
|
|
2197
2227
|
data,
|
|
2198
2228
|
columns,
|
|
2199
|
-
getRowId,
|
|
2229
|
+
getRowId = defaultGetRowId,
|
|
2200
2230
|
enableRowSelection = false,
|
|
2201
2231
|
isRowSelectable,
|
|
2202
2232
|
bulkActions,
|
|
@@ -2214,36 +2244,26 @@ function Table(props) {
|
|
|
2214
2244
|
tableRef,
|
|
2215
2245
|
pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
|
|
2216
2246
|
showPagination,
|
|
2217
|
-
caption
|
|
2247
|
+
caption,
|
|
2248
|
+
sort,
|
|
2249
|
+
onSortChange,
|
|
2250
|
+
pagination,
|
|
2251
|
+
onPaginationChange,
|
|
2252
|
+
totalCount,
|
|
2253
|
+
labels
|
|
2218
2254
|
} = props;
|
|
2219
2255
|
const ariaLabel = props["aria-label"];
|
|
2220
2256
|
const ariaLabelledBy = props["aria-labelledby"];
|
|
2221
|
-
const {
|
|
2222
|
-
const
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
if (!get) return data;
|
|
2228
|
-
const tagged = data.map((row, index) => ({ row, index }));
|
|
2229
|
-
tagged.sort((a, b) => {
|
|
2230
|
-
const cmp = compareValues(get(a.row), get(b.row));
|
|
2231
|
-
if (cmp !== 0) return sort.direction === "asc" ? cmp : -cmp;
|
|
2232
|
-
return a.index - b.index;
|
|
2233
|
-
});
|
|
2234
|
-
return tagged.map((entry) => entry.row);
|
|
2235
|
-
}, [data, columns, sort, isServerSide]);
|
|
2236
|
-
const pagedRows = react.useMemo(() => {
|
|
2237
|
-
if (isServerSide) return sortedRows;
|
|
2238
|
-
const start = pagination.pageIndex * pagination.pageSize;
|
|
2239
|
-
return sortedRows.slice(start, start + pagination.pageSize);
|
|
2240
|
-
}, [sortedRows, pagination, isServerSide]);
|
|
2241
|
-
const totalRowCount = isServerSide ? props.totalCount ?? 0 : data.length;
|
|
2242
|
-
const pageCount = Math.max(1, Math.ceil(totalRowCount / pagination.pageSize));
|
|
2257
|
+
const { selected, setSelected } = useTableState(props);
|
|
2258
|
+
const effectiveSort = sort ?? { columnId: null, direction: "asc" };
|
|
2259
|
+
const pageSize = pagination?.pageSize ?? pageSizeOptions[0] ?? DEFAULT_PAGE_SIZE;
|
|
2260
|
+
const pageIndex = pagination?.pageIndex ?? 0;
|
|
2261
|
+
const totalRowCount = totalCount ?? data.length;
|
|
2262
|
+
const pageCount = Math.max(1, Math.ceil(totalRowCount / pageSize));
|
|
2243
2263
|
const selectableRowIds = react.useMemo(() => {
|
|
2244
2264
|
if (!enableRowSelection) return [];
|
|
2245
|
-
return
|
|
2246
|
-
}, [
|
|
2265
|
+
return data.map((row, index) => ({ row, index })).filter(({ row }) => isRowSelectable ? isRowSelectable(row) : true).map(({ row, index }) => getRowId(row, index));
|
|
2266
|
+
}, [data, enableRowSelection, isRowSelectable, getRowId]);
|
|
2247
2267
|
const selectedOnPageCount = selectableRowIds.reduce(
|
|
2248
2268
|
(acc, id) => selected.has(id) ? acc + 1 : acc,
|
|
2249
2269
|
0
|
|
@@ -2271,13 +2291,16 @@ function Table(props) {
|
|
|
2271
2291
|
};
|
|
2272
2292
|
const clearSelection = () => setSelected(/* @__PURE__ */ new Set());
|
|
2273
2293
|
const handleSortClick = (columnId) => {
|
|
2274
|
-
|
|
2294
|
+
if (!onSortChange) return;
|
|
2295
|
+
onSortChange(nextSort(effectiveSort, columnId));
|
|
2275
2296
|
};
|
|
2297
|
+
const handlePaginationChange = onPaginationChange ?? (() => {
|
|
2298
|
+
});
|
|
2276
2299
|
const totalColumnCount = columns.length + (enableRowSelection ? 1 : 0);
|
|
2277
|
-
const paginationVisible = showPagination ?? totalRowCount >
|
|
2300
|
+
const paginationVisible = Boolean(pagination) && (showPagination ?? totalRowCount > pageSize);
|
|
2278
2301
|
const sizeClasses = tableSizeClass[size];
|
|
2279
2302
|
const showToolbar = enableRowSelection && bulkActions !== void 0 && selected.size > 0;
|
|
2280
|
-
const skeletonCount = loadingRowCount ??
|
|
2303
|
+
const skeletonCount = loadingRowCount ?? pageSize;
|
|
2281
2304
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-3", className), children: [
|
|
2282
2305
|
showToolbar && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2283
2306
|
Toolbar,
|
|
@@ -2326,8 +2349,8 @@ function Table(props) {
|
|
|
2326
2349
|
}
|
|
2327
2350
|
) }) : null,
|
|
2328
2351
|
columns.map((column) => {
|
|
2329
|
-
const isSorted =
|
|
2330
|
-
const ariaSort = isSorted ?
|
|
2352
|
+
const isSorted = effectiveSort.columnId === column.id;
|
|
2353
|
+
const ariaSort = isSorted ? effectiveSort.direction === "asc" ? "ascending" : "descending" : "none";
|
|
2331
2354
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2332
2355
|
"th",
|
|
2333
2356
|
{
|
|
@@ -2344,14 +2367,14 @@ function Table(props) {
|
|
|
2344
2367
|
type: "button",
|
|
2345
2368
|
onClick: () => handleSortClick(column.id),
|
|
2346
2369
|
className: "inline-flex items-center gap-1.5 font-inherit uppercase tracking-inherit text-inherit hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
2347
|
-
"aria-label": sortAriaLabel(column,
|
|
2370
|
+
"aria-label": sortAriaLabel(column, effectiveSort),
|
|
2348
2371
|
children: [
|
|
2349
2372
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: renderHeader(column.header) }),
|
|
2350
2373
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2351
2374
|
SortIndicator,
|
|
2352
2375
|
{
|
|
2353
2376
|
active: isSorted,
|
|
2354
|
-
direction: isSorted ?
|
|
2377
|
+
direction: isSorted ? effectiveSort.direction : null
|
|
2355
2378
|
}
|
|
2356
2379
|
)
|
|
2357
2380
|
]
|
|
@@ -2371,14 +2394,14 @@ function Table(props) {
|
|
|
2371
2394
|
columnCount: totalColumnCount,
|
|
2372
2395
|
cellClassName: sizeClasses.cell
|
|
2373
2396
|
}
|
|
2374
|
-
) :
|
|
2397
|
+
) : data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2375
2398
|
"td",
|
|
2376
2399
|
{
|
|
2377
2400
|
colSpan: totalColumnCount,
|
|
2378
2401
|
className: cn(sizeClasses.cell, "py-10 text-center text-muted-foreground"),
|
|
2379
2402
|
children: emptyState ?? "No data"
|
|
2380
2403
|
}
|
|
2381
|
-
) }) :
|
|
2404
|
+
) }) : data.map((row, rowIndex) => {
|
|
2382
2405
|
const id = getRowId(row, rowIndex);
|
|
2383
2406
|
const isSelected = selected.has(id);
|
|
2384
2407
|
const rowSelectable = isRowSelectable ? isRowSelectable(row) : true;
|
|
@@ -2431,12 +2454,13 @@ function Table(props) {
|
|
|
2431
2454
|
paginationVisible ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2432
2455
|
Pagination,
|
|
2433
2456
|
{
|
|
2434
|
-
pageIndex
|
|
2435
|
-
pageSize
|
|
2457
|
+
pageIndex,
|
|
2458
|
+
pageSize,
|
|
2436
2459
|
pageCount,
|
|
2437
2460
|
totalRowCount,
|
|
2438
2461
|
pageSizeOptions,
|
|
2439
|
-
onChange:
|
|
2462
|
+
onChange: handlePaginationChange,
|
|
2463
|
+
labels
|
|
2440
2464
|
}
|
|
2441
2465
|
) : null
|
|
2442
2466
|
] });
|
|
@@ -2452,24 +2476,6 @@ function renderCell(column, row, rowIndex) {
|
|
|
2452
2476
|
}
|
|
2453
2477
|
return null;
|
|
2454
2478
|
}
|
|
2455
|
-
function resolveSortGetter(column) {
|
|
2456
|
-
if (column.sortAccessor) return column.sortAccessor;
|
|
2457
|
-
if (column.accessor !== void 0) {
|
|
2458
|
-
const key = column.accessor;
|
|
2459
|
-
return (row) => row[key];
|
|
2460
|
-
}
|
|
2461
|
-
return null;
|
|
2462
|
-
}
|
|
2463
|
-
function compareValues(a, b) {
|
|
2464
|
-
if (a === b) return 0;
|
|
2465
|
-
if (a === null || a === void 0) return 1;
|
|
2466
|
-
if (b === null || b === void 0) return -1;
|
|
2467
|
-
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
2468
|
-
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
2469
|
-
if (typeof a === "bigint" && typeof b === "bigint") return a < b ? -1 : 1;
|
|
2470
|
-
if (typeof a === "boolean" && typeof b === "boolean") return a === b ? 0 : a ? 1 : -1;
|
|
2471
|
-
return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
|
|
2472
|
-
}
|
|
2473
2479
|
function nextSort(current, columnId) {
|
|
2474
2480
|
if (current.columnId !== columnId) return { columnId, direction: "asc" };
|
|
2475
2481
|
if (current.direction === "asc") return { columnId, direction: "desc" };
|
|
@@ -2520,12 +2526,14 @@ function ListPage({
|
|
|
2520
2526
|
getRowId,
|
|
2521
2527
|
isLoading = false,
|
|
2522
2528
|
loadingRowCount,
|
|
2523
|
-
|
|
2529
|
+
searchValue,
|
|
2530
|
+
onSearchChange,
|
|
2524
2531
|
filters,
|
|
2532
|
+
filterValues,
|
|
2533
|
+
onFilterChange,
|
|
2525
2534
|
enableRowSelection,
|
|
2526
2535
|
bulkActions,
|
|
2527
2536
|
pagination,
|
|
2528
|
-
defaultPagination,
|
|
2529
2537
|
onPaginationChange,
|
|
2530
2538
|
totalCount,
|
|
2531
2539
|
pageSizeOptions,
|
|
@@ -2535,64 +2543,36 @@ function ListPage({
|
|
|
2535
2543
|
className
|
|
2536
2544
|
}) {
|
|
2537
2545
|
const labels = { ...DEFAULT_LABELS2, ...labelsProp };
|
|
2538
|
-
const
|
|
2539
|
-
|
|
2546
|
+
const showSearch = onSearchChange !== void 0;
|
|
2547
|
+
const showFilterBar = showSearch || Boolean(filters?.length);
|
|
2548
|
+
const hasActiveQuery = react.useMemo(() => {
|
|
2549
|
+
if ((searchValue ?? "").trim() !== "") return true;
|
|
2540
2550
|
for (const f of filters ?? []) {
|
|
2541
|
-
|
|
2551
|
+
const current = filterValues?.[f.key];
|
|
2552
|
+
const def = f.options[0]?.value ?? "";
|
|
2553
|
+
if (current !== void 0 && current !== def) return true;
|
|
2542
2554
|
}
|
|
2543
|
-
return
|
|
2544
|
-
}, [filters]);
|
|
2545
|
-
const [search, setSearch] = react.useState("");
|
|
2546
|
-
const [filterValues, setFilterValues] = react.useState(initialFilterValues);
|
|
2547
|
-
const setFilter = (key, value) => {
|
|
2548
|
-
setFilterValues((prev) => ({ ...prev, [key]: value }));
|
|
2549
|
-
};
|
|
2555
|
+
return false;
|
|
2556
|
+
}, [searchValue, filters, filterValues]);
|
|
2550
2557
|
const reset = () => {
|
|
2551
|
-
|
|
2552
|
-
setFilterValues(initialFilterValues);
|
|
2553
|
-
};
|
|
2554
|
-
const hasActiveFilters = react.useMemo(() => {
|
|
2555
|
-
if (search.trim() !== "") return true;
|
|
2558
|
+
onSearchChange?.("");
|
|
2556
2559
|
for (const f of filters ?? []) {
|
|
2557
|
-
const
|
|
2558
|
-
|
|
2559
|
-
if (current !== def) return true;
|
|
2560
|
+
const def = f.options[0]?.value ?? "";
|
|
2561
|
+
onFilterChange?.(f.key, def);
|
|
2560
2562
|
}
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
const filtered = react.useMemo(() => {
|
|
2564
|
-
return data.filter((row) => {
|
|
2565
|
-
if (search.trim() && searchKeys && searchKeys.length > 0) {
|
|
2566
|
-
const q = search.trim().toLowerCase();
|
|
2567
|
-
const matches = searchKeys.some((key) => {
|
|
2568
|
-
const val = row[key];
|
|
2569
|
-
return val != null && String(val).toLowerCase().includes(q);
|
|
2570
|
-
});
|
|
2571
|
-
if (!matches) return false;
|
|
2572
|
-
}
|
|
2573
|
-
for (const f of filters ?? []) {
|
|
2574
|
-
const value = filterValues[f.key];
|
|
2575
|
-
const def = f.defaultValue ?? f.options[0]?.value ?? "";
|
|
2576
|
-
if (value !== void 0 && value !== def) {
|
|
2577
|
-
if (f.accessor(row) !== value) return false;
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
return true;
|
|
2581
|
-
});
|
|
2582
|
-
}, [data, search, searchKeys, filters, filterValues]);
|
|
2583
|
-
const showFilterBar = Boolean(searchKeys?.length) || Boolean(filters?.length);
|
|
2584
|
-
const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveFilters ? "no-data" : filtered.length === 0 ? "no-results" : "rows";
|
|
2563
|
+
};
|
|
2564
|
+
const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveQuery ? "no-data" : data.length === 0 && hasActiveQuery ? "no-results" : "rows";
|
|
2585
2565
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page", className: cn("space-y-6", className), children: [
|
|
2586
2566
|
/* @__PURE__ */ jsxRuntime.jsx(PageHeader, { title, description, bordered, actions }),
|
|
2587
2567
|
showFilterBar ? /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page-filter-bar", className: "flex flex-wrap items-center gap-3", children: [
|
|
2588
|
-
|
|
2568
|
+
showSearch ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2589
2569
|
Input,
|
|
2590
2570
|
{
|
|
2591
2571
|
type: "search",
|
|
2592
2572
|
placeholder: labels.searchPlaceholder,
|
|
2593
2573
|
"aria-label": labels.searchAriaLabel || labels.searchPlaceholder,
|
|
2594
|
-
value:
|
|
2595
|
-
onChange: (e) =>
|
|
2574
|
+
value: searchValue ?? "",
|
|
2575
|
+
onChange: (e) => onSearchChange?.(e.target.value),
|
|
2596
2576
|
leadingIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, {}),
|
|
2597
2577
|
wrapperClassName: "sm:max-w-xs",
|
|
2598
2578
|
disabled: isLoading
|
|
@@ -2601,16 +2581,16 @@ function ListPage({
|
|
|
2601
2581
|
filters?.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2602
2582
|
Select,
|
|
2603
2583
|
{
|
|
2604
|
-
"aria-label": f.
|
|
2605
|
-
value: filterValues[f.key],
|
|
2606
|
-
onValueChange: (v) =>
|
|
2584
|
+
"aria-label": typeof f.label === "string" ? f.label : f.key,
|
|
2585
|
+
value: filterValues?.[f.key] ?? f.options[0]?.value ?? "",
|
|
2586
|
+
onValueChange: (v) => onFilterChange?.(f.key, v),
|
|
2607
2587
|
options: f.options,
|
|
2608
2588
|
className: FILTER_WIDTH_CLASS[f.width ?? "default"],
|
|
2609
2589
|
disabled: isLoading
|
|
2610
2590
|
},
|
|
2611
2591
|
f.key
|
|
2612
2592
|
)),
|
|
2613
|
-
|
|
2593
|
+
hasActiveQuery && !isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", onClick: reset, children: [
|
|
2614
2594
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, {}),
|
|
2615
2595
|
labels.reset
|
|
2616
2596
|
] }) : null
|
|
@@ -2619,7 +2599,7 @@ function ListPage({
|
|
|
2619
2599
|
Table,
|
|
2620
2600
|
{
|
|
2621
2601
|
"aria-label": typeof title === "string" ? title : void 0,
|
|
2622
|
-
data
|
|
2602
|
+
data,
|
|
2623
2603
|
columns,
|
|
2624
2604
|
getRowId,
|
|
2625
2605
|
enableRowSelection,
|
|
@@ -2627,10 +2607,10 @@ function ListPage({
|
|
|
2627
2607
|
loading: isLoading,
|
|
2628
2608
|
loadingRowCount,
|
|
2629
2609
|
pagination,
|
|
2630
|
-
defaultPagination,
|
|
2631
2610
|
onPaginationChange,
|
|
2632
2611
|
totalCount,
|
|
2633
|
-
pageSizeOptions
|
|
2612
|
+
pageSizeOptions,
|
|
2613
|
+
labels
|
|
2634
2614
|
}
|
|
2635
2615
|
) : tableMode === "no-data" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2636
2616
|
"div",
|