@dimaan/ui 0.0.19 → 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.js CHANGED
@@ -5,7 +5,7 @@ import { twMerge } from 'tailwind-merge';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { Loader2, Check, Minus, Calendar, X, ChevronLeft, ChevronRight, ChevronDown, ChevronUp, ArrowLeft, Menu, FileQuestion, ChevronsUpDown, Search, RefreshCw, Inbox, SearchX } from 'lucide-react';
7
7
  import { DirectionProvider } from '@radix-ui/react-direction';
8
- import { Link, useLocation, useResolvedPath } from 'react-router-dom';
8
+ import { Link, useLocation, useResolvedPath, useNavigate } from 'react-router-dom';
9
9
  import * as RadixPopover from '@radix-ui/react-popover';
10
10
  import { DayPicker } from 'react-day-picker';
11
11
  import * as RadixDialog from '@radix-ui/react-dialog';
@@ -1696,12 +1696,26 @@ var formPageBodyClass = "flex-1";
1696
1696
  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";
1697
1697
  var formPageSkeletonRowClass = "h-10 w-full animate-pulse rounded-md bg-muted";
1698
1698
  var DEFAULT_SKELETON_ROW_COUNT2 = 6;
1699
+ var DEFAULT_LABELS_LTR = {
1700
+ back: "Back",
1701
+ cancel: "Cancel",
1702
+ save: "Save",
1703
+ saving: "Saving\u2026"
1704
+ };
1705
+ var DEFAULT_LABELS_RTL = {
1706
+ back: "\u0631\u062C\u0648\u0639",
1707
+ cancel: "\u0625\u0644\u063A\u0627\u0621",
1708
+ save: "\u062D\u0641\u0638",
1709
+ saving: "\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026"
1710
+ };
1699
1711
  function FormPage({
1700
1712
  title,
1701
1713
  description,
1702
- back,
1703
1714
  bordered = true,
1704
1715
  onSubmit,
1716
+ onCancel,
1717
+ isSubmitting,
1718
+ labels: labelsProp,
1705
1719
  isLoading = false,
1706
1720
  loadingRowCount = DEFAULT_SKELETON_ROW_COUNT2,
1707
1721
  actions,
@@ -1711,8 +1725,23 @@ function FormPage({
1711
1725
  bodyClassName,
1712
1726
  actionsClassName
1713
1727
  }) {
1728
+ const navigate = useNavigate();
1729
+ const dir = useDirection();
1730
+ const formContext = useFormContext();
1731
+ const submitting = isSubmitting ?? formContext?.formState?.isSubmitting ?? false;
1732
+ const defaults = dir === "rtl" ? DEFAULT_LABELS_RTL : DEFAULT_LABELS_LTR;
1733
+ const labels = { ...defaults, ...labelsProp };
1734
+ const goBack = () => navigate(-1);
1714
1735
  return /* @__PURE__ */ jsxs("div", { "data-slot": "form-page", className: cn(formPageBaseClass, className), children: [
1715
- /* @__PURE__ */ jsx(PageHeader, { title, description, back, bordered }),
1736
+ /* @__PURE__ */ jsx(
1737
+ PageHeader,
1738
+ {
1739
+ title,
1740
+ description,
1741
+ back: { label: labels.back, onClick: goBack },
1742
+ bordered
1743
+ }
1744
+ ),
1716
1745
  /* @__PURE__ */ jsxs(
1717
1746
  "form",
1718
1747
  {
@@ -1723,14 +1752,27 @@ function FormPage({
1723
1752
  className: cn("flex flex-1 flex-col gap-6", formClassName),
1724
1753
  children: [
1725
1754
  /* @__PURE__ */ jsx("div", { "data-slot": "form-page-body", className: cn(formPageBodyClass, bodyClassName), children: isLoading ? /* @__PURE__ */ jsx(FormPageSkeleton, { rowCount: loadingRowCount }) : children }),
1726
- actions !== null && actions !== void 0 ? /* @__PURE__ */ jsx(
1755
+ /* @__PURE__ */ jsxs(
1727
1756
  "div",
1728
1757
  {
1729
1758
  "data-slot": "form-page-actions",
1730
1759
  className: cn(formPageActionsBarClass, actionsClassName),
1731
- children: actions
1760
+ children: [
1761
+ actions,
1762
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onCancel ?? goBack, children: labels.cancel }),
1763
+ /* @__PURE__ */ jsx(
1764
+ Button,
1765
+ {
1766
+ type: "submit",
1767
+ loading: submitting,
1768
+ loadingText: labels.saving,
1769
+ disabled: isLoading,
1770
+ children: labels.save
1771
+ }
1772
+ )
1773
+ ]
1732
1774
  }
1733
- ) : null
1775
+ )
1734
1776
  ]
1735
1777
  }
1736
1778
  )
@@ -1981,15 +2023,35 @@ var SelectItem = forwardRef(function SelectItem2({ className, children, ...props
1981
2023
  /* @__PURE__ */ jsx(RadixSelect.ItemText, { children })
1982
2024
  ] });
1983
2025
  });
2026
+ var EN_LABELS = {
2027
+ rowsPerPage: "Rows per page",
2028
+ pageRangeOf: "of",
2029
+ previousPage: "Previous page",
2030
+ nextPage: "Next page"
2031
+ };
2032
+ var AR_LABELS = {
2033
+ rowsPerPage: "\u0635\u0641\u0648\u0641 \u0644\u0643\u0644 \u0635\u0641\u062D\u0629",
2034
+ pageRangeOf: "\u0645\u0646",
2035
+ previousPage: "\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
2036
+ nextPage: "\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629"
2037
+ };
1984
2038
  function Pagination({
1985
2039
  pageIndex,
1986
2040
  pageSize,
1987
2041
  pageCount,
1988
2042
  totalRowCount,
1989
2043
  pageSizeOptions,
1990
- onChange
2044
+ onChange,
2045
+ labels: labelsProp
1991
2046
  }) {
1992
2047
  const dir = useDirection();
2048
+ const localeDefaults = dir === "rtl" ? AR_LABELS : EN_LABELS;
2049
+ const labels = {
2050
+ rowsPerPage: labelsProp?.rowsPerPage ?? localeDefaults.rowsPerPage,
2051
+ pageRangeOf: labelsProp?.pageRangeOf ?? localeDefaults.pageRangeOf,
2052
+ previousPage: labelsProp?.previousPage ?? localeDefaults.previousPage,
2053
+ nextPage: labelsProp?.nextPage ?? localeDefaults.nextPage
2054
+ };
1993
2055
  const isRtl = dir === "rtl";
1994
2056
  const isFirst = pageIndex <= 0;
1995
2057
  const isLast = pageIndex >= pageCount - 1;
@@ -2003,7 +2065,7 @@ function Pagination({
2003
2065
  const end = Math.min(totalRowCount, (pageIndex + 1) * pageSize);
2004
2066
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 text-sm text-muted-foreground", children: [
2005
2067
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
2006
- /* @__PURE__ */ jsx("span", { children: "Rows per page" }),
2068
+ /* @__PURE__ */ jsx("span", { children: labels.rowsPerPage }),
2007
2069
  /* @__PURE__ */ jsx(
2008
2070
  "select",
2009
2071
  {
@@ -2022,7 +2084,9 @@ function Pagination({
2022
2084
  start,
2023
2085
  "\u2013",
2024
2086
  end,
2025
- " of ",
2087
+ " ",
2088
+ labels.pageRangeOf,
2089
+ " ",
2026
2090
  totalRowCount
2027
2091
  ] }),
2028
2092
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
@@ -2034,7 +2098,7 @@ function Pagination({
2034
2098
  size: "sm",
2035
2099
  disabled: isFirst,
2036
2100
  onClick: goPrev,
2037
- "aria-label": "Previous page",
2101
+ "aria-label": labels.previousPage,
2038
2102
  children: isRtl ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
2039
2103
  }
2040
2104
  ),
@@ -2051,7 +2115,7 @@ function Pagination({
2051
2115
  size: "sm",
2052
2116
  disabled: isLast,
2053
2117
  onClick: goNext,
2054
- "aria-label": "Next page",
2118
+ "aria-label": labels.nextPage,
2055
2119
  children: isRtl ? /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
2056
2120
  }
2057
2121
  )
@@ -2104,66 +2168,28 @@ var alignClass = {
2104
2168
  end: "text-end"
2105
2169
  };
2106
2170
  var EMPTY_SELECTION = /* @__PURE__ */ new Set();
2107
- var NO_SORT = { columnId: null, direction: "asc" };
2108
2171
  function useTableState(props) {
2109
2172
  const {
2110
- defaultSort,
2111
- sort: sortProp,
2112
- onSortChange,
2113
- defaultPagination,
2114
- pagination: paginationProp,
2115
- onPaginationChange,
2116
- pageSizeOptions,
2117
2173
  defaultSelectedRowIds,
2118
2174
  selectedRowIds: selectedRowIdsProp,
2119
- onSelectedRowIdsChange,
2120
- totalCount
2175
+ onSelectedRowIdsChange
2121
2176
  } = props;
2122
- const [internalSort, setInternalSort] = useState(defaultSort ?? NO_SORT);
2123
- const isSortControlled = sortProp !== void 0;
2124
- const sort = isSortControlled ? sortProp : internalSort;
2125
- const setSort = useCallback(
2126
- (next) => {
2127
- if (!isSortControlled) setInternalSort(next);
2128
- onSortChange?.(next);
2129
- },
2130
- [isSortControlled, onSortChange]
2131
- );
2132
- const [internalPagination, setInternalPagination] = useState(
2133
- defaultPagination ?? { pageIndex: 0, pageSize: pageSizeOptions?.[0] ?? 10 }
2134
- );
2135
- const isPaginationControlled = paginationProp !== void 0;
2136
- const pagination = isPaginationControlled ? paginationProp : internalPagination;
2137
- const setPagination = useCallback(
2138
- (next) => {
2139
- if (!isPaginationControlled) setInternalPagination(next);
2140
- onPaginationChange?.(next);
2141
- },
2142
- [isPaginationControlled, onPaginationChange]
2143
- );
2144
2177
  const [internalSelected, setInternalSelected] = useState(
2145
2178
  defaultSelectedRowIds ?? EMPTY_SELECTION
2146
2179
  );
2147
- const isSelectionControlled = selectedRowIdsProp !== void 0;
2148
- const selected = isSelectionControlled ? selectedRowIdsProp : internalSelected;
2180
+ const isControlled = selectedRowIdsProp !== void 0;
2181
+ const selected = isControlled ? selectedRowIdsProp : internalSelected;
2149
2182
  const setSelected = useCallback(
2150
2183
  (next) => {
2151
- if (!isSelectionControlled) setInternalSelected(next);
2184
+ if (!isControlled) setInternalSelected(next);
2152
2185
  onSelectedRowIdsChange?.(next);
2153
2186
  },
2154
- [isSelectionControlled, onSelectedRowIdsChange]
2187
+ [isControlled, onSelectedRowIdsChange]
2155
2188
  );
2156
- return {
2157
- sort,
2158
- setSort,
2159
- pagination,
2160
- setPagination,
2161
- selected,
2162
- setSelected,
2163
- isServerSide: totalCount !== void 0
2164
- };
2189
+ return { selected, setSelected };
2165
2190
  }
2166
2191
  var DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50];
2192
+ var DEFAULT_PAGE_SIZE = 10;
2167
2193
  function defaultGetRowId(row, index) {
2168
2194
  const rowId = row.id;
2169
2195
  return rowId === void 0 || rowId === null ? String(index) : String(rowId);
@@ -2190,36 +2216,26 @@ function Table(props) {
2190
2216
  tableRef,
2191
2217
  pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
2192
2218
  showPagination,
2193
- caption
2219
+ caption,
2220
+ sort,
2221
+ onSortChange,
2222
+ pagination,
2223
+ onPaginationChange,
2224
+ totalCount,
2225
+ labels
2194
2226
  } = props;
2195
2227
  const ariaLabel = props["aria-label"];
2196
2228
  const ariaLabelledBy = props["aria-labelledby"];
2197
- const { sort, setSort, pagination, setPagination, selected, setSelected, isServerSide } = useTableState(props);
2198
- const sortedRows = useMemo(() => {
2199
- if (isServerSide || sort.columnId === null) return data;
2200
- const col = columns.find((c) => c.id === sort.columnId);
2201
- if (!col) return data;
2202
- const get = resolveSortGetter(col);
2203
- if (!get) return data;
2204
- const tagged = data.map((row, index) => ({ row, index }));
2205
- tagged.sort((a, b) => {
2206
- const cmp = compareValues(get(a.row), get(b.row));
2207
- if (cmp !== 0) return sort.direction === "asc" ? cmp : -cmp;
2208
- return a.index - b.index;
2209
- });
2210
- return tagged.map((entry) => entry.row);
2211
- }, [data, columns, sort, isServerSide]);
2212
- const pagedRows = useMemo(() => {
2213
- if (isServerSide) return sortedRows;
2214
- const start = pagination.pageIndex * pagination.pageSize;
2215
- return sortedRows.slice(start, start + pagination.pageSize);
2216
- }, [sortedRows, pagination, isServerSide]);
2217
- const totalRowCount = isServerSide ? props.totalCount ?? 0 : data.length;
2218
- const pageCount = Math.max(1, Math.ceil(totalRowCount / pagination.pageSize));
2229
+ const { selected, setSelected } = useTableState(props);
2230
+ const effectiveSort = sort ?? { columnId: null, direction: "asc" };
2231
+ const pageSize = pagination?.pageSize ?? pageSizeOptions[0] ?? DEFAULT_PAGE_SIZE;
2232
+ const pageIndex = pagination?.pageIndex ?? 0;
2233
+ const totalRowCount = totalCount ?? data.length;
2234
+ const pageCount = Math.max(1, Math.ceil(totalRowCount / pageSize));
2219
2235
  const selectableRowIds = useMemo(() => {
2220
2236
  if (!enableRowSelection) return [];
2221
- return pagedRows.map((row, index) => ({ row, index })).filter(({ row }) => isRowSelectable ? isRowSelectable(row) : true).map(({ row, index }) => getRowId(row, index));
2222
- }, [pagedRows, enableRowSelection, isRowSelectable, getRowId]);
2237
+ return data.map((row, index) => ({ row, index })).filter(({ row }) => isRowSelectable ? isRowSelectable(row) : true).map(({ row, index }) => getRowId(row, index));
2238
+ }, [data, enableRowSelection, isRowSelectable, getRowId]);
2223
2239
  const selectedOnPageCount = selectableRowIds.reduce(
2224
2240
  (acc, id) => selected.has(id) ? acc + 1 : acc,
2225
2241
  0
@@ -2247,13 +2263,16 @@ function Table(props) {
2247
2263
  };
2248
2264
  const clearSelection = () => setSelected(/* @__PURE__ */ new Set());
2249
2265
  const handleSortClick = (columnId) => {
2250
- setSort(nextSort(sort, columnId));
2266
+ if (!onSortChange) return;
2267
+ onSortChange(nextSort(effectiveSort, columnId));
2251
2268
  };
2269
+ const handlePaginationChange = onPaginationChange ?? (() => {
2270
+ });
2252
2271
  const totalColumnCount = columns.length + (enableRowSelection ? 1 : 0);
2253
- const paginationVisible = showPagination ?? totalRowCount > pagination.pageSize;
2272
+ const paginationVisible = Boolean(pagination) && (showPagination ?? totalRowCount > pageSize);
2254
2273
  const sizeClasses = tableSizeClass[size];
2255
2274
  const showToolbar = enableRowSelection && bulkActions !== void 0 && selected.size > 0;
2256
- const skeletonCount = loadingRowCount ?? pagination.pageSize;
2275
+ const skeletonCount = loadingRowCount ?? pageSize;
2257
2276
  return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full flex-col gap-3", className), children: [
2258
2277
  showToolbar && /* @__PURE__ */ jsx(
2259
2278
  Toolbar,
@@ -2302,8 +2321,8 @@ function Table(props) {
2302
2321
  }
2303
2322
  ) }) : null,
2304
2323
  columns.map((column) => {
2305
- const isSorted = sort.columnId === column.id;
2306
- const ariaSort = isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none";
2324
+ const isSorted = effectiveSort.columnId === column.id;
2325
+ const ariaSort = isSorted ? effectiveSort.direction === "asc" ? "ascending" : "descending" : "none";
2307
2326
  return /* @__PURE__ */ jsx(
2308
2327
  "th",
2309
2328
  {
@@ -2320,14 +2339,14 @@ function Table(props) {
2320
2339
  type: "button",
2321
2340
  onClick: () => handleSortClick(column.id),
2322
2341
  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",
2323
- "aria-label": sortAriaLabel(column, sort),
2342
+ "aria-label": sortAriaLabel(column, effectiveSort),
2324
2343
  children: [
2325
2344
  /* @__PURE__ */ jsx("span", { children: renderHeader(column.header) }),
2326
2345
  /* @__PURE__ */ jsx(
2327
2346
  SortIndicator,
2328
2347
  {
2329
2348
  active: isSorted,
2330
- direction: isSorted ? sort.direction : null
2349
+ direction: isSorted ? effectiveSort.direction : null
2331
2350
  }
2332
2351
  )
2333
2352
  ]
@@ -2347,14 +2366,14 @@ function Table(props) {
2347
2366
  columnCount: totalColumnCount,
2348
2367
  cellClassName: sizeClasses.cell
2349
2368
  }
2350
- ) : pagedRows.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
2369
+ ) : data.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
2351
2370
  "td",
2352
2371
  {
2353
2372
  colSpan: totalColumnCount,
2354
2373
  className: cn(sizeClasses.cell, "py-10 text-center text-muted-foreground"),
2355
2374
  children: emptyState ?? "No data"
2356
2375
  }
2357
- ) }) : pagedRows.map((row, rowIndex) => {
2376
+ ) }) : data.map((row, rowIndex) => {
2358
2377
  const id = getRowId(row, rowIndex);
2359
2378
  const isSelected = selected.has(id);
2360
2379
  const rowSelectable = isRowSelectable ? isRowSelectable(row) : true;
@@ -2407,12 +2426,13 @@ function Table(props) {
2407
2426
  paginationVisible ? /* @__PURE__ */ jsx(
2408
2427
  Pagination,
2409
2428
  {
2410
- pageIndex: pagination.pageIndex,
2411
- pageSize: pagination.pageSize,
2429
+ pageIndex,
2430
+ pageSize,
2412
2431
  pageCount,
2413
2432
  totalRowCount,
2414
2433
  pageSizeOptions,
2415
- onChange: setPagination
2434
+ onChange: handlePaginationChange,
2435
+ labels
2416
2436
  }
2417
2437
  ) : null
2418
2438
  ] });
@@ -2428,24 +2448,6 @@ function renderCell(column, row, rowIndex) {
2428
2448
  }
2429
2449
  return null;
2430
2450
  }
2431
- function resolveSortGetter(column) {
2432
- if (column.sortAccessor) return column.sortAccessor;
2433
- if (column.accessor !== void 0) {
2434
- const key = column.accessor;
2435
- return (row) => row[key];
2436
- }
2437
- return null;
2438
- }
2439
- function compareValues(a, b) {
2440
- if (a === b) return 0;
2441
- if (a === null || a === void 0) return 1;
2442
- if (b === null || b === void 0) return -1;
2443
- if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
2444
- if (typeof a === "number" && typeof b === "number") return a - b;
2445
- if (typeof a === "bigint" && typeof b === "bigint") return a < b ? -1 : 1;
2446
- if (typeof a === "boolean" && typeof b === "boolean") return a === b ? 0 : a ? 1 : -1;
2447
- return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
2448
- }
2449
2451
  function nextSort(current, columnId) {
2450
2452
  if (current.columnId !== columnId) return { columnId, direction: "asc" };
2451
2453
  if (current.direction === "asc") return { columnId, direction: "desc" };
@@ -2496,16 +2498,14 @@ function ListPage({
2496
2498
  getRowId,
2497
2499
  isLoading = false,
2498
2500
  loadingRowCount,
2499
- searchKeys,
2500
- searchValue: searchValueProp,
2501
+ searchValue,
2501
2502
  onSearchChange,
2502
2503
  filters,
2503
- filterValues: filterValuesProp,
2504
+ filterValues,
2504
2505
  onFilterChange,
2505
2506
  enableRowSelection,
2506
2507
  bulkActions,
2507
2508
  pagination,
2508
- defaultPagination,
2509
2509
  onPaginationChange,
2510
2510
  totalCount,
2511
2511
  pageSizeOptions,
@@ -2515,82 +2515,36 @@ function ListPage({
2515
2515
  className
2516
2516
  }) {
2517
2517
  const labels = { ...DEFAULT_LABELS2, ...labelsProp };
2518
- const initialFilterValues = useMemo(() => {
2519
- const init = {};
2518
+ const showSearch = onSearchChange !== void 0;
2519
+ const showFilterBar = showSearch || Boolean(filters?.length);
2520
+ const hasActiveQuery = useMemo(() => {
2521
+ if ((searchValue ?? "").trim() !== "") return true;
2520
2522
  for (const f of filters ?? []) {
2521
- init[f.key] = f.defaultValue ?? f.options[0]?.value ?? "";
2523
+ const current = filterValues?.[f.key];
2524
+ const def = f.options[0]?.value ?? "";
2525
+ if (current !== void 0 && current !== def) return true;
2522
2526
  }
2523
- return init;
2524
- }, [filters]);
2525
- const isSearchControlled = searchValueProp !== void 0;
2526
- const isFiltersControlled = filterValuesProp !== void 0;
2527
- const [internalSearch, setInternalSearch] = useState("");
2528
- const [internalFilterValues, setInternalFilterValues] = useState(initialFilterValues);
2529
- const search = isSearchControlled ? searchValueProp : internalSearch;
2530
- const filterValues = isFiltersControlled ? filterValuesProp : internalFilterValues;
2531
- const setSearch = (next) => {
2532
- if (!isSearchControlled) setInternalSearch(next);
2533
- onSearchChange?.(next);
2534
- };
2535
- const setFilter = (key, value) => {
2536
- if (!isFiltersControlled) {
2537
- setInternalFilterValues((prev) => ({ ...prev, [key]: value }));
2538
- }
2539
- onFilterChange?.(key, value);
2540
- };
2527
+ return false;
2528
+ }, [searchValue, filters, filterValues]);
2541
2529
  const reset = () => {
2542
- if (!isSearchControlled) setInternalSearch("");
2543
2530
  onSearchChange?.("");
2544
- if (!isFiltersControlled) setInternalFilterValues(initialFilterValues);
2545
2531
  for (const f of filters ?? []) {
2546
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2532
+ const def = f.options[0]?.value ?? "";
2547
2533
  onFilterChange?.(f.key, def);
2548
2534
  }
2549
2535
  };
2550
- const hasActiveFilters = useMemo(() => {
2551
- if (search.trim() !== "") return true;
2552
- for (const f of filters ?? []) {
2553
- const current = filterValues[f.key];
2554
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2555
- if (current !== def) return true;
2556
- }
2557
- return false;
2558
- }, [search, filters, filterValues]);
2559
- const filtered = useMemo(() => {
2560
- return data.filter((row) => {
2561
- if (!isSearchControlled && search.trim() && searchKeys && searchKeys.length > 0) {
2562
- const q = search.trim().toLowerCase();
2563
- const matches = searchKeys.some((key) => {
2564
- const val = row[key];
2565
- return val != null && String(val).toLowerCase().includes(q);
2566
- });
2567
- if (!matches) return false;
2568
- }
2569
- if (!isFiltersControlled) {
2570
- for (const f of filters ?? []) {
2571
- const value = filterValues[f.key];
2572
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2573
- if (value !== void 0 && value !== def) {
2574
- if (f.accessor(row) !== value) return false;
2575
- }
2576
- }
2577
- }
2578
- return true;
2579
- });
2580
- }, [data, search, searchKeys, filters, filterValues, isSearchControlled, isFiltersControlled]);
2581
- const showFilterBar = Boolean(searchKeys?.length) || Boolean(filters?.length);
2582
- const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveFilters ? "no-data" : filtered.length === 0 ? "no-results" : "rows";
2536
+ const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveQuery ? "no-data" : data.length === 0 && hasActiveQuery ? "no-results" : "rows";
2583
2537
  return /* @__PURE__ */ jsxs("div", { "data-slot": "list-page", className: cn("space-y-6", className), children: [
2584
2538
  /* @__PURE__ */ jsx(PageHeader, { title, description, bordered, actions }),
2585
2539
  showFilterBar ? /* @__PURE__ */ jsxs("div", { "data-slot": "list-page-filter-bar", className: "flex flex-wrap items-center gap-3", children: [
2586
- searchKeys?.length ? /* @__PURE__ */ jsx(
2540
+ showSearch ? /* @__PURE__ */ jsx(
2587
2541
  Input,
2588
2542
  {
2589
2543
  type: "search",
2590
2544
  placeholder: labels.searchPlaceholder,
2591
2545
  "aria-label": labels.searchAriaLabel || labels.searchPlaceholder,
2592
- value: search,
2593
- onChange: (e) => setSearch(e.target.value),
2546
+ value: searchValue ?? "",
2547
+ onChange: (e) => onSearchChange?.(e.target.value),
2594
2548
  leadingIcon: /* @__PURE__ */ jsx(Search, {}),
2595
2549
  wrapperClassName: "sm:max-w-xs",
2596
2550
  disabled: isLoading
@@ -2599,16 +2553,16 @@ function ListPage({
2599
2553
  filters?.map((f) => /* @__PURE__ */ jsx(
2600
2554
  Select,
2601
2555
  {
2602
- "aria-label": f.ariaLabel,
2603
- value: filterValues[f.key],
2604
- onValueChange: (v) => setFilter(f.key, v),
2556
+ "aria-label": typeof f.label === "string" ? f.label : f.key,
2557
+ value: filterValues?.[f.key] ?? f.options[0]?.value ?? "",
2558
+ onValueChange: (v) => onFilterChange?.(f.key, v),
2605
2559
  options: f.options,
2606
2560
  className: FILTER_WIDTH_CLASS[f.width ?? "default"],
2607
2561
  disabled: isLoading
2608
2562
  },
2609
2563
  f.key
2610
2564
  )),
2611
- hasActiveFilters && !isLoading ? /* @__PURE__ */ jsxs(Button, { variant: "ghost", onClick: reset, children: [
2565
+ hasActiveQuery && !isLoading ? /* @__PURE__ */ jsxs(Button, { variant: "ghost", onClick: reset, children: [
2612
2566
  /* @__PURE__ */ jsx(RefreshCw, {}),
2613
2567
  labels.reset
2614
2568
  ] }) : null
@@ -2617,7 +2571,7 @@ function ListPage({
2617
2571
  Table,
2618
2572
  {
2619
2573
  "aria-label": typeof title === "string" ? title : void 0,
2620
- data: filtered,
2574
+ data,
2621
2575
  columns,
2622
2576
  getRowId,
2623
2577
  enableRowSelection,
@@ -2625,10 +2579,10 @@ function ListPage({
2625
2579
  loading: isLoading,
2626
2580
  loadingRowCount,
2627
2581
  pagination,
2628
- defaultPagination,
2629
2582
  onPaginationChange,
2630
2583
  totalCount,
2631
- pageSizeOptions
2584
+ pageSizeOptions,
2585
+ labels
2632
2586
  }
2633
2587
  ) : tableMode === "no-data" ? /* @__PURE__ */ jsx(
2634
2588
  "div",