@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.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,66 +2196,28 @@ 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;
2195
2221
  function defaultGetRowId(row, index) {
2196
2222
  const rowId = row.id;
2197
2223
  return rowId === void 0 || rowId === null ? String(index) : String(rowId);
@@ -2218,36 +2244,26 @@ function Table(props) {
2218
2244
  tableRef,
2219
2245
  pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
2220
2246
  showPagination,
2221
- caption
2247
+ caption,
2248
+ sort,
2249
+ onSortChange,
2250
+ pagination,
2251
+ onPaginationChange,
2252
+ totalCount,
2253
+ labels
2222
2254
  } = props;
2223
2255
  const ariaLabel = props["aria-label"];
2224
2256
  const ariaLabelledBy = props["aria-labelledby"];
2225
- const { sort, setSort, pagination, setPagination, selected, setSelected, isServerSide } = useTableState(props);
2226
- const sortedRows = react.useMemo(() => {
2227
- if (isServerSide || sort.columnId === null) return data;
2228
- const col = columns.find((c) => c.id === sort.columnId);
2229
- if (!col) return data;
2230
- const get = resolveSortGetter(col);
2231
- if (!get) return data;
2232
- const tagged = data.map((row, index) => ({ row, index }));
2233
- tagged.sort((a, b) => {
2234
- const cmp = compareValues(get(a.row), get(b.row));
2235
- if (cmp !== 0) return sort.direction === "asc" ? cmp : -cmp;
2236
- return a.index - b.index;
2237
- });
2238
- return tagged.map((entry) => entry.row);
2239
- }, [data, columns, sort, isServerSide]);
2240
- const pagedRows = react.useMemo(() => {
2241
- if (isServerSide) return sortedRows;
2242
- const start = pagination.pageIndex * pagination.pageSize;
2243
- return sortedRows.slice(start, start + pagination.pageSize);
2244
- }, [sortedRows, pagination, isServerSide]);
2245
- const totalRowCount = isServerSide ? props.totalCount ?? 0 : data.length;
2246
- 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));
2247
2263
  const selectableRowIds = react.useMemo(() => {
2248
2264
  if (!enableRowSelection) return [];
2249
- return pagedRows.map((row, index) => ({ row, index })).filter(({ row }) => isRowSelectable ? isRowSelectable(row) : true).map(({ row, index }) => getRowId(row, index));
2250
- }, [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]);
2251
2267
  const selectedOnPageCount = selectableRowIds.reduce(
2252
2268
  (acc, id) => selected.has(id) ? acc + 1 : acc,
2253
2269
  0
@@ -2275,13 +2291,16 @@ function Table(props) {
2275
2291
  };
2276
2292
  const clearSelection = () => setSelected(/* @__PURE__ */ new Set());
2277
2293
  const handleSortClick = (columnId) => {
2278
- setSort(nextSort(sort, columnId));
2294
+ if (!onSortChange) return;
2295
+ onSortChange(nextSort(effectiveSort, columnId));
2279
2296
  };
2297
+ const handlePaginationChange = onPaginationChange ?? (() => {
2298
+ });
2280
2299
  const totalColumnCount = columns.length + (enableRowSelection ? 1 : 0);
2281
- const paginationVisible = showPagination ?? totalRowCount > pagination.pageSize;
2300
+ const paginationVisible = Boolean(pagination) && (showPagination ?? totalRowCount > pageSize);
2282
2301
  const sizeClasses = tableSizeClass[size];
2283
2302
  const showToolbar = enableRowSelection && bulkActions !== void 0 && selected.size > 0;
2284
- const skeletonCount = loadingRowCount ?? pagination.pageSize;
2303
+ const skeletonCount = loadingRowCount ?? pageSize;
2285
2304
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-3", className), children: [
2286
2305
  showToolbar && /* @__PURE__ */ jsxRuntime.jsx(
2287
2306
  Toolbar,
@@ -2330,8 +2349,8 @@ function Table(props) {
2330
2349
  }
2331
2350
  ) }) : null,
2332
2351
  columns.map((column) => {
2333
- const isSorted = sort.columnId === column.id;
2334
- 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";
2335
2354
  return /* @__PURE__ */ jsxRuntime.jsx(
2336
2355
  "th",
2337
2356
  {
@@ -2348,14 +2367,14 @@ function Table(props) {
2348
2367
  type: "button",
2349
2368
  onClick: () => handleSortClick(column.id),
2350
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",
2351
- "aria-label": sortAriaLabel(column, sort),
2370
+ "aria-label": sortAriaLabel(column, effectiveSort),
2352
2371
  children: [
2353
2372
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: renderHeader(column.header) }),
2354
2373
  /* @__PURE__ */ jsxRuntime.jsx(
2355
2374
  SortIndicator,
2356
2375
  {
2357
2376
  active: isSorted,
2358
- direction: isSorted ? sort.direction : null
2377
+ direction: isSorted ? effectiveSort.direction : null
2359
2378
  }
2360
2379
  )
2361
2380
  ]
@@ -2375,14 +2394,14 @@ function Table(props) {
2375
2394
  columnCount: totalColumnCount,
2376
2395
  cellClassName: sizeClasses.cell
2377
2396
  }
2378
- ) : pagedRows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
2397
+ ) : data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
2379
2398
  "td",
2380
2399
  {
2381
2400
  colSpan: totalColumnCount,
2382
2401
  className: cn(sizeClasses.cell, "py-10 text-center text-muted-foreground"),
2383
2402
  children: emptyState ?? "No data"
2384
2403
  }
2385
- ) }) : pagedRows.map((row, rowIndex) => {
2404
+ ) }) : data.map((row, rowIndex) => {
2386
2405
  const id = getRowId(row, rowIndex);
2387
2406
  const isSelected = selected.has(id);
2388
2407
  const rowSelectable = isRowSelectable ? isRowSelectable(row) : true;
@@ -2435,12 +2454,13 @@ function Table(props) {
2435
2454
  paginationVisible ? /* @__PURE__ */ jsxRuntime.jsx(
2436
2455
  Pagination,
2437
2456
  {
2438
- pageIndex: pagination.pageIndex,
2439
- pageSize: pagination.pageSize,
2457
+ pageIndex,
2458
+ pageSize,
2440
2459
  pageCount,
2441
2460
  totalRowCount,
2442
2461
  pageSizeOptions,
2443
- onChange: setPagination
2462
+ onChange: handlePaginationChange,
2463
+ labels
2444
2464
  }
2445
2465
  ) : null
2446
2466
  ] });
@@ -2456,24 +2476,6 @@ function renderCell(column, row, rowIndex) {
2456
2476
  }
2457
2477
  return null;
2458
2478
  }
2459
- function resolveSortGetter(column) {
2460
- if (column.sortAccessor) return column.sortAccessor;
2461
- if (column.accessor !== void 0) {
2462
- const key = column.accessor;
2463
- return (row) => row[key];
2464
- }
2465
- return null;
2466
- }
2467
- function compareValues(a, b) {
2468
- if (a === b) return 0;
2469
- if (a === null || a === void 0) return 1;
2470
- if (b === null || b === void 0) return -1;
2471
- if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
2472
- if (typeof a === "number" && typeof b === "number") return a - b;
2473
- if (typeof a === "bigint" && typeof b === "bigint") return a < b ? -1 : 1;
2474
- if (typeof a === "boolean" && typeof b === "boolean") return a === b ? 0 : a ? 1 : -1;
2475
- return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
2476
- }
2477
2479
  function nextSort(current, columnId) {
2478
2480
  if (current.columnId !== columnId) return { columnId, direction: "asc" };
2479
2481
  if (current.direction === "asc") return { columnId, direction: "desc" };
@@ -2524,16 +2526,14 @@ function ListPage({
2524
2526
  getRowId,
2525
2527
  isLoading = false,
2526
2528
  loadingRowCount,
2527
- searchKeys,
2528
- searchValue: searchValueProp,
2529
+ searchValue,
2529
2530
  onSearchChange,
2530
2531
  filters,
2531
- filterValues: filterValuesProp,
2532
+ filterValues,
2532
2533
  onFilterChange,
2533
2534
  enableRowSelection,
2534
2535
  bulkActions,
2535
2536
  pagination,
2536
- defaultPagination,
2537
2537
  onPaginationChange,
2538
2538
  totalCount,
2539
2539
  pageSizeOptions,
@@ -2543,82 +2543,36 @@ function ListPage({
2543
2543
  className
2544
2544
  }) {
2545
2545
  const labels = { ...DEFAULT_LABELS2, ...labelsProp };
2546
- const initialFilterValues = react.useMemo(() => {
2547
- 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;
2548
2550
  for (const f of filters ?? []) {
2549
- init[f.key] = f.defaultValue ?? f.options[0]?.value ?? "";
2550
- }
2551
- return init;
2552
- }, [filters]);
2553
- const isSearchControlled = searchValueProp !== void 0;
2554
- const isFiltersControlled = filterValuesProp !== void 0;
2555
- const [internalSearch, setInternalSearch] = react.useState("");
2556
- const [internalFilterValues, setInternalFilterValues] = react.useState(initialFilterValues);
2557
- const search = isSearchControlled ? searchValueProp : internalSearch;
2558
- const filterValues = isFiltersControlled ? filterValuesProp : internalFilterValues;
2559
- const setSearch = (next) => {
2560
- if (!isSearchControlled) setInternalSearch(next);
2561
- onSearchChange?.(next);
2562
- };
2563
- const setFilter = (key, value) => {
2564
- if (!isFiltersControlled) {
2565
- setInternalFilterValues((prev) => ({ ...prev, [key]: value }));
2551
+ const current = filterValues?.[f.key];
2552
+ const def = f.options[0]?.value ?? "";
2553
+ if (current !== void 0 && current !== def) return true;
2566
2554
  }
2567
- onFilterChange?.(key, value);
2568
- };
2555
+ return false;
2556
+ }, [searchValue, filters, filterValues]);
2569
2557
  const reset = () => {
2570
- if (!isSearchControlled) setInternalSearch("");
2571
2558
  onSearchChange?.("");
2572
- if (!isFiltersControlled) setInternalFilterValues(initialFilterValues);
2573
2559
  for (const f of filters ?? []) {
2574
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2560
+ const def = f.options[0]?.value ?? "";
2575
2561
  onFilterChange?.(f.key, def);
2576
2562
  }
2577
2563
  };
2578
- const hasActiveFilters = react.useMemo(() => {
2579
- if (search.trim() !== "") return true;
2580
- for (const f of filters ?? []) {
2581
- const current = filterValues[f.key];
2582
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2583
- if (current !== def) return true;
2584
- }
2585
- return false;
2586
- }, [search, filters, filterValues]);
2587
- const filtered = react.useMemo(() => {
2588
- return data.filter((row) => {
2589
- if (!isSearchControlled && search.trim() && searchKeys && searchKeys.length > 0) {
2590
- const q = search.trim().toLowerCase();
2591
- const matches = searchKeys.some((key) => {
2592
- const val = row[key];
2593
- return val != null && String(val).toLowerCase().includes(q);
2594
- });
2595
- if (!matches) return false;
2596
- }
2597
- if (!isFiltersControlled) {
2598
- for (const f of filters ?? []) {
2599
- const value = filterValues[f.key];
2600
- const def = f.defaultValue ?? f.options[0]?.value ?? "";
2601
- if (value !== void 0 && value !== def) {
2602
- if (f.accessor(row) !== value) return false;
2603
- }
2604
- }
2605
- }
2606
- return true;
2607
- });
2608
- }, [data, search, searchKeys, filters, filterValues, isSearchControlled, isFiltersControlled]);
2609
- const showFilterBar = Boolean(searchKeys?.length) || Boolean(filters?.length);
2610
- const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveFilters ? "no-data" : filtered.length === 0 ? "no-results" : "rows";
2564
+ const tableMode = isLoading ? "loading" : data.length === 0 && !hasActiveQuery ? "no-data" : data.length === 0 && hasActiveQuery ? "no-results" : "rows";
2611
2565
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page", className: cn("space-y-6", className), children: [
2612
2566
  /* @__PURE__ */ jsxRuntime.jsx(PageHeader, { title, description, bordered, actions }),
2613
2567
  showFilterBar ? /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "list-page-filter-bar", className: "flex flex-wrap items-center gap-3", children: [
2614
- searchKeys?.length ? /* @__PURE__ */ jsxRuntime.jsx(
2568
+ showSearch ? /* @__PURE__ */ jsxRuntime.jsx(
2615
2569
  Input,
2616
2570
  {
2617
2571
  type: "search",
2618
2572
  placeholder: labels.searchPlaceholder,
2619
2573
  "aria-label": labels.searchAriaLabel || labels.searchPlaceholder,
2620
- value: search,
2621
- onChange: (e) => setSearch(e.target.value),
2574
+ value: searchValue ?? "",
2575
+ onChange: (e) => onSearchChange?.(e.target.value),
2622
2576
  leadingIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, {}),
2623
2577
  wrapperClassName: "sm:max-w-xs",
2624
2578
  disabled: isLoading
@@ -2627,16 +2581,16 @@ function ListPage({
2627
2581
  filters?.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
2628
2582
  Select,
2629
2583
  {
2630
- "aria-label": f.ariaLabel,
2631
- value: filterValues[f.key],
2632
- 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),
2633
2587
  options: f.options,
2634
2588
  className: FILTER_WIDTH_CLASS[f.width ?? "default"],
2635
2589
  disabled: isLoading
2636
2590
  },
2637
2591
  f.key
2638
2592
  )),
2639
- hasActiveFilters && !isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", onClick: reset, children: [
2593
+ hasActiveQuery && !isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", onClick: reset, children: [
2640
2594
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, {}),
2641
2595
  labels.reset
2642
2596
  ] }) : null
@@ -2645,7 +2599,7 @@ function ListPage({
2645
2599
  Table,
2646
2600
  {
2647
2601
  "aria-label": typeof title === "string" ? title : void 0,
2648
- data: filtered,
2602
+ data,
2649
2603
  columns,
2650
2604
  getRowId,
2651
2605
  enableRowSelection,
@@ -2653,10 +2607,10 @@ function ListPage({
2653
2607
  loading: isLoading,
2654
2608
  loadingRowCount,
2655
2609
  pagination,
2656
- defaultPagination,
2657
2610
  onPaginationChange,
2658
2611
  totalCount,
2659
- pageSizeOptions
2612
+ pageSizeOptions,
2613
+ labels
2660
2614
  }
2661
2615
  ) : tableMode === "no-data" ? /* @__PURE__ */ jsxRuntime.jsx(
2662
2616
  "div",