@dimaan/ui 0.0.19 → 0.0.21

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