@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 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(PageHeader, { title, description, back, bordered }),
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
- actions !== null && actions !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1783
+ /* @__PURE__ */ jsxRuntime.jsxs(
1755
1784
  "div",
1756
1785
  {
1757
1786
  "data-slot": "form-page-actions",
1758
1787
  className: cn(formPageActionsBarClass, actionsClassName),
1759
- children: actions
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
- ) : null
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: "Rows per page" }),
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
- " of ",
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": "Previous page",
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": "Next page",
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 isSelectionControlled = selectedRowIdsProp !== void 0;
2176
- const selected = isSelectionControlled ? selectedRowIdsProp : internalSelected;
2208
+ const isControlled = selectedRowIdsProp !== void 0;
2209
+ const selected = isControlled ? selectedRowIdsProp : internalSelected;
2177
2210
  const setSelected = react.useCallback(
2178
2211
  (next) => {
2179
- if (!isSelectionControlled) setInternalSelected(next);
2212
+ if (!isControlled) setInternalSelected(next);
2180
2213
  onSelectedRowIdsChange?.(next);
2181
2214
  },
2182
- [isSelectionControlled, onSelectedRowIdsChange]
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 { sort, setSort, pagination, setPagination, selected, setSelected, isServerSide } = useTableState(props);
2222
- const sortedRows = react.useMemo(() => {
2223
- if (isServerSide || sort.columnId === null) return data;
2224
- const col = columns.find((c) => c.id === sort.columnId);
2225
- if (!col) return data;
2226
- const get = resolveSortGetter(col);
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 pagedRows.map((row, index) => ({ row, index })).filter(({ row }) => isRowSelectable ? isRowSelectable(row) : true).map(({ row, index }) => getRowId(row, index));
2246
- }, [pagedRows, enableRowSelection, isRowSelectable, getRowId]);
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
- setSort(nextSort(sort, columnId));
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 > pagination.pageSize;
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 ?? pagination.pageSize;
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 = sort.columnId === column.id;
2330
- const ariaSort = isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none";
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, sort),
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 ? sort.direction : null
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
- ) : pagedRows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
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
- ) }) : pagedRows.map((row, rowIndex) => {
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: pagination.pageIndex,
2435
- pageSize: pagination.pageSize,
2457
+ pageIndex,
2458
+ pageSize,
2436
2459
  pageCount,
2437
2460
  totalRowCount,
2438
2461
  pageSizeOptions,
2439
- onChange: setPagination
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
- searchKeys,
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 initialFilterValues = react.useMemo(() => {
2539
- const init = {};
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
- init[f.key] = f.defaultValue ?? f.options[0]?.value ?? "";
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 init;
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
- setSearch("");
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 current = filterValues[f.key];
2558
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2559
- if (current !== def) return true;
2560
+ const def = f.options[0]?.value ?? "";
2561
+ onFilterChange?.(f.key, def);
2560
2562
  }
2561
- return false;
2562
- }, [search, filters, filterValues]);
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
- searchKeys?.length ? /* @__PURE__ */ jsxRuntime.jsx(
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: search,
2595
- onChange: (e) => setSearch(e.target.value),
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.ariaLabel,
2605
- value: filterValues[f.key],
2606
- onValueChange: (v) => setFilter(f.key, 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
- hasActiveFilters && !isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", onClick: reset, children: [
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: filtered,
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",