@marktiderman/genesis-ui 2.0.0 → 2.2.0

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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{AppShell-BJarYZzz.d.ts → AppShell-sQT0UbXg.d.ts} +4 -4
  3. package/dist/{chunk-Q4I4SFBD.js → chunk-GDFNAHI4.js} +9 -5
  4. package/dist/chunk-GDFNAHI4.js.map +1 -0
  5. package/dist/components/data/index.d.ts +230 -27
  6. package/dist/components/data/index.js +253 -27
  7. package/dist/components/data/index.js.map +1 -1
  8. package/dist/components/layout/index.d.ts +2 -3
  9. package/dist/components/layout/index.js +4 -4
  10. package/dist/components/patterns/empty-state.d.ts +4 -5
  11. package/dist/components/patterns/form-field.d.ts +3 -4
  12. package/dist/components/patterns/index.d.ts +2 -3
  13. package/dist/components/patterns/index.js +3 -3
  14. package/dist/components/patterns/page-loading.d.ts +2 -2
  15. package/dist/components/patterns/settings-row.d.ts +1 -2
  16. package/dist/components/patterns/status-badge.d.ts +1 -2
  17. package/dist/components/patterns/toggle-row.d.ts +1 -2
  18. package/dist/components/patterns/user-avatar.d.ts +2 -2
  19. package/dist/components/ui/accessible-icon.d.ts +1 -2
  20. package/dist/components/ui/alert-dialog.d.ts +2 -3
  21. package/dist/components/ui/badge.d.ts +1 -2
  22. package/dist/components/ui/breadcrumb.d.ts +2 -3
  23. package/dist/components/ui/button-group.d.ts +1 -2
  24. package/dist/components/ui/calendar.d.ts +2 -3
  25. package/dist/components/ui/card.d.ts +6 -7
  26. package/dist/components/ui/carousel.d.ts +2 -3
  27. package/dist/components/ui/chart.d.ts +4 -5
  28. package/dist/components/ui/command-palette.d.ts +1 -2
  29. package/dist/components/ui/command.d.ts +2 -3
  30. package/dist/components/ui/context-menu.d.ts +1 -2
  31. package/dist/components/ui/date-picker.d.ts +2 -2
  32. package/dist/components/ui/dialog.d.ts +2 -3
  33. package/dist/components/ui/drawer.d.ts +3 -4
  34. package/dist/components/ui/dropdown-menu.d.ts +1 -2
  35. package/dist/components/ui/kbd.d.ts +1 -2
  36. package/dist/components/ui/menubar.d.ts +1 -2
  37. package/dist/components/ui/pagination.d.ts +5 -6
  38. package/dist/components/ui/password-toggle-field.d.ts +2 -3
  39. package/dist/components/ui/progress.d.ts +1 -2
  40. package/dist/components/ui/resizable.d.ts +2 -3
  41. package/dist/components/ui/separator.d.ts +1 -2
  42. package/dist/components/ui/sheet.d.ts +2 -3
  43. package/dist/components/ui/skeleton.d.ts +1 -2
  44. package/dist/components/ui/sonner.d.ts +1 -2
  45. package/dist/components/ui/spinner.d.ts +1 -2
  46. package/dist/components/ui/tooltip.d.ts +1 -2
  47. package/dist/components/ui/typography.d.ts +9 -10
  48. package/dist/hooks/index.d.ts +2 -3
  49. package/dist/hooks/index.js +1 -1
  50. package/dist/hooks/use-resource-page.d.ts +2 -3
  51. package/dist/hooks/use-resource-page.js +1 -1
  52. package/dist/hooks/use-view-preference.d.ts +2 -2
  53. package/dist/index.d.ts +0 -1
  54. package/dist/index.js +11 -11
  55. package/dist/{use-resource-page-CPs6wjKt.d.ts → use-resource-page-DTQS011Q.d.ts} +18 -6
  56. package/dist/{view-settings--KXNT_jE.d.ts → view-settings-kHKCHMjj.d.ts} +2 -2
  57. package/dist/{view-toggle-DDe_Luj2.d.ts → view-toggle-CahQ87PW.d.ts} +2 -2
  58. package/package.json +15 -15
  59. package/dist/chunk-Q4I4SFBD.js.map +0 -1
@@ -15,18 +15,18 @@ import '../../chunk-B2GIBUQD.js';
15
15
  import { Badge } from '../../chunk-NPNADZHM.js';
16
16
  import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../chunk-FK42ZGGV.js';
17
17
  import { Popover, PopoverTrigger, PopoverContent } from '../../chunk-22XB3Q6H.js';
18
+ import { PageLoading } from '../../chunk-YRYQXU3G.js';
19
+ import { Spinner } from '../../chunk-OVU3Z2MT.js';
18
20
  import { Switch } from '../../chunk-27ELYTGE.js';
21
+ import { DetailPage } from '../../chunk-AFZ76Q26.js';
22
+ import '../../chunk-D2LIXA2Y.js';
23
+ import '../../chunk-AVFZ4P4B.js';
19
24
  import { EmptyState } from '../../chunk-65SPT7EA.js';
20
25
  export { EmptyState } from '../../chunk-65SPT7EA.js';
21
26
  import { Button } from '../../chunk-NWSCYLPT.js';
22
- import { PageLoading } from '../../chunk-YRYQXU3G.js';
23
- import { Spinner } from '../../chunk-OVU3Z2MT.js';
24
27
  import { FormField, FormLabel, FormError, FormDescription } from '../../chunk-R7QFP6EL.js';
25
28
  import '../../chunk-F47U5KNW.js';
26
- import { DetailPage } from '../../chunk-AFZ76Q26.js';
27
- import '../../chunk-D2LIXA2Y.js';
28
- import '../../chunk-AVFZ4P4B.js';
29
- import { titleCase, useResourcePage } from '../../chunk-Q4I4SFBD.js';
29
+ import { titleCase, useResourcePage } from '../../chunk-GDFNAHI4.js';
30
30
  export { useSavedViews } from '../../chunk-GCQFVMPI.js';
31
31
  import '../../chunk-FTTNGGLA.js';
32
32
  import { useViewSettings } from '../../chunk-OZ7ZAYCS.js';
@@ -40,7 +40,7 @@ import { useKeyboardNavigation } from '../../chunk-YJ6MPS6U.js';
40
40
  import { useIsMobile } from '../../chunk-M7AU5DDM.js';
41
41
  import { AlertTriangle, RefreshCw, ChevronDown, Check, Search, X, ArrowUpDown, Bookmark, Trash2, BookmarkPlus, Loader2, Columns3, ArrowUp, ArrowDown, ChevronLeft, ChevronRight, ExternalLink, Pencil, ChevronsUpDown, ImageIcon, Upload, AlertCircle, FileIcon, Plus } from 'lucide-react';
42
42
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
43
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
43
+ import { useState, useRef, useEffect, useCallback, useMemo, Fragment as Fragment$1 } from 'react';
44
44
  import { formatDistanceToNow, format } from 'date-fns';
45
45
  import { useFieldArray, Controller, useWatch } from 'react-hook-form';
46
46
  import { useResource, useWizard, useResourceForm, useOne, buildArrayItemDefaults } from '@marktiderman/genesis-core/hooks';
@@ -1146,6 +1146,7 @@ function DataBulkBar({
1146
1146
  size: "sm",
1147
1147
  variant: action.variant || "outline",
1148
1148
  onClick: action.onClick,
1149
+ disabled: action.disabled,
1149
1150
  children: [
1150
1151
  /* @__PURE__ */ jsx(ActionIcon, { className: "h-3.5 w-3.5 mr-1" }),
1151
1152
  action.label
@@ -2424,6 +2425,29 @@ function ResourcePage(props) {
2424
2425
  searchPlaceholder,
2425
2426
  initialFilters,
2426
2427
  onFiltersChange,
2428
+ filters: filtersProp,
2429
+ page: pageProp,
2430
+ perPage: perPageProp,
2431
+ onPageChange,
2432
+ onPerPageChange,
2433
+ onSortChange,
2434
+ onSearchChange,
2435
+ loading: loadingProp,
2436
+ error: errorProp,
2437
+ errorMessage,
2438
+ onRetry: onRetryProp,
2439
+ savedViews,
2440
+ onLoadView,
2441
+ onSaveView,
2442
+ onDeleteView,
2443
+ canSaveViews,
2444
+ columnVisibility,
2445
+ columnVisibilityKey,
2446
+ resizableColumns,
2447
+ resizeKey,
2448
+ stickyHeader,
2449
+ stickyFirstColumn,
2450
+ pageSizeOptions,
2427
2451
  onCreate,
2428
2452
  onEdit,
2429
2453
  onDelete,
@@ -2437,6 +2461,7 @@ function ResourcePage(props) {
2437
2461
  formLayout: formLayoutProp,
2438
2462
  bulkActions,
2439
2463
  renderCard: renderCardProp,
2464
+ renderTable: renderTableProp,
2440
2465
  gridCols: gridColsProp,
2441
2466
  keyboardNavigation = true,
2442
2467
  toolbar,
@@ -2447,16 +2472,18 @@ function ResourcePage(props) {
2447
2472
  viewSettingsKey: viewSettingsKeyProp
2448
2473
  } = props;
2449
2474
  const isClientMode = !!resourceName;
2475
+ const isServerControlled = pageProp !== void 0 || perPageProp !== void 0 || onPageChange !== void 0 || onPerPageChange !== void 0 || onSortChange !== void 0 || onSearchChange !== void 0;
2450
2476
  const viewSettingsKey = viewSettingsKeyProp ?? resourceName ?? title.toLowerCase().replace(/\s+/g, "-");
2451
2477
  const { settings, updateSetting } = useViewSettings(viewSettingsKey);
2478
+ const effectivePageSize = perPageProp ?? settings.pageSize;
2452
2479
  const resourceHook = useResource(
2453
2480
  resourceName ?? "__noop__",
2454
2481
  isClientMode ? resourceOptions : { enabled: false }
2455
2482
  );
2456
2483
  const displayData = isClientMode ? resourceHook.list.data?.data ?? [] : dataProp ?? [];
2457
2484
  const displayTotal = isClientMode ? resourceHook.list.data?.total ?? 0 : totalProp ?? 0;
2458
- const isLoading = isClientMode ? resourceHook.list.isLoading : false;
2459
- const hasError = isClientMode ? resourceHook.list.isError : false;
2485
+ const isLoading = isClientMode ? resourceHook.list.isLoading : loadingProp ?? false;
2486
+ const hasError = isClientMode ? resourceHook.list.isError : errorProp ?? false;
2460
2487
  const page = useResourcePage({
2461
2488
  resource: resourceName,
2462
2489
  data: displayData,
@@ -2469,7 +2496,8 @@ function ResourcePage(props) {
2469
2496
  defaultView,
2470
2497
  detail,
2471
2498
  titleField: titleFieldProp,
2472
- subtitleField: subtitleFieldProp
2499
+ subtitleField: subtitleFieldProp,
2500
+ controlled: isServerControlled
2473
2501
  });
2474
2502
  const actions = useMemo(() => {
2475
2503
  if (isClientMode) {
@@ -2481,15 +2509,24 @@ function ResourcePage(props) {
2481
2509
  }
2482
2510
  return {
2483
2511
  update: async () => {
2484
- throw new Error("ResourceActions.update not available in server-data mode");
2512
+ throw new Error(
2513
+ "ResourceActions.update not available in server-data mode"
2514
+ );
2485
2515
  },
2486
2516
  remove: async () => {
2487
- throw new Error("ResourceActions.remove not available in server-data mode");
2517
+ throw new Error(
2518
+ "ResourceActions.remove not available in server-data mode"
2519
+ );
2488
2520
  },
2489
2521
  refetch: () => {
2490
2522
  }
2491
2523
  };
2492
- }, [isClientMode, resourceHook.update, resourceHook.remove, resourceHook.list]);
2524
+ }, [
2525
+ isClientMode,
2526
+ resourceHook.update,
2527
+ resourceHook.remove,
2528
+ resourceHook.list
2529
+ ]);
2493
2530
  const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
2494
2531
  const handleToggleSelect = useCallback((id) => {
2495
2532
  setSelectedIds((prev) => {
@@ -2539,15 +2576,101 @@ function ResourcePage(props) {
2539
2576
  [useBuiltInEdit, onEdit]
2540
2577
  );
2541
2578
  const tableColumns = useMemo(() => {
2542
- if (!isClientMode) return page.tableColumns;
2543
- return page.columns.map((col) => ({
2579
+ const base = isClientMode ? page.columns.map((col) => ({
2544
2580
  key: col.key,
2545
2581
  header: col.header ?? col.key,
2546
2582
  sortable: col.sortable ?? true,
2547
2583
  hideBelow: col.hideBelow,
2548
2584
  render: col.render ? (item, value) => col.render(item, value, actions) : void 0
2549
- }));
2550
- }, [isClientMode, page.columns, page.tableColumns, actions]);
2585
+ })) : page.tableColumns;
2586
+ if (!isServerControlled) return base;
2587
+ return base.map((col) => ({ ...col, sortable: false }));
2588
+ }, [
2589
+ isClientMode,
2590
+ isServerControlled,
2591
+ page.columns,
2592
+ page.tableColumns,
2593
+ actions
2594
+ ]);
2595
+ const currentPage = pageProp ?? 1;
2596
+ const handleSearchChange = useCallback(
2597
+ (value) => {
2598
+ page.filterConfig.onSearchChange(value);
2599
+ if (!isServerControlled) return;
2600
+ onSearchChange?.(value);
2601
+ if (currentPage !== 1) onPageChange?.(1);
2602
+ },
2603
+ [
2604
+ page.filterConfig,
2605
+ isServerControlled,
2606
+ onSearchChange,
2607
+ onPageChange,
2608
+ currentPage
2609
+ ]
2610
+ );
2611
+ const handleSortSelect = useCallback(
2612
+ (value) => {
2613
+ page.filterConfig.onSortChange(value);
2614
+ if (!isServerControlled) return;
2615
+ const [field, order] = value.split(":");
2616
+ onSortChange?.(
2617
+ field && (order === "asc" || order === "desc") ? { field, order } : null
2618
+ );
2619
+ onPageChange?.(1);
2620
+ },
2621
+ [page.filterConfig, isServerControlled, onSortChange, onPageChange]
2622
+ );
2623
+ const handleClearFilters = useCallback(() => {
2624
+ page.clearFilters();
2625
+ if (!isServerControlled) return;
2626
+ onSearchChange?.("");
2627
+ onSortChange?.(null);
2628
+ onPageChange?.(1);
2629
+ }, [page, isServerControlled, onSearchChange, onSortChange, onPageChange]);
2630
+ const handleStatusChange = useCallback(
2631
+ (values) => {
2632
+ page.filterConfig.statusChips?.onChange(values);
2633
+ if (!isServerControlled) return;
2634
+ if (currentPage !== 1) onPageChange?.(1);
2635
+ },
2636
+ [page.filterConfig, isServerControlled, onPageChange, currentPage]
2637
+ );
2638
+ const statusChipsConfig = useMemo(() => {
2639
+ const base = page.filterConfig.statusChips;
2640
+ if (!base) return void 0;
2641
+ return { ...base, onChange: handleStatusChange };
2642
+ }, [page.filterConfig.statusChips, handleStatusChange]);
2643
+ const handlePageSizeChange = useCallback(
2644
+ (size) => {
2645
+ updateSetting("pageSize", size);
2646
+ onPerPageChange?.(size);
2647
+ if (isServerControlled) onPageChange?.(1);
2648
+ },
2649
+ [updateSetting, onPerPageChange, isServerControlled, onPageChange]
2650
+ );
2651
+ const missingPerPage = isServerControlled && !!onPageChange && perPageProp === void 0;
2652
+ const missingTotal = isServerControlled && !!onPageChange && totalProp === void 0;
2653
+ const pagerMisconfigured = missingPerPage || missingTotal;
2654
+ const missingPagerProps = [
2655
+ ...missingPerPage ? ["perPage"] : [],
2656
+ ...missingTotal ? ["total"] : []
2657
+ ];
2658
+ const loggedMissingPerPageRef = useRef(false);
2659
+ useEffect(() => {
2660
+ if (!pagerMisconfigured) return;
2661
+ if (loggedMissingPerPageRef.current) return;
2662
+ loggedMissingPerPageRef.current = true;
2663
+ console.error(
2664
+ `ResourcePage: ${missingPagerProps.map((name) => `\`${name}\``).join(" and ")} ${missingPagerProps.length > 1 ? "are" : "is"} required when \`onPageChange\` is supplied.`
2665
+ );
2666
+ }, [pagerMisconfigured]);
2667
+ const pagerPageSize = perPageProp ?? effectivePageSize;
2668
+ const totalPages = Math.max(
2669
+ 1,
2670
+ Math.ceil(displayTotal / Math.max(1, pagerPageSize))
2671
+ );
2672
+ const rangeFrom = page.data.length === 0 ? 0 : (currentPage - 1) * pagerPageSize + 1;
2673
+ const rangeTo = rangeFrom === 0 ? 0 : rangeFrom + page.data.length - 1;
2551
2674
  const detailTitle = page.selectedItem ? String(
2552
2675
  page.selectedItem[page.titleField] ?? ""
2553
2676
  ) : "";
@@ -2691,28 +2814,35 @@ function ResourcePage(props) {
2691
2814
  isLoading,
2692
2815
  hasError,
2693
2816
  isEmpty,
2694
- onRetry: isClientMode ? () => resourceHook.list.refetch() : void 0,
2817
+ errorMessage,
2818
+ onRetry: isClientMode ? () => resourceHook.list.refetch() : onRetryProp,
2695
2819
  viewMode: page.viewMode,
2696
2820
  onViewModeChange: page.setViewMode,
2697
- pageSize: settings.pageSize,
2698
- onPageSizeChange: (size) => updateSetting("pageSize", size),
2821
+ pageSize: effectivePageSize,
2822
+ onPageSizeChange: handlePageSizeChange,
2699
2823
  density: settings.density,
2700
2824
  onDensityChange: (d) => updateSetting("density", d),
2701
2825
  createAction,
2702
2826
  hasActiveFilters: page.hasActiveFilters,
2703
- onClearFilters: page.clearFilters,
2827
+ onClearFilters: handleClearFilters,
2704
2828
  emptyAction: emptyState,
2705
2829
  filters: /* @__PURE__ */ jsx(
2706
2830
  DataFilters,
2707
2831
  {
2708
2832
  search: page.filterConfig.search,
2709
- onSearchChange: page.filterConfig.onSearchChange,
2833
+ onSearchChange: handleSearchChange,
2710
2834
  searchPlaceholder,
2711
2835
  sort: page.filterConfig.sort,
2712
- onSortChange: page.filterConfig.onSortChange,
2836
+ onSortChange: handleSortSelect,
2713
2837
  sortOptions: page.filterConfig.sortOptions,
2714
- statusChips: page.filterConfig.statusChips,
2715
- onClearAll: page.hasActiveFilters ? page.clearFilters : void 0
2838
+ filters: filtersProp,
2839
+ statusChips: statusChipsConfig,
2840
+ savedViews,
2841
+ onLoadView,
2842
+ onSaveView,
2843
+ onDeleteView,
2844
+ canSaveViews,
2845
+ onClearAll: page.hasActiveFilters ? handleClearFilters : void 0
2716
2846
  }
2717
2847
  ),
2718
2848
  children: [
@@ -2727,6 +2857,7 @@ function ResourcePage(props) {
2727
2857
  label: a.label,
2728
2858
  icon: a.icon ?? Trash2,
2729
2859
  variant: a.variant,
2860
+ disabled: a.disabled,
2730
2861
  onClick: () => {
2731
2862
  void a.onAction(Array.from(selectedIds));
2732
2863
  }
@@ -2742,7 +2873,7 @@ function ResourcePage(props) {
2742
2873
  getKey: (item) => String(item.id ?? ""),
2743
2874
  focusedIndex: keyboardNav.focusedIndex,
2744
2875
  keyboardContainerRef: keyboardNav.containerRef,
2745
- renderTable: (items) => /* @__PURE__ */ jsx(
2876
+ renderTable: (items) => renderTableProp ? renderTableProp(items) : /* @__PURE__ */ jsx(
2746
2877
  DataTable,
2747
2878
  {
2748
2879
  items,
@@ -2754,13 +2885,108 @@ function ResourcePage(props) {
2754
2885
  onToggleSelect: handleToggleSelect,
2755
2886
  onToggleAll: handleToggleAll,
2756
2887
  density: settings.density,
2757
- pageSize: settings.pageSize
2888
+ pageSize: effectivePageSize,
2889
+ pageSizeOptions,
2890
+ columnVisibility,
2891
+ columnVisibilityKey,
2892
+ resizableColumns,
2893
+ resizeKey,
2894
+ stickyHeader,
2895
+ stickyFirstColumn,
2896
+ pagination: isServerControlled ? false : void 0
2758
2897
  }
2759
2898
  ),
2760
2899
  renderCard: (item, index) => renderCardProp ? renderCardProp(item, index, cardActionsFor(item)) : renderDefaultCard(item),
2761
2900
  renderListItem: (item, index) => renderCardProp ? renderCardProp(item, index, cardActionsFor(item)) : renderDefaultListItem(item)
2762
2901
  }
2763
2902
  ),
2903
+ isServerControlled && onPageChange && pagerMisconfigured && /* @__PURE__ */ jsxs(
2904
+ "div",
2905
+ {
2906
+ className: "flex items-center gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive",
2907
+ "data-testid": "resource-page-pagination-error",
2908
+ role: "alert",
2909
+ children: [
2910
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
2911
+ /* @__PURE__ */ jsxs("span", { children: [
2912
+ "Pagination unavailable:",
2913
+ " ",
2914
+ missingPagerProps.map((name, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
2915
+ index > 0 ? " and " : null,
2916
+ /* @__PURE__ */ jsx("code", { children: name })
2917
+ ] }, name)),
2918
+ " ",
2919
+ missingPagerProps.length > 1 ? "are" : "is",
2920
+ " required when",
2921
+ " ",
2922
+ /* @__PURE__ */ jsx("code", { children: "onPageChange" }),
2923
+ " is supplied."
2924
+ ] })
2925
+ ]
2926
+ }
2927
+ ),
2928
+ isServerControlled && onPageChange && !pagerMisconfigured && /* @__PURE__ */ jsxs(
2929
+ "nav",
2930
+ {
2931
+ "aria-label": "Pagination",
2932
+ className: "flex flex-col sm:flex-row items-center justify-between gap-2 px-3 py-2 text-sm",
2933
+ "data-testid": "resource-page-pagination",
2934
+ children: [
2935
+ /* @__PURE__ */ jsx(
2936
+ "span",
2937
+ {
2938
+ className: "text-muted-foreground",
2939
+ "data-testid": "resource-page-range",
2940
+ "aria-live": "polite",
2941
+ children: displayTotal === 0 ? "No records" : `Showing ${rangeFrom}-${rangeTo} of ${displayTotal}`
2942
+ }
2943
+ ),
2944
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2945
+ /* @__PURE__ */ jsxs(
2946
+ Button,
2947
+ {
2948
+ variant: "outline",
2949
+ size: "sm",
2950
+ disabled: currentPage <= 1,
2951
+ onClick: () => onPageChange(currentPage - 1),
2952
+ testID: "resource-page-prev",
2953
+ children: [
2954
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4 mr-1", "aria-hidden": "true" }),
2955
+ "Previous"
2956
+ ]
2957
+ }
2958
+ ),
2959
+ /* @__PURE__ */ jsxs(
2960
+ "span",
2961
+ {
2962
+ className: "text-muted-foreground",
2963
+ "data-testid": "resource-page-indicator",
2964
+ children: [
2965
+ "Page ",
2966
+ currentPage,
2967
+ " of ",
2968
+ totalPages
2969
+ ]
2970
+ }
2971
+ ),
2972
+ /* @__PURE__ */ jsxs(
2973
+ Button,
2974
+ {
2975
+ variant: "outline",
2976
+ size: "sm",
2977
+ disabled: currentPage >= totalPages,
2978
+ onClick: () => onPageChange(currentPage + 1),
2979
+ testID: "resource-page-next",
2980
+ children: [
2981
+ "Next",
2982
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 ml-1", "aria-hidden": "true" })
2983
+ ]
2984
+ }
2985
+ )
2986
+ ] })
2987
+ ]
2988
+ }
2989
+ ),
2764
2990
  (detail === "panel" || detail === "modal") && /* @__PURE__ */ jsx(
2765
2991
  DetailPanel,
2766
2992
  {