@marktiderman/genesis-ui 1.3.0 → 2.1.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.
- package/LICENSE +21 -0
- package/dist/AppShell-sQT0UbXg.d.ts +198 -0
- package/dist/{chunk-NJMO3VPA.js → chunk-22XB3Q6H.js} +8 -8
- package/dist/chunk-22XB3Q6H.js.map +1 -0
- package/dist/{chunk-2MXMWBDV.js → chunk-27ELYTGE.js} +6 -6
- package/dist/chunk-27ELYTGE.js.map +1 -0
- package/dist/chunk-46TZGMFW.js +159 -0
- package/dist/chunk-46TZGMFW.js.map +1 -0
- package/dist/chunk-4CQHPWJD.js +117 -0
- package/dist/chunk-4CQHPWJD.js.map +1 -0
- package/dist/{chunk-ZDAT5JDH.js → chunk-65SPT7EA.js} +24 -6
- package/dist/chunk-65SPT7EA.js.map +1 -0
- package/dist/chunk-6KHY647C.js +67 -0
- package/dist/chunk-6KHY647C.js.map +1 -0
- package/dist/chunk-6M4NHHKG.js +51 -0
- package/dist/chunk-6M4NHHKG.js.map +1 -0
- package/dist/chunk-6Q6CLLJ4.js +9 -0
- package/dist/chunk-6Q6CLLJ4.js.map +1 -0
- package/dist/{chunk-UGHQFQOE.js → chunk-6TVMQH6M.js} +28 -28
- package/dist/chunk-6TVMQH6M.js.map +1 -0
- package/dist/{chunk-6VVVGYKS.js → chunk-6XPMU65K.js} +5 -5
- package/dist/{chunk-6VVVGYKS.js.map → chunk-6XPMU65K.js.map} +1 -1
- package/dist/{chunk-YZEA5TGK.js → chunk-7XMZVISM.js} +16 -16
- package/dist/chunk-7XMZVISM.js.map +1 -0
- package/dist/chunk-A7AHVDG7.js +52 -0
- package/dist/chunk-A7AHVDG7.js.map +1 -0
- package/dist/chunk-AFZ76Q26.js +84 -0
- package/dist/chunk-AFZ76Q26.js.map +1 -0
- package/dist/{chunk-4V4H2ZM7.js → chunk-AL5TMEZQ.js} +31 -31
- package/dist/chunk-AL5TMEZQ.js.map +1 -0
- package/dist/{chunk-AUECDWP2.js → chunk-AOZGQM6W.js} +3 -3
- package/dist/chunk-AOZGQM6W.js.map +1 -0
- package/dist/chunk-ARJI2JUV.js +122 -0
- package/dist/chunk-ARJI2JUV.js.map +1 -0
- package/dist/chunk-AVFZ4P4B.js +25 -0
- package/dist/chunk-AVFZ4P4B.js.map +1 -0
- package/dist/chunk-B2GIBUQD.js +11 -0
- package/dist/chunk-B2GIBUQD.js.map +1 -0
- package/dist/{chunk-JXI2MYL3.js → chunk-C46ITXE4.js} +5 -5
- package/dist/chunk-C46ITXE4.js.map +1 -0
- package/dist/{chunk-A2OXCNNY.js → chunk-CNTWQSUT.js} +3 -3
- package/dist/{chunk-A2OXCNNY.js.map → chunk-CNTWQSUT.js.map} +1 -1
- package/dist/chunk-D2LIXA2Y.js +65 -0
- package/dist/chunk-D2LIXA2Y.js.map +1 -0
- package/dist/{chunk-T5VX5DYO.js → chunk-F47U5KNW.js} +5 -5
- package/dist/chunk-F47U5KNW.js.map +1 -0
- package/dist/chunk-FEJAZFP3.js +1100 -0
- package/dist/chunk-FEJAZFP3.js.map +1 -0
- package/dist/{chunk-2B3MFHBQ.js → chunk-FK42ZGGV.js} +21 -21
- package/dist/chunk-FK42ZGGV.js.map +1 -0
- package/dist/{chunk-XISSLIMH.js → chunk-FTTNGGLA.js} +2 -2
- package/dist/{chunk-XISSLIMH.js.map → chunk-FTTNGGLA.js.map} +1 -1
- package/dist/chunk-G5YKBPBF.js +74 -0
- package/dist/chunk-G5YKBPBF.js.map +1 -0
- package/dist/{chunk-QLCDAFS7.js → chunk-GDFNAHI4.js} +10 -6
- package/dist/chunk-GDFNAHI4.js.map +1 -0
- package/dist/{chunk-KB5T5LWM.js → chunk-IJCT5IJD.js} +3 -3
- package/dist/{chunk-KB5T5LWM.js.map → chunk-IJCT5IJD.js.map} +1 -1
- package/dist/{chunk-44TULYGG.js → chunk-J6FBA7PH.js} +3 -3
- package/dist/{chunk-44TULYGG.js.map → chunk-J6FBA7PH.js.map} +1 -1
- package/dist/chunk-JAMLFMDS.js +12 -0
- package/dist/chunk-JAMLFMDS.js.map +1 -0
- package/dist/{chunk-C6H7AMO4.js → chunk-LNFF2RBD.js} +9 -9
- package/dist/chunk-LNFF2RBD.js.map +1 -0
- package/dist/{chunk-QBZMY2AF.js → chunk-M62CHO3N.js} +18 -18
- package/dist/chunk-M62CHO3N.js.map +1 -0
- package/dist/{chunk-5Q4FABZQ.js → chunk-NUXW6NPP.js} +8 -8
- package/dist/chunk-NUXW6NPP.js.map +1 -0
- package/dist/{chunk-ZJFSZFPI.js → chunk-NWSCYLPT.js} +77 -18
- package/dist/chunk-NWSCYLPT.js.map +1 -0
- package/dist/{chunk-63FW5ZUA.js → chunk-P3ZL6FGR.js} +7 -7
- package/dist/chunk-P3ZL6FGR.js.map +1 -0
- package/dist/chunk-P64MFQXZ.js +191 -0
- package/dist/chunk-P64MFQXZ.js.map +1 -0
- package/dist/chunk-PLIYF6KI.js +52 -0
- package/dist/chunk-PLIYF6KI.js.map +1 -0
- package/dist/chunk-PSR47JRA.js +26 -0
- package/dist/chunk-PSR47JRA.js.map +1 -0
- package/dist/{chunk-SBJV3K4G.js → chunk-QJ6P2DW6.js} +28 -28
- package/dist/chunk-QJ6P2DW6.js.map +1 -0
- package/dist/{chunk-IP6TMT3D.js → chunk-R7QFP6EL.js} +3 -3
- package/dist/chunk-R7QFP6EL.js.map +1 -0
- package/dist/{chunk-WZWR2ELB.js → chunk-SEBU6JCK.js} +6 -6
- package/dist/chunk-SEBU6JCK.js.map +1 -0
- package/dist/{chunk-7OBL3H5P.js → chunk-SEFK4NZV.js} +3 -3
- package/dist/chunk-SEFK4NZV.js.map +1 -0
- package/dist/chunk-SRIT4NFQ.js +67 -0
- package/dist/chunk-SRIT4NFQ.js.map +1 -0
- package/dist/chunk-SY62XJFA.js +19 -0
- package/dist/chunk-SY62XJFA.js.map +1 -0
- package/dist/{chunk-SVXDWPLO.js → chunk-THD3YOOZ.js} +17 -17
- package/dist/chunk-THD3YOOZ.js.map +1 -0
- package/dist/chunk-VXFYETRK.js +58 -0
- package/dist/chunk-VXFYETRK.js.map +1 -0
- package/dist/chunk-XBX6QMR5.js +58 -0
- package/dist/chunk-XBX6QMR5.js.map +1 -0
- package/dist/{chunk-SCUT2ZCD.js → chunk-XCGZPFT7.js} +17 -17
- package/dist/chunk-XCGZPFT7.js.map +1 -0
- package/dist/chunk-XMK3T4TA.js +73 -0
- package/dist/chunk-XMK3T4TA.js.map +1 -0
- package/dist/chunk-YJ6MPS6U.js +226 -0
- package/dist/chunk-YJ6MPS6U.js.map +1 -0
- package/dist/chunk-YRYQXU3G.js +38 -0
- package/dist/chunk-YRYQXU3G.js.map +1 -0
- package/dist/{chunk-5J7BP5DI.js → chunk-YWFPMND7.js} +10 -10
- package/dist/chunk-YWFPMND7.js.map +1 -0
- package/dist/chunk-YYEGAFUE.js +94 -0
- package/dist/chunk-YYEGAFUE.js.map +1 -0
- package/dist/{chunk-TKA4LOMT.js → chunk-ZZ7H7VVX.js} +8 -8
- package/dist/chunk-ZZ7H7VVX.js.map +1 -0
- package/dist/components/data/index.d.ts +318 -228
- package/dist/components/data/index.js +591 -1394
- package/dist/components/data/index.js.map +1 -1
- package/dist/components/layout/dashboard-page.d.ts +4 -0
- package/dist/components/layout/dashboard-page.js +5 -0
- package/dist/components/layout/dashboard-page.js.map +1 -0
- package/dist/components/layout/detail-page.d.ts +91 -0
- package/dist/components/layout/detail-page.js +6 -0
- package/dist/components/layout/detail-page.js.map +1 -0
- package/dist/components/layout/form-page.d.ts +82 -0
- package/dist/components/layout/form-page.js +5 -0
- package/dist/components/layout/form-page.js.map +1 -0
- package/dist/components/layout/index.d.ts +14 -0
- package/dist/components/layout/index.js +21 -0
- package/dist/components/layout/index.js.map +1 -0
- package/dist/components/layout/settings-page.d.ts +114 -0
- package/dist/components/layout/settings-page.js +6 -0
- package/dist/components/layout/settings-page.js.map +1 -0
- package/dist/components/patterns/empty-state.d.ts +73 -0
- package/dist/components/{ui → patterns}/empty-state.js +2 -1
- package/dist/components/{ui → patterns}/form-field.d.ts +5 -6
- package/dist/components/{ui → patterns}/form-field.js +2 -2
- package/dist/components/patterns/index.d.ts +17 -0
- package/dist/components/patterns/index.js +18 -0
- package/dist/components/patterns/index.js.map +1 -0
- package/dist/components/patterns/page-loading.d.ts +25 -0
- package/dist/components/patterns/page-loading.js +5 -0
- package/dist/components/patterns/page-loading.js.map +1 -0
- package/dist/components/patterns/settings-row.d.ts +41 -0
- package/dist/components/patterns/settings-row.js +6 -0
- package/dist/components/patterns/settings-row.js.map +1 -0
- package/dist/components/patterns/status-badge.d.ts +37 -0
- package/dist/components/patterns/status-badge.js +4 -0
- package/dist/components/patterns/status-badge.js.map +1 -0
- package/dist/components/patterns/toggle-row.d.ts +35 -0
- package/dist/components/patterns/toggle-row.js +8 -0
- package/dist/components/patterns/toggle-row.js.map +1 -0
- package/dist/components/patterns/user-avatar.d.ts +34 -0
- package/dist/components/patterns/user-avatar.js +5 -0
- package/dist/components/patterns/user-avatar.js.map +1 -0
- package/dist/components/ui/accessible-icon.d.ts +47 -0
- package/dist/components/ui/accessible-icon.js +3 -0
- package/dist/components/ui/accessible-icon.js.map +1 -0
- package/dist/components/ui/accordion.d.ts +5 -5
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/alert-dialog.d.ts +12 -13
- package/dist/components/ui/alert-dialog.js +1 -1
- package/dist/components/ui/aspect-ratio.d.ts +2 -2
- package/dist/components/ui/aspect-ratio.js +1 -1
- package/dist/components/ui/avatar.d.ts +4 -4
- package/dist/components/ui/avatar.js +1 -1
- package/dist/components/ui/badge.d.ts +1 -2
- package/dist/components/ui/breadcrumb.d.ts +2 -3
- package/dist/components/ui/button-group.d.ts +1 -2
- package/dist/components/ui/button.d.ts +73 -8
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/calendar.d.ts +2 -3
- package/dist/components/ui/calendar.js +2 -2
- package/dist/components/ui/card.d.ts +6 -7
- package/dist/components/ui/carousel.d.ts +4 -4
- package/dist/components/ui/carousel.js +2 -2
- package/dist/components/ui/chart.d.ts +4 -5
- package/dist/components/ui/checkbox.d.ts +2 -2
- package/dist/components/ui/checkbox.js +1 -1
- package/dist/components/ui/collapsible.d.ts +4 -4
- package/dist/components/ui/collapsible.js +1 -1
- package/dist/components/ui/command-palette.d.ts +1 -2
- package/dist/components/ui/command-palette.js +3 -3
- package/dist/components/ui/command.d.ts +11 -12
- package/dist/components/ui/command.js +2 -2
- package/dist/components/ui/context-menu.d.ts +16 -17
- package/dist/components/ui/context-menu.js +1 -1
- package/dist/components/ui/date-picker.d.ts +2 -2
- package/dist/components/ui/date-picker.js +4 -4
- package/dist/components/ui/dialog.d.ts +11 -12
- package/dist/components/ui/dialog.js +1 -1
- package/dist/components/ui/drawer.d.ts +10 -11
- package/dist/components/ui/dropdown-menu.d.ts +16 -17
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/hover-card.d.ts +4 -4
- package/dist/components/ui/hover-card.js +1 -1
- package/dist/components/ui/input-otp.d.ts +2 -2
- package/dist/components/ui/kbd.d.ts +1 -2
- package/dist/components/ui/label.d.ts +2 -2
- package/dist/components/ui/label.js +1 -1
- package/dist/components/ui/menubar.d.ts +17 -18
- package/dist/components/ui/menubar.js +1 -1
- package/dist/components/ui/navigation-menu.d.ts +9 -9
- package/dist/components/ui/navigation-menu.js +1 -1
- package/dist/components/ui/pagination.d.ts +5 -6
- package/dist/components/ui/pagination.js +2 -2
- package/dist/components/ui/password-toggle-field.d.ts +120 -0
- package/dist/components/ui/password-toggle-field.js +4 -0
- package/dist/components/ui/password-toggle-field.js.map +1 -0
- package/dist/components/ui/popover.d.ts +4 -4
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/progress.d.ts +1 -2
- package/dist/components/ui/radio-group.d.ts +3 -3
- package/dist/components/ui/radio-group.js +1 -1
- package/dist/components/ui/resizable.d.ts +3 -4
- package/dist/components/ui/scroll-area.d.ts +60 -3
- package/dist/components/ui/scroll-area.js +1 -1
- package/dist/components/ui/select.d.ts +9 -9
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/separator.d.ts +1 -2
- package/dist/components/ui/sheet.d.ts +13 -12
- package/dist/components/ui/sheet.js +1 -1
- package/dist/components/ui/skeleton.d.ts +1 -2
- package/dist/components/ui/slider.d.ts +2 -2
- package/dist/components/ui/slider.js +1 -1
- package/dist/components/ui/sonner.d.ts +1 -2
- package/dist/components/ui/spinner.d.ts +1 -2
- package/dist/components/ui/switch.d.ts +2 -2
- package/dist/components/ui/switch.js +1 -1
- package/dist/components/ui/tabs.d.ts +29 -14
- package/dist/components/ui/tabs.js +1 -1
- package/dist/components/ui/toggle-group.d.ts +3 -3
- package/dist/components/ui/toggle-group.js +2 -2
- package/dist/components/ui/toggle.d.ts +2 -2
- package/dist/components/ui/toggle.js +1 -1
- package/dist/components/ui/toolbar.d.ts +104 -0
- package/dist/components/ui/toolbar.js +6 -0
- package/dist/components/ui/toolbar.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +46 -5
- package/dist/components/ui/tooltip.js +1 -1
- package/dist/components/ui/typography.d.ts +9 -10
- package/dist/components/ui/visually-hidden.d.ts +48 -0
- package/dist/components/ui/visually-hidden.js +4 -0
- package/dist/components/ui/visually-hidden.js.map +1 -0
- package/dist/dashboard-page-C0TihRl5.d.ts +107 -0
- package/dist/hooks/index.d.ts +2 -3
- package/dist/hooks/index.js +6 -6
- package/dist/hooks/use-keyboard-navigation.d.ts +58 -2
- package/dist/hooks/use-keyboard-navigation.js +1 -1
- package/dist/hooks/use-resource-page.d.ts +2 -3
- package/dist/hooks/use-resource-page.js +2 -2
- package/dist/hooks/use-view-preference.d.ts +2 -2
- package/dist/hooks/use-view-preference.js +1 -1
- package/dist/index.d.ts +22 -25
- package/dist/index.js +54 -38
- package/dist/spacing-BS6qECD4.d.ts +191 -0
- package/dist/split-Dk9f4Mi0.d.ts +57 -0
- package/dist/{use-resource-page-BXBv_Xah.d.ts → use-resource-page-DTQS011Q.d.ts} +18 -6
- package/dist/view-settings-kHKCHMjj.d.ts +12 -0
- package/dist/{ViewToggle-DDe_Luj2.d.ts → view-toggle-CahQ87PW.d.ts} +2 -2
- package/package.json +80 -39
- package/dist/chunk-2B3MFHBQ.js.map +0 -1
- package/dist/chunk-2MXMWBDV.js.map +0 -1
- package/dist/chunk-4V4H2ZM7.js.map +0 -1
- package/dist/chunk-5J7BP5DI.js.map +0 -1
- package/dist/chunk-5Q4FABZQ.js.map +0 -1
- package/dist/chunk-63FW5ZUA.js.map +0 -1
- package/dist/chunk-7OBL3H5P.js.map +0 -1
- package/dist/chunk-AUECDWP2.js.map +0 -1
- package/dist/chunk-C6H7AMO4.js.map +0 -1
- package/dist/chunk-EI5EGKHL.js +0 -32
- package/dist/chunk-EI5EGKHL.js.map +0 -1
- package/dist/chunk-IP6TMT3D.js.map +0 -1
- package/dist/chunk-JJ4NOMMI.js +0 -73
- package/dist/chunk-JJ4NOMMI.js.map +0 -1
- package/dist/chunk-JXI2MYL3.js.map +0 -1
- package/dist/chunk-KBS4BHME.js +0 -11
- package/dist/chunk-KBS4BHME.js.map +0 -1
- package/dist/chunk-LRXDZBV2.js +0 -26
- package/dist/chunk-LRXDZBV2.js.map +0 -1
- package/dist/chunk-NJMO3VPA.js.map +0 -1
- package/dist/chunk-OCTV3S4I.js +0 -29
- package/dist/chunk-OCTV3S4I.js.map +0 -1
- package/dist/chunk-QBZMY2AF.js.map +0 -1
- package/dist/chunk-QLCDAFS7.js.map +0 -1
- package/dist/chunk-SBJV3K4G.js.map +0 -1
- package/dist/chunk-SCUT2ZCD.js.map +0 -1
- package/dist/chunk-SVXDWPLO.js.map +0 -1
- package/dist/chunk-T465NJRL.js +0 -134
- package/dist/chunk-T465NJRL.js.map +0 -1
- package/dist/chunk-T5VX5DYO.js.map +0 -1
- package/dist/chunk-TKA4LOMT.js.map +0 -1
- package/dist/chunk-UGHQFQOE.js.map +0 -1
- package/dist/chunk-WALXVR6V.js +0 -9
- package/dist/chunk-WALXVR6V.js.map +0 -1
- package/dist/chunk-WZWR2ELB.js.map +0 -1
- package/dist/chunk-YZEA5TGK.js.map +0 -1
- package/dist/chunk-ZDAT5JDH.js.map +0 -1
- package/dist/chunk-ZJFSZFPI.js.map +0 -1
- package/dist/components/ui/empty-state.d.ts +0 -22
- /package/dist/components/{ui → patterns}/empty-state.js.map +0 -0
- /package/dist/components/{ui → patterns}/form-field.js.map +0 -0
|
@@ -1,473 +1,52 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { AppShell, PageHeader } from '../../chunk-FEJAZFP3.js';
|
|
3
|
+
export { ViewSettings, ViewToggle } from '../../chunk-46TZGMFW.js';
|
|
4
4
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../../chunk-N2ZFNOOT.js';
|
|
5
5
|
import { Textarea } from '../../chunk-YETMISCE.js';
|
|
6
|
-
import { Progress } from '../../chunk-W5Y3LG5K.js';
|
|
7
|
-
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../chunk-2B3MFHBQ.js';
|
|
8
6
|
import { Separator } from '../../chunk-SXSCHWZU.js';
|
|
9
|
-
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '../../chunk-
|
|
7
|
+
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '../../chunk-XCGZPFT7.js';
|
|
10
8
|
import { Skeleton } from '../../chunk-QFM4Z2SS.js';
|
|
9
|
+
import { Progress } from '../../chunk-W5Y3LG5K.js';
|
|
10
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuSeparator, DropdownMenuItem } from '../../chunk-QJ6P2DW6.js';
|
|
11
11
|
import { Input } from '../../chunk-QSXVL5UB.js';
|
|
12
|
-
import {
|
|
13
|
-
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuSeparator, DropdownMenuItem } from '../../chunk-SBJV3K4G.js';
|
|
14
|
-
import { FormField, FormLabel, FormError, FormDescription } from '../../chunk-IP6TMT3D.js';
|
|
15
|
-
import { Label } from '../../chunk-T5VX5DYO.js';
|
|
12
|
+
import { Checkbox } from '../../chunk-SEBU6JCK.js';
|
|
16
13
|
import { Card, CardContent, CardHeader, CardTitle } from '../../chunk-FN3FZVUR.js';
|
|
17
|
-
import
|
|
18
|
-
import { Collapsible, CollapsibleContent } from '../../chunk-KBS4BHME.js';
|
|
14
|
+
import '../../chunk-B2GIBUQD.js';
|
|
19
15
|
import { Badge } from '../../chunk-NPNADZHM.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
16
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../chunk-FK42ZGGV.js';
|
|
17
|
+
import { Popover, PopoverTrigger, PopoverContent } from '../../chunk-22XB3Q6H.js';
|
|
18
|
+
import { Switch } from '../../chunk-27ELYTGE.js';
|
|
19
|
+
import { EmptyState } from '../../chunk-65SPT7EA.js';
|
|
20
|
+
export { EmptyState } from '../../chunk-65SPT7EA.js';
|
|
21
|
+
import { Button } from '../../chunk-NWSCYLPT.js';
|
|
22
|
+
import { PageLoading } from '../../chunk-YRYQXU3G.js';
|
|
23
|
+
import { Spinner } from '../../chunk-OVU3Z2MT.js';
|
|
24
|
+
import { FormField, FormLabel, FormError, FormDescription } from '../../chunk-R7QFP6EL.js';
|
|
25
|
+
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-GDFNAHI4.js';
|
|
22
30
|
export { useSavedViews } from '../../chunk-GCQFVMPI.js';
|
|
23
|
-
import '../../chunk-
|
|
31
|
+
import '../../chunk-FTTNGGLA.js';
|
|
24
32
|
import { useViewSettings } from '../../chunk-OZ7ZAYCS.js';
|
|
25
|
-
export { CommandPalette, useCommandPaletteHotkey } from '../../chunk-
|
|
26
|
-
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from '../../chunk-
|
|
27
|
-
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '../../chunk-
|
|
33
|
+
export { CommandPalette, useCommandPaletteHotkey } from '../../chunk-CNTWQSUT.js';
|
|
34
|
+
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from '../../chunk-SEFK4NZV.js';
|
|
35
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '../../chunk-7XMZVISM.js';
|
|
28
36
|
import { cn } from '../../chunk-NZ5WBA4R.js';
|
|
29
|
-
import { DefaultLink, defaultNavigate
|
|
37
|
+
import { DefaultLink, defaultNavigate } from '../../chunk-6NPEMLBA.js';
|
|
30
38
|
export { DefaultLink, defaultNavigate, isPathActive } from '../../chunk-6NPEMLBA.js';
|
|
39
|
+
import { useKeyboardNavigation } from '../../chunk-YJ6MPS6U.js';
|
|
31
40
|
import { useIsMobile } from '../../chunk-M7AU5DDM.js';
|
|
32
|
-
import {
|
|
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';
|
|
33
42
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
34
|
-
import {
|
|
43
|
+
import { useState, useRef, useEffect, useCallback, useMemo, Fragment as Fragment$1 } from 'react';
|
|
35
44
|
import { formatDistanceToNow, format } from 'date-fns';
|
|
36
45
|
import { useFieldArray, Controller, useWatch } from 'react-hook-form';
|
|
37
|
-
import { useResource, useWizard, useResourceForm, buildArrayItemDefaults } from '@marktiderman/genesis-core/hooks';
|
|
46
|
+
import { useResource, useWizard, useResourceForm, useOne, buildArrayItemDefaults } from '@marktiderman/genesis-core/hooks';
|
|
38
47
|
import { useDataProvider } from '@marktiderman/genesis-core/provider';
|
|
39
48
|
import { useDropzone } from 'react-dropzone';
|
|
40
49
|
|
|
41
|
-
function EmptyState({
|
|
42
|
-
icon: Icon = Search,
|
|
43
|
-
message = "No items found",
|
|
44
|
-
action,
|
|
45
|
-
hasFilters = false,
|
|
46
|
-
onClearFilters
|
|
47
|
-
}) {
|
|
48
|
-
return /* @__PURE__ */ jsxs("div", { className: "text-center py-16 animate-fade-in", children: [
|
|
49
|
-
/* @__PURE__ */ jsx(Icon, { className: "h-10 w-10 text-muted-foreground/30 mx-auto mb-3" }),
|
|
50
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: hasFilters ? "No results match your filters" : message }),
|
|
51
|
-
hasFilters && onClearFilters ? /* @__PURE__ */ jsx(Button, { variant: "link", size: "sm", onClick: onClearFilters, className: "mt-2", children: "Clear all filters" }) : action && /* @__PURE__ */ jsx("div", { className: "mt-4", children: action })
|
|
52
|
-
] });
|
|
53
|
-
}
|
|
54
|
-
function ViewToggle({ viewMode, onViewModeChange }) {
|
|
55
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center border rounded-lg overflow-hidden", children: [
|
|
56
|
-
/* @__PURE__ */ jsx(
|
|
57
|
-
Button,
|
|
58
|
-
{
|
|
59
|
-
variant: viewMode === "grid" ? "default" : "ghost",
|
|
60
|
-
size: "icon",
|
|
61
|
-
className: "h-8 w-8 rounded-none",
|
|
62
|
-
onClick: () => onViewModeChange("grid"),
|
|
63
|
-
title: "Grid view",
|
|
64
|
-
children: /* @__PURE__ */ jsx(LayoutGrid, { className: "h-4 w-4" })
|
|
65
|
-
}
|
|
66
|
-
),
|
|
67
|
-
/* @__PURE__ */ jsx(
|
|
68
|
-
Button,
|
|
69
|
-
{
|
|
70
|
-
variant: viewMode === "table" ? "default" : "ghost",
|
|
71
|
-
size: "icon",
|
|
72
|
-
className: "h-8 w-8 rounded-none",
|
|
73
|
-
onClick: () => onViewModeChange("table"),
|
|
74
|
-
title: "Table view",
|
|
75
|
-
children: /* @__PURE__ */ jsx(Table2, { className: "h-4 w-4" })
|
|
76
|
-
}
|
|
77
|
-
),
|
|
78
|
-
/* @__PURE__ */ jsx(
|
|
79
|
-
Button,
|
|
80
|
-
{
|
|
81
|
-
variant: viewMode === "list" ? "default" : "ghost",
|
|
82
|
-
size: "icon",
|
|
83
|
-
className: "h-8 w-8 rounded-none",
|
|
84
|
-
onClick: () => onViewModeChange("list"),
|
|
85
|
-
title: "List view",
|
|
86
|
-
children: /* @__PURE__ */ jsx(List, { className: "h-4 w-4" })
|
|
87
|
-
}
|
|
88
|
-
)
|
|
89
|
-
] });
|
|
90
|
-
}
|
|
91
|
-
var PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
|
|
92
|
-
var DENSITY_OPTIONS = [
|
|
93
|
-
{ value: "compact", label: "Compact" },
|
|
94
|
-
{ value: "comfortable", label: "Comfortable" },
|
|
95
|
-
{ value: "spacious", label: "Spacious" }
|
|
96
|
-
];
|
|
97
|
-
function ViewSettings({
|
|
98
|
-
pageSize,
|
|
99
|
-
onPageSizeChange,
|
|
100
|
-
density,
|
|
101
|
-
onDensityChange
|
|
102
|
-
}) {
|
|
103
|
-
return /* @__PURE__ */ jsxs(Popover, { children: [
|
|
104
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
105
|
-
Button,
|
|
106
|
-
{
|
|
107
|
-
variant: "ghost",
|
|
108
|
-
size: "icon",
|
|
109
|
-
className: "h-8 w-8",
|
|
110
|
-
title: "View settings",
|
|
111
|
-
children: /* @__PURE__ */ jsx(Settings2, { className: "h-4 w-4" })
|
|
112
|
-
}
|
|
113
|
-
) }),
|
|
114
|
-
/* @__PURE__ */ jsxs(PopoverContent, { align: "end", className: "w-56 space-y-4", children: [
|
|
115
|
-
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Display Settings" }),
|
|
116
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
117
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground", children: "Page size" }),
|
|
118
|
-
/* @__PURE__ */ jsxs(
|
|
119
|
-
Select,
|
|
120
|
-
{
|
|
121
|
-
value: String(pageSize),
|
|
122
|
-
onValueChange: (v) => onPageSizeChange(Number(v)),
|
|
123
|
-
children: [
|
|
124
|
-
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
125
|
-
/* @__PURE__ */ jsx(SelectContent, { className: "bg-popover z-50", children: PAGE_SIZE_OPTIONS.map((n) => /* @__PURE__ */ jsxs(SelectItem, { value: String(n), children: [
|
|
126
|
-
n,
|
|
127
|
-
" items"
|
|
128
|
-
] }, n)) })
|
|
129
|
-
]
|
|
130
|
-
}
|
|
131
|
-
)
|
|
132
|
-
] }),
|
|
133
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
134
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs text-muted-foreground", children: "Density" }),
|
|
135
|
-
/* @__PURE__ */ jsxs(
|
|
136
|
-
Select,
|
|
137
|
-
{
|
|
138
|
-
value: density,
|
|
139
|
-
onValueChange: (v) => onDensityChange(v),
|
|
140
|
-
children: [
|
|
141
|
-
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
142
|
-
/* @__PURE__ */ jsx(SelectContent, { className: "bg-popover z-50", children: DENSITY_OPTIONS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)) })
|
|
143
|
-
]
|
|
144
|
-
}
|
|
145
|
-
)
|
|
146
|
-
] })
|
|
147
|
-
] })
|
|
148
|
-
] });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/option-storage.ts
|
|
152
|
-
function readStoredOptions(key) {
|
|
153
|
-
if (typeof window === "undefined") return {};
|
|
154
|
-
try {
|
|
155
|
-
const raw = localStorage.getItem(key);
|
|
156
|
-
if (!raw) return {};
|
|
157
|
-
const parsed = JSON.parse(raw);
|
|
158
|
-
if (!parsed || typeof parsed !== "object") return {};
|
|
159
|
-
return parsed;
|
|
160
|
-
} catch {
|
|
161
|
-
return {};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function writeStoredOptions(key, value) {
|
|
165
|
-
if (typeof window === "undefined") return;
|
|
166
|
-
try {
|
|
167
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
168
|
-
} catch {
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function pluralizeEntity(entity, count) {
|
|
172
|
-
if (count === 1) return entity;
|
|
173
|
-
return entity.endsWith("s") ? entity : `${entity}s`;
|
|
174
|
-
}
|
|
175
|
-
var OPTION_DEFAULTS = {
|
|
176
|
-
showIcon: true,
|
|
177
|
-
showSubtitle: true,
|
|
178
|
-
showCount: true,
|
|
179
|
-
showViewToggle: true,
|
|
180
|
-
showViewSettings: true,
|
|
181
|
-
showCreate: true,
|
|
182
|
-
showDetailsToggle: true,
|
|
183
|
-
showDetailsHint: true,
|
|
184
|
-
subtitleInDetails: void 0,
|
|
185
|
-
defaultDetailsOpen: false,
|
|
186
|
-
detailsLabel: "Details",
|
|
187
|
-
configurable: void 0
|
|
188
|
-
};
|
|
189
|
-
var BOOLEAN_OPTION_KEYS = [
|
|
190
|
-
"showIcon",
|
|
191
|
-
"showSubtitle",
|
|
192
|
-
"showCount",
|
|
193
|
-
"showViewToggle",
|
|
194
|
-
"showViewSettings",
|
|
195
|
-
"showCreate",
|
|
196
|
-
"showDetailsToggle",
|
|
197
|
-
"showDetailsHint",
|
|
198
|
-
"subtitleInDetails",
|
|
199
|
-
"defaultDetailsOpen",
|
|
200
|
-
"configurable"
|
|
201
|
-
];
|
|
202
|
-
var STRING_OPTION_KEYS = ["detailsLabel"];
|
|
203
|
-
function readStoredOptions2(key) {
|
|
204
|
-
const raw = readStoredOptions(key);
|
|
205
|
-
const sanitized = {};
|
|
206
|
-
for (const optKey of BOOLEAN_OPTION_KEYS) {
|
|
207
|
-
const value = raw[optKey];
|
|
208
|
-
if (typeof value === "boolean") {
|
|
209
|
-
sanitized[optKey] = value;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
for (const optKey of STRING_OPTION_KEYS) {
|
|
213
|
-
const value = raw[optKey];
|
|
214
|
-
if (typeof value === "string") {
|
|
215
|
-
sanitized[optKey] = value;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return sanitized;
|
|
219
|
-
}
|
|
220
|
-
function PageHeader({
|
|
221
|
-
title,
|
|
222
|
-
subtitle,
|
|
223
|
-
icon: Icon,
|
|
224
|
-
options: optionsProp,
|
|
225
|
-
optionsStorageKey,
|
|
226
|
-
actions,
|
|
227
|
-
details,
|
|
228
|
-
detailsOpen,
|
|
229
|
-
onDetailsOpenChange,
|
|
230
|
-
detailsActive = false,
|
|
231
|
-
detailsHint,
|
|
232
|
-
count,
|
|
233
|
-
totalCount,
|
|
234
|
-
entityName,
|
|
235
|
-
countActive = false,
|
|
236
|
-
viewMode,
|
|
237
|
-
onViewModeChange,
|
|
238
|
-
pageSize,
|
|
239
|
-
onPageSizeChange,
|
|
240
|
-
density,
|
|
241
|
-
onDensityChange,
|
|
242
|
-
createAction
|
|
243
|
-
}) {
|
|
244
|
-
const detailsRegionId = useId();
|
|
245
|
-
const hasDetails = details != null;
|
|
246
|
-
const hasCount = count !== void 0 && totalCount !== void 0;
|
|
247
|
-
const hasViewToggle = Boolean(viewMode && onViewModeChange);
|
|
248
|
-
const hasViewSettings = Boolean(onPageSizeChange && onDensityChange);
|
|
249
|
-
const hasCreate = createAction != null;
|
|
250
|
-
const [userOverrides, setUserOverrides] = useState(
|
|
251
|
-
{}
|
|
252
|
-
);
|
|
253
|
-
const [hydratedKey, setHydratedKey] = useState(
|
|
254
|
-
optionsStorageKey ? void 0 : ""
|
|
255
|
-
);
|
|
256
|
-
useEffect(() => {
|
|
257
|
-
if (!optionsStorageKey) {
|
|
258
|
-
setUserOverrides({});
|
|
259
|
-
setHydratedKey("");
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
setUserOverrides(readStoredOptions2(optionsStorageKey));
|
|
263
|
-
setHydratedKey(optionsStorageKey);
|
|
264
|
-
}, [optionsStorageKey]);
|
|
265
|
-
useEffect(() => {
|
|
266
|
-
if (!optionsStorageKey || hydratedKey !== optionsStorageKey) return;
|
|
267
|
-
writeStoredOptions(optionsStorageKey, userOverrides);
|
|
268
|
-
}, [optionsStorageKey, userOverrides, hydratedKey]);
|
|
269
|
-
const resolved = useMemo(() => {
|
|
270
|
-
const merged = {
|
|
271
|
-
...OPTION_DEFAULTS,
|
|
272
|
-
...optionsProp,
|
|
273
|
-
...userOverrides
|
|
274
|
-
};
|
|
275
|
-
if (merged.subtitleInDetails === void 0) {
|
|
276
|
-
merged.subtitleInDetails = hasDetails;
|
|
277
|
-
}
|
|
278
|
-
if (merged.configurable === void 0) {
|
|
279
|
-
merged.configurable = hasDetails || hasCount || hasViewSettings || hasViewToggle;
|
|
280
|
-
}
|
|
281
|
-
return merged;
|
|
282
|
-
}, [
|
|
283
|
-
optionsProp,
|
|
284
|
-
userOverrides,
|
|
285
|
-
hasDetails,
|
|
286
|
-
hasCount,
|
|
287
|
-
hasViewSettings,
|
|
288
|
-
hasViewToggle
|
|
289
|
-
]);
|
|
290
|
-
const patchOption = useCallback((key, value) => {
|
|
291
|
-
setUserOverrides((prev) => ({ ...prev, [key]: value }));
|
|
292
|
-
}, []);
|
|
293
|
-
const moveSubtitle = Boolean(resolved.subtitleInDetails) && hasDetails;
|
|
294
|
-
const showTitleSubtitle = Boolean(subtitle) && Boolean(resolved.showSubtitle) && !moveSubtitle;
|
|
295
|
-
const [uncontrolledOpen, setUncontrolledOpen] = useState(
|
|
296
|
-
() => optionsProp?.defaultDetailsOpen ?? OPTION_DEFAULTS.defaultDetailsOpen
|
|
297
|
-
);
|
|
298
|
-
const isControlled = detailsOpen !== void 0;
|
|
299
|
-
const open = isControlled ? detailsOpen : uncontrolledOpen;
|
|
300
|
-
const setOpen = (next) => {
|
|
301
|
-
if (!isControlled) setUncontrolledOpen(next);
|
|
302
|
-
onDetailsOpenChange?.(next);
|
|
303
|
-
};
|
|
304
|
-
const detailsLabel = resolved.detailsLabel ?? "Details";
|
|
305
|
-
const entity = entityName || "item";
|
|
306
|
-
const toggles = [
|
|
307
|
-
{ key: "showIcon", label: "Icon", available: Boolean(Icon) },
|
|
308
|
-
{
|
|
309
|
-
key: "showSubtitle",
|
|
310
|
-
label: "Subtitle",
|
|
311
|
-
available: Boolean(subtitle) && !moveSubtitle
|
|
312
|
-
},
|
|
313
|
-
{ key: "showCount", label: "Count", available: hasCount },
|
|
314
|
-
{ key: "showViewToggle", label: "View toggle", available: hasViewToggle },
|
|
315
|
-
{
|
|
316
|
-
key: "showViewSettings",
|
|
317
|
-
label: "Display settings",
|
|
318
|
-
available: hasViewSettings
|
|
319
|
-
},
|
|
320
|
-
{ key: "showCreate", label: "Create action", available: hasCreate },
|
|
321
|
-
{
|
|
322
|
-
key: "showDetailsToggle",
|
|
323
|
-
label: "Filters / details",
|
|
324
|
-
available: hasDetails
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
key: "showDetailsHint",
|
|
328
|
-
label: "Collapsed hint",
|
|
329
|
-
available: hasDetails && detailsHint != null
|
|
330
|
-
}
|
|
331
|
-
].filter((t) => t.available);
|
|
332
|
-
const showDetailsToggle = hasDetails && Boolean(resolved.showDetailsToggle);
|
|
333
|
-
const showHint = hasDetails && !open && Boolean(resolved.showDetailsHint) && detailsHint != null;
|
|
334
|
-
const actionsCluster = /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
|
|
335
|
-
showHint ? /* @__PURE__ */ jsx("span", { className: "hidden max-w-[14rem] truncate text-xs text-muted-foreground sm:inline", children: detailsHint }) : null,
|
|
336
|
-
hasCount && resolved.showCount !== false ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: countActive ? `${count} of ${totalCount}` : `${totalCount} ${pluralizeEntity(entity, totalCount)}` }) : null,
|
|
337
|
-
hasViewToggle && resolved.showViewToggle !== false ? /* @__PURE__ */ jsx(ViewToggle, { viewMode, onViewModeChange }) : null,
|
|
338
|
-
showDetailsToggle ? /* @__PURE__ */ jsxs(
|
|
339
|
-
Button,
|
|
340
|
-
{
|
|
341
|
-
type: "button",
|
|
342
|
-
variant: "ghost",
|
|
343
|
-
size: "icon",
|
|
344
|
-
className: cn(
|
|
345
|
-
"relative h-8 w-8",
|
|
346
|
-
(open || detailsActive) && "bg-accent text-accent-foreground"
|
|
347
|
-
),
|
|
348
|
-
onClick: () => setOpen(!open),
|
|
349
|
-
"data-testid": "page-header-details-toggle",
|
|
350
|
-
title: open ? `Hide ${detailsLabel}` : `Show ${detailsLabel}`,
|
|
351
|
-
"aria-label": open ? `Hide ${detailsLabel}` : `Show ${detailsLabel}`,
|
|
352
|
-
"aria-expanded": open,
|
|
353
|
-
"aria-controls": detailsRegionId,
|
|
354
|
-
testID: "page-header-details-toggle",
|
|
355
|
-
children: [
|
|
356
|
-
/* @__PURE__ */ jsx(ListFilter, { className: "h-4 w-4" }),
|
|
357
|
-
detailsActive ? /* @__PURE__ */ jsx(
|
|
358
|
-
"span",
|
|
359
|
-
{
|
|
360
|
-
className: "absolute right-1.5 top-1.5 size-1.5 rounded-full bg-primary",
|
|
361
|
-
"aria-hidden": true
|
|
362
|
-
}
|
|
363
|
-
) : null
|
|
364
|
-
]
|
|
365
|
-
}
|
|
366
|
-
) : null,
|
|
367
|
-
hasViewSettings && resolved.showViewSettings !== false ? /* @__PURE__ */ jsx(
|
|
368
|
-
ViewSettings,
|
|
369
|
-
{
|
|
370
|
-
pageSize: pageSize ?? 25,
|
|
371
|
-
onPageSizeChange,
|
|
372
|
-
density: density ?? "comfortable",
|
|
373
|
-
onDensityChange
|
|
374
|
-
}
|
|
375
|
-
) : null,
|
|
376
|
-
hasCreate && resolved.showCreate !== false ? createAction : null,
|
|
377
|
-
actions,
|
|
378
|
-
resolved.configurable && toggles.length > 0 ? /* @__PURE__ */ jsxs(Popover, { children: [
|
|
379
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
380
|
-
Button,
|
|
381
|
-
{
|
|
382
|
-
type: "button",
|
|
383
|
-
variant: "ghost",
|
|
384
|
-
size: "icon",
|
|
385
|
-
className: "h-8 w-8",
|
|
386
|
-
title: "Header options",
|
|
387
|
-
"aria-label": "Header options",
|
|
388
|
-
"data-testid": "page-header-options",
|
|
389
|
-
testID: "page-header-options",
|
|
390
|
-
children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4" })
|
|
391
|
-
}
|
|
392
|
-
) }),
|
|
393
|
-
/* @__PURE__ */ jsxs(PopoverContent, { align: "end", className: "w-64 space-y-3", children: [
|
|
394
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
395
|
-
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Header options" }),
|
|
396
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Customize this page header. Saved on this device when a storage key is set." })
|
|
397
|
-
] }),
|
|
398
|
-
/* @__PURE__ */ jsx("ul", { className: "space-y-3", children: toggles.map((t) => {
|
|
399
|
-
const checked = Boolean(resolved[t.key] ?? true);
|
|
400
|
-
return /* @__PURE__ */ jsxs(
|
|
401
|
-
"li",
|
|
402
|
-
{
|
|
403
|
-
className: "flex items-center justify-between gap-3",
|
|
404
|
-
children: [
|
|
405
|
-
/* @__PURE__ */ jsx(
|
|
406
|
-
Label,
|
|
407
|
-
{
|
|
408
|
-
htmlFor: `page-header-opt-${t.key}`,
|
|
409
|
-
className: "text-sm font-normal",
|
|
410
|
-
children: t.label
|
|
411
|
-
}
|
|
412
|
-
),
|
|
413
|
-
/* @__PURE__ */ jsx(
|
|
414
|
-
Switch,
|
|
415
|
-
{
|
|
416
|
-
id: `page-header-opt-${t.key}`,
|
|
417
|
-
checked,
|
|
418
|
-
onCheckedChange: (v) => patchOption(t.key, v)
|
|
419
|
-
}
|
|
420
|
-
)
|
|
421
|
-
]
|
|
422
|
-
},
|
|
423
|
-
t.key
|
|
424
|
-
);
|
|
425
|
-
}) }),
|
|
426
|
-
optionsStorageKey && Object.keys(userOverrides).length > 0 ? /* @__PURE__ */ jsx(
|
|
427
|
-
Button,
|
|
428
|
-
{
|
|
429
|
-
type: "button",
|
|
430
|
-
variant: "ghost",
|
|
431
|
-
size: "sm",
|
|
432
|
-
className: "h-8 w-full text-xs",
|
|
433
|
-
onClick: () => setUserOverrides({}),
|
|
434
|
-
"data-testid": "page-header-options-reset",
|
|
435
|
-
"aria-label": "Reset header options",
|
|
436
|
-
testID: "page-header-options-reset",
|
|
437
|
-
children: "Reset to defaults"
|
|
438
|
-
}
|
|
439
|
-
) : null
|
|
440
|
-
] })
|
|
441
|
-
] }) : null
|
|
442
|
-
] });
|
|
443
|
-
const titleRow = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
444
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
445
|
-
Icon && resolved.showIcon !== false ? /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-primary/10", children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-primary" }) }) : null,
|
|
446
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
447
|
-
/* @__PURE__ */ jsx(
|
|
448
|
-
"h1",
|
|
449
|
-
{
|
|
450
|
-
"data-testid": "page-title",
|
|
451
|
-
className: "truncate font-display text-xl font-bold tracking-tight sm:text-2xl",
|
|
452
|
-
children: title
|
|
453
|
-
}
|
|
454
|
-
),
|
|
455
|
-
showTitleSubtitle ? /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-muted-foreground", children: subtitle }) : null
|
|
456
|
-
] })
|
|
457
|
-
] }),
|
|
458
|
-
actionsCluster
|
|
459
|
-
] });
|
|
460
|
-
if (!hasDetails) {
|
|
461
|
-
return titleRow;
|
|
462
|
-
}
|
|
463
|
-
return /* @__PURE__ */ jsxs(Collapsible, { open, onOpenChange: setOpen, children: [
|
|
464
|
-
titleRow,
|
|
465
|
-
/* @__PURE__ */ jsx(CollapsibleContent, { id: detailsRegionId, className: "mt-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-lg border border-border bg-card/40 p-3 sm:p-4", children: [
|
|
466
|
-
moveSubtitle && subtitle && resolved.showSubtitle !== false ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle }) : null,
|
|
467
|
-
details
|
|
468
|
-
] }) })
|
|
469
|
-
] });
|
|
470
|
-
}
|
|
471
50
|
function DataPageShell({
|
|
472
51
|
title,
|
|
473
52
|
icon,
|
|
@@ -570,7 +149,7 @@ function DataPageShell({
|
|
|
570
149
|
EmptyState,
|
|
571
150
|
{
|
|
572
151
|
icon: emptyIcon,
|
|
573
|
-
|
|
152
|
+
title: emptyMessage,
|
|
574
153
|
action: emptyAction,
|
|
575
154
|
hasFilters: hasActiveFilters,
|
|
576
155
|
onClearFilters
|
|
@@ -947,14 +526,25 @@ function DataGrid({
|
|
|
947
526
|
}
|
|
948
527
|
if (viewMode === "list" && renderListItem) {
|
|
949
528
|
const keyFnList = getKey || ((item) => item.id);
|
|
950
|
-
return /* @__PURE__ */ jsx(
|
|
529
|
+
return /* @__PURE__ */ jsx(
|
|
951
530
|
"div",
|
|
952
531
|
{
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
532
|
+
ref: keyboardContainerRef,
|
|
533
|
+
className: "divide-y divide-border rounded-lg border",
|
|
534
|
+
children: items.map((item, i) => /* @__PURE__ */ jsx(
|
|
535
|
+
"div",
|
|
536
|
+
{
|
|
537
|
+
"data-nav-item": true,
|
|
538
|
+
className: cn(
|
|
539
|
+
"px-4 py-3 transition-colors hover:bg-accent/50",
|
|
540
|
+
focusedIndex === i && "ring-2 ring-inset ring-primary bg-accent/50"
|
|
541
|
+
),
|
|
542
|
+
children: renderListItem(item, i)
|
|
543
|
+
},
|
|
544
|
+
keyFnList(item)
|
|
545
|
+
))
|
|
546
|
+
}
|
|
547
|
+
);
|
|
958
548
|
}
|
|
959
549
|
const visible = items.slice(0, visibleCount);
|
|
960
550
|
const keyFn = getKey || ((item) => item.id);
|
|
@@ -1731,6 +1321,11 @@ var widthClasses = {
|
|
|
1731
1321
|
md: "w-96",
|
|
1732
1322
|
lg: "w-[480px]"
|
|
1733
1323
|
};
|
|
1324
|
+
var dialogMaxWidthClasses = {
|
|
1325
|
+
sm: "sm:max-w-sm",
|
|
1326
|
+
md: "sm:max-w-lg",
|
|
1327
|
+
lg: "sm:max-w-2xl"
|
|
1328
|
+
};
|
|
1734
1329
|
function keyToLabel(key) {
|
|
1735
1330
|
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1736
1331
|
}
|
|
@@ -1741,6 +1336,37 @@ function formatValue(value) {
|
|
|
1741
1336
|
if (typeof value === "object") return JSON.stringify(value);
|
|
1742
1337
|
return String(value);
|
|
1743
1338
|
}
|
|
1339
|
+
function renderTitleBlock(layout, title, subtitle) {
|
|
1340
|
+
const titleText = title || "Detail panel";
|
|
1341
|
+
if (layout === "dialog") {
|
|
1342
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1343
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: cn("text-sm font-semibold truncate", !title && "sr-only"), children: titleText }),
|
|
1344
|
+
/* @__PURE__ */ jsx(
|
|
1345
|
+
DialogDescription,
|
|
1346
|
+
{
|
|
1347
|
+
className: cn("text-xs text-muted-foreground truncate", !subtitle && "sr-only"),
|
|
1348
|
+
children: subtitle || titleText
|
|
1349
|
+
}
|
|
1350
|
+
)
|
|
1351
|
+
] });
|
|
1352
|
+
}
|
|
1353
|
+
if (layout === "sheet") {
|
|
1354
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1355
|
+
/* @__PURE__ */ jsx(SheetTitle, { className: cn("text-sm font-semibold truncate", !title && "sr-only"), children: titleText }),
|
|
1356
|
+
/* @__PURE__ */ jsx(
|
|
1357
|
+
SheetDescription,
|
|
1358
|
+
{
|
|
1359
|
+
className: cn("text-xs text-muted-foreground truncate", !subtitle && "sr-only"),
|
|
1360
|
+
children: subtitle || titleText
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
] });
|
|
1364
|
+
}
|
|
1365
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1366
|
+
title && /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold truncate", children: title }),
|
|
1367
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: subtitle })
|
|
1368
|
+
] });
|
|
1369
|
+
}
|
|
1744
1370
|
function DetailPanel({
|
|
1745
1371
|
item,
|
|
1746
1372
|
open,
|
|
@@ -1751,7 +1377,8 @@ function DetailPanel({
|
|
|
1751
1377
|
onDelete,
|
|
1752
1378
|
children,
|
|
1753
1379
|
fields,
|
|
1754
|
-
width = "md"
|
|
1380
|
+
width = "md",
|
|
1381
|
+
layout = "sheet"
|
|
1755
1382
|
}) {
|
|
1756
1383
|
if (!open || !item) return null;
|
|
1757
1384
|
const renderContent = () => {
|
|
@@ -1776,78 +1403,114 @@ function DetailPanel({
|
|
|
1776
1403
|
] })
|
|
1777
1404
|
] }, key)) });
|
|
1778
1405
|
};
|
|
1779
|
-
|
|
1780
|
-
/* @__PURE__ */ jsx(
|
|
1781
|
-
|
|
1406
|
+
const header = /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-border px-4 py-3", children: [
|
|
1407
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: renderTitleBlock(layout, title, subtitle) }),
|
|
1408
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
1409
|
+
onEdit && /* @__PURE__ */ jsx(
|
|
1410
|
+
Button,
|
|
1411
|
+
{
|
|
1412
|
+
testID: "detail-panel-edit",
|
|
1413
|
+
variant: "ghost",
|
|
1414
|
+
size: "icon",
|
|
1415
|
+
className: "h-8 w-8",
|
|
1416
|
+
onClick: () => onEdit(item),
|
|
1417
|
+
"aria-label": "Edit",
|
|
1418
|
+
children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
|
|
1419
|
+
}
|
|
1420
|
+
),
|
|
1421
|
+
onDelete && /* @__PURE__ */ jsx(
|
|
1422
|
+
Button,
|
|
1423
|
+
{
|
|
1424
|
+
testID: "detail-panel-delete",
|
|
1425
|
+
variant: "ghost",
|
|
1426
|
+
size: "icon",
|
|
1427
|
+
className: "h-8 w-8 text-destructive hover:text-destructive",
|
|
1428
|
+
onClick: () => onDelete(item),
|
|
1429
|
+
"aria-label": "Delete",
|
|
1430
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
1431
|
+
}
|
|
1432
|
+
),
|
|
1433
|
+
/* @__PURE__ */ jsx(
|
|
1434
|
+
Button,
|
|
1435
|
+
{
|
|
1436
|
+
testID: "detail-panel-close",
|
|
1437
|
+
variant: "ghost",
|
|
1438
|
+
size: "icon",
|
|
1439
|
+
className: "h-8 w-8",
|
|
1440
|
+
onClick: onClose,
|
|
1441
|
+
"aria-label": "Close",
|
|
1442
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
1443
|
+
}
|
|
1444
|
+
)
|
|
1445
|
+
] })
|
|
1446
|
+
] });
|
|
1447
|
+
const content = /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-4 py-3", children: renderContent() });
|
|
1448
|
+
if (layout === "dialog") {
|
|
1449
|
+
return /* @__PURE__ */ jsx(
|
|
1450
|
+
Dialog,
|
|
1782
1451
|
{
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1452
|
+
open,
|
|
1453
|
+
onOpenChange: (next) => {
|
|
1454
|
+
if (!next) onClose();
|
|
1455
|
+
},
|
|
1456
|
+
children: /* @__PURE__ */ jsxs(
|
|
1457
|
+
DialogContent,
|
|
1458
|
+
{
|
|
1459
|
+
showCloseButton: false,
|
|
1460
|
+
className: cn(
|
|
1461
|
+
"flex max-h-[85vh] flex-col gap-0 overflow-hidden p-0",
|
|
1462
|
+
dialogMaxWidthClasses[width]
|
|
1463
|
+
),
|
|
1464
|
+
children: [
|
|
1465
|
+
header,
|
|
1466
|
+
content
|
|
1467
|
+
]
|
|
1468
|
+
}
|
|
1469
|
+
)
|
|
1786
1470
|
}
|
|
1787
|
-
)
|
|
1788
|
-
|
|
1789
|
-
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
if (layout === "sheet") {
|
|
1474
|
+
return /* @__PURE__ */ jsx(
|
|
1475
|
+
Sheet,
|
|
1790
1476
|
{
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
if (e.key === "Escape") onClose();
|
|
1477
|
+
open,
|
|
1478
|
+
onOpenChange: (next) => {
|
|
1479
|
+
if (!next) onClose();
|
|
1795
1480
|
},
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
onEdit && /* @__PURE__ */ jsx(
|
|
1812
|
-
Button,
|
|
1813
|
-
{
|
|
1814
|
-
variant: "ghost",
|
|
1815
|
-
size: "icon",
|
|
1816
|
-
className: "h-8 w-8",
|
|
1817
|
-
onClick: () => onEdit(item),
|
|
1818
|
-
"aria-label": "Edit",
|
|
1819
|
-
children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
|
|
1820
|
-
}
|
|
1821
|
-
),
|
|
1822
|
-
onDelete && /* @__PURE__ */ jsx(
|
|
1823
|
-
Button,
|
|
1824
|
-
{
|
|
1825
|
-
variant: "ghost",
|
|
1826
|
-
size: "icon",
|
|
1827
|
-
className: "h-8 w-8 text-destructive hover:text-destructive",
|
|
1828
|
-
onClick: () => onDelete(item),
|
|
1829
|
-
"aria-label": "Delete",
|
|
1830
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
1831
|
-
}
|
|
1832
|
-
),
|
|
1833
|
-
/* @__PURE__ */ jsx(
|
|
1834
|
-
Button,
|
|
1835
|
-
{
|
|
1836
|
-
variant: "ghost",
|
|
1837
|
-
size: "icon",
|
|
1838
|
-
className: "h-8 w-8",
|
|
1839
|
-
onClick: onClose,
|
|
1840
|
-
"aria-label": "Close",
|
|
1841
|
-
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
1842
|
-
}
|
|
1843
|
-
)
|
|
1844
|
-
] })
|
|
1845
|
-
] }),
|
|
1846
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-4 py-3", children: renderContent() })
|
|
1847
|
-
]
|
|
1481
|
+
children: /* @__PURE__ */ jsxs(
|
|
1482
|
+
SheetContent,
|
|
1483
|
+
{
|
|
1484
|
+
side: "right",
|
|
1485
|
+
showCloseButton: false,
|
|
1486
|
+
className: cn(
|
|
1487
|
+
"flex flex-col gap-0 overflow-hidden p-0 max-w-[90vw] sm:max-w-[90vw]",
|
|
1488
|
+
widthClasses[width]
|
|
1489
|
+
),
|
|
1490
|
+
children: [
|
|
1491
|
+
header,
|
|
1492
|
+
content
|
|
1493
|
+
]
|
|
1494
|
+
}
|
|
1495
|
+
)
|
|
1848
1496
|
}
|
|
1849
|
-
)
|
|
1850
|
-
|
|
1497
|
+
);
|
|
1498
|
+
}
|
|
1499
|
+
return /* @__PURE__ */ jsxs(
|
|
1500
|
+
"div",
|
|
1501
|
+
{
|
|
1502
|
+
role: "region",
|
|
1503
|
+
"aria-label": title || "Detail panel",
|
|
1504
|
+
className: cn(
|
|
1505
|
+
"flex flex-col rounded-lg border border-border bg-card",
|
|
1506
|
+
widthClasses[width]
|
|
1507
|
+
),
|
|
1508
|
+
children: [
|
|
1509
|
+
header,
|
|
1510
|
+
content
|
|
1511
|
+
]
|
|
1512
|
+
}
|
|
1513
|
+
);
|
|
1851
1514
|
}
|
|
1852
1515
|
function RelationField({
|
|
1853
1516
|
field,
|
|
@@ -2761,6 +2424,24 @@ function ResourcePage(props) {
|
|
|
2761
2424
|
searchPlaceholder,
|
|
2762
2425
|
initialFilters,
|
|
2763
2426
|
onFiltersChange,
|
|
2427
|
+
page: pageProp,
|
|
2428
|
+
perPage: perPageProp,
|
|
2429
|
+
onPageChange,
|
|
2430
|
+
onPerPageChange,
|
|
2431
|
+
onSortChange,
|
|
2432
|
+
onSearchChange,
|
|
2433
|
+
savedViews,
|
|
2434
|
+
onLoadView,
|
|
2435
|
+
onSaveView,
|
|
2436
|
+
onDeleteView,
|
|
2437
|
+
canSaveViews,
|
|
2438
|
+
columnVisibility,
|
|
2439
|
+
columnVisibilityKey,
|
|
2440
|
+
resizableColumns,
|
|
2441
|
+
resizeKey,
|
|
2442
|
+
stickyHeader,
|
|
2443
|
+
stickyFirstColumn,
|
|
2444
|
+
pageSizeOptions,
|
|
2764
2445
|
onCreate,
|
|
2765
2446
|
onEdit,
|
|
2766
2447
|
onDelete,
|
|
@@ -2773,6 +2454,9 @@ function ResourcePage(props) {
|
|
|
2773
2454
|
formSteps,
|
|
2774
2455
|
formLayout: formLayoutProp,
|
|
2775
2456
|
bulkActions,
|
|
2457
|
+
renderCard: renderCardProp,
|
|
2458
|
+
gridCols: gridColsProp,
|
|
2459
|
+
keyboardNavigation = true,
|
|
2776
2460
|
toolbar,
|
|
2777
2461
|
emptyState,
|
|
2778
2462
|
resourceOptions,
|
|
@@ -2781,8 +2465,10 @@ function ResourcePage(props) {
|
|
|
2781
2465
|
viewSettingsKey: viewSettingsKeyProp
|
|
2782
2466
|
} = props;
|
|
2783
2467
|
const isClientMode = !!resourceName;
|
|
2468
|
+
const isServerControlled = pageProp !== void 0 || perPageProp !== void 0 || onPageChange !== void 0 || onPerPageChange !== void 0 || onSortChange !== void 0 || onSearchChange !== void 0;
|
|
2784
2469
|
const viewSettingsKey = viewSettingsKeyProp ?? resourceName ?? title.toLowerCase().replace(/\s+/g, "-");
|
|
2785
2470
|
const { settings, updateSetting } = useViewSettings(viewSettingsKey);
|
|
2471
|
+
const effectivePageSize = perPageProp ?? settings.pageSize;
|
|
2786
2472
|
const resourceHook = useResource(
|
|
2787
2473
|
resourceName ?? "__noop__",
|
|
2788
2474
|
isClientMode ? resourceOptions : { enabled: false }
|
|
@@ -2803,7 +2489,8 @@ function ResourcePage(props) {
|
|
|
2803
2489
|
defaultView,
|
|
2804
2490
|
detail,
|
|
2805
2491
|
titleField: titleFieldProp,
|
|
2806
|
-
subtitleField: subtitleFieldProp
|
|
2492
|
+
subtitleField: subtitleFieldProp,
|
|
2493
|
+
controlled: isServerControlled
|
|
2807
2494
|
});
|
|
2808
2495
|
const actions = useMemo(() => {
|
|
2809
2496
|
if (isClientMode) {
|
|
@@ -2815,15 +2502,24 @@ function ResourcePage(props) {
|
|
|
2815
2502
|
}
|
|
2816
2503
|
return {
|
|
2817
2504
|
update: async () => {
|
|
2818
|
-
throw new Error(
|
|
2505
|
+
throw new Error(
|
|
2506
|
+
"ResourceActions.update not available in server-data mode"
|
|
2507
|
+
);
|
|
2819
2508
|
},
|
|
2820
2509
|
remove: async () => {
|
|
2821
|
-
throw new Error(
|
|
2510
|
+
throw new Error(
|
|
2511
|
+
"ResourceActions.remove not available in server-data mode"
|
|
2512
|
+
);
|
|
2822
2513
|
},
|
|
2823
2514
|
refetch: () => {
|
|
2824
2515
|
}
|
|
2825
2516
|
};
|
|
2826
|
-
}, [
|
|
2517
|
+
}, [
|
|
2518
|
+
isClientMode,
|
|
2519
|
+
resourceHook.update,
|
|
2520
|
+
resourceHook.remove,
|
|
2521
|
+
resourceHook.list
|
|
2522
|
+
]);
|
|
2827
2523
|
const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
|
|
2828
2524
|
const handleToggleSelect = useCallback((id) => {
|
|
2829
2525
|
setSelectedIds((prev) => {
|
|
@@ -2873,15 +2569,101 @@ function ResourcePage(props) {
|
|
|
2873
2569
|
[useBuiltInEdit, onEdit]
|
|
2874
2570
|
);
|
|
2875
2571
|
const tableColumns = useMemo(() => {
|
|
2876
|
-
|
|
2877
|
-
return page.columns.map((col) => ({
|
|
2572
|
+
const base = isClientMode ? page.columns.map((col) => ({
|
|
2878
2573
|
key: col.key,
|
|
2879
2574
|
header: col.header ?? col.key,
|
|
2880
2575
|
sortable: col.sortable ?? true,
|
|
2881
2576
|
hideBelow: col.hideBelow,
|
|
2882
2577
|
render: col.render ? (item, value) => col.render(item, value, actions) : void 0
|
|
2883
|
-
}));
|
|
2884
|
-
|
|
2578
|
+
})) : page.tableColumns;
|
|
2579
|
+
if (!isServerControlled) return base;
|
|
2580
|
+
return base.map((col) => ({ ...col, sortable: false }));
|
|
2581
|
+
}, [
|
|
2582
|
+
isClientMode,
|
|
2583
|
+
isServerControlled,
|
|
2584
|
+
page.columns,
|
|
2585
|
+
page.tableColumns,
|
|
2586
|
+
actions
|
|
2587
|
+
]);
|
|
2588
|
+
const currentPage = pageProp ?? 1;
|
|
2589
|
+
const handleSearchChange = useCallback(
|
|
2590
|
+
(value) => {
|
|
2591
|
+
page.filterConfig.onSearchChange(value);
|
|
2592
|
+
if (!isServerControlled) return;
|
|
2593
|
+
onSearchChange?.(value);
|
|
2594
|
+
if (currentPage !== 1) onPageChange?.(1);
|
|
2595
|
+
},
|
|
2596
|
+
[
|
|
2597
|
+
page.filterConfig,
|
|
2598
|
+
isServerControlled,
|
|
2599
|
+
onSearchChange,
|
|
2600
|
+
onPageChange,
|
|
2601
|
+
currentPage
|
|
2602
|
+
]
|
|
2603
|
+
);
|
|
2604
|
+
const handleSortSelect = useCallback(
|
|
2605
|
+
(value) => {
|
|
2606
|
+
page.filterConfig.onSortChange(value);
|
|
2607
|
+
if (!isServerControlled) return;
|
|
2608
|
+
const [field, order] = value.split(":");
|
|
2609
|
+
onSortChange?.(
|
|
2610
|
+
field && (order === "asc" || order === "desc") ? { field, order } : null
|
|
2611
|
+
);
|
|
2612
|
+
onPageChange?.(1);
|
|
2613
|
+
},
|
|
2614
|
+
[page.filterConfig, isServerControlled, onSortChange, onPageChange]
|
|
2615
|
+
);
|
|
2616
|
+
const handleClearFilters = useCallback(() => {
|
|
2617
|
+
page.clearFilters();
|
|
2618
|
+
if (!isServerControlled) return;
|
|
2619
|
+
onSearchChange?.("");
|
|
2620
|
+
onSortChange?.(null);
|
|
2621
|
+
onPageChange?.(1);
|
|
2622
|
+
}, [page, isServerControlled, onSearchChange, onSortChange, onPageChange]);
|
|
2623
|
+
const handleStatusChange = useCallback(
|
|
2624
|
+
(values) => {
|
|
2625
|
+
page.filterConfig.statusChips?.onChange(values);
|
|
2626
|
+
if (!isServerControlled) return;
|
|
2627
|
+
if (currentPage !== 1) onPageChange?.(1);
|
|
2628
|
+
},
|
|
2629
|
+
[page.filterConfig, isServerControlled, onPageChange, currentPage]
|
|
2630
|
+
);
|
|
2631
|
+
const statusChipsConfig = useMemo(() => {
|
|
2632
|
+
const base = page.filterConfig.statusChips;
|
|
2633
|
+
if (!base) return void 0;
|
|
2634
|
+
return { ...base, onChange: handleStatusChange };
|
|
2635
|
+
}, [page.filterConfig.statusChips, handleStatusChange]);
|
|
2636
|
+
const handlePageSizeChange = useCallback(
|
|
2637
|
+
(size) => {
|
|
2638
|
+
updateSetting("pageSize", size);
|
|
2639
|
+
onPerPageChange?.(size);
|
|
2640
|
+
if (isServerControlled) onPageChange?.(1);
|
|
2641
|
+
},
|
|
2642
|
+
[updateSetting, onPerPageChange, isServerControlled, onPageChange]
|
|
2643
|
+
);
|
|
2644
|
+
const missingPerPage = isServerControlled && !!onPageChange && perPageProp === void 0;
|
|
2645
|
+
const missingTotal = isServerControlled && !!onPageChange && totalProp === void 0;
|
|
2646
|
+
const pagerMisconfigured = missingPerPage || missingTotal;
|
|
2647
|
+
const missingPagerProps = [
|
|
2648
|
+
...missingPerPage ? ["perPage"] : [],
|
|
2649
|
+
...missingTotal ? ["total"] : []
|
|
2650
|
+
];
|
|
2651
|
+
const loggedMissingPerPageRef = useRef(false);
|
|
2652
|
+
useEffect(() => {
|
|
2653
|
+
if (!pagerMisconfigured) return;
|
|
2654
|
+
if (loggedMissingPerPageRef.current) return;
|
|
2655
|
+
loggedMissingPerPageRef.current = true;
|
|
2656
|
+
console.error(
|
|
2657
|
+
`ResourcePage: ${missingPagerProps.map((name) => `\`${name}\``).join(" and ")} ${missingPagerProps.length > 1 ? "are" : "is"} required when \`onPageChange\` is supplied.`
|
|
2658
|
+
);
|
|
2659
|
+
}, [pagerMisconfigured]);
|
|
2660
|
+
const pagerPageSize = perPageProp ?? effectivePageSize;
|
|
2661
|
+
const totalPages = Math.max(
|
|
2662
|
+
1,
|
|
2663
|
+
Math.ceil(displayTotal / Math.max(1, pagerPageSize))
|
|
2664
|
+
);
|
|
2665
|
+
const rangeFrom = page.data.length === 0 ? 0 : (currentPage - 1) * pagerPageSize + 1;
|
|
2666
|
+
const rangeTo = rangeFrom === 0 ? 0 : rangeFrom + page.data.length - 1;
|
|
2885
2667
|
const detailTitle = page.selectedItem ? String(
|
|
2886
2668
|
page.selectedItem[page.titleField] ?? ""
|
|
2887
2669
|
) : "";
|
|
@@ -2898,6 +2680,35 @@ function ResourcePage(props) {
|
|
|
2898
2680
|
}
|
|
2899
2681
|
page.handleRowClick(item);
|
|
2900
2682
|
};
|
|
2683
|
+
const hasBulkSelect = !!bulkActions && bulkActions.length > 0;
|
|
2684
|
+
const overlayOpen = page.detailOpen || formOpen;
|
|
2685
|
+
const keyboardNav = useKeyboardNavigation({
|
|
2686
|
+
itemCount: page.data.length,
|
|
2687
|
+
enabled: keyboardNavigation && page.viewMode !== "table",
|
|
2688
|
+
overlayOpen,
|
|
2689
|
+
onOpen: (index) => {
|
|
2690
|
+
const item = page.data[index];
|
|
2691
|
+
if (item) handleRowClick(item);
|
|
2692
|
+
},
|
|
2693
|
+
onToggleSelect: hasBulkSelect ? (index) => {
|
|
2694
|
+
const item = page.data[index];
|
|
2695
|
+
if (item) {
|
|
2696
|
+
handleToggleSelect(
|
|
2697
|
+
String(item.id ?? "")
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
} : void 0,
|
|
2701
|
+
// Supplied only while there is an open detail to close — the hook
|
|
2702
|
+
// suppresses Backspace's default whenever this is present, so leaving it
|
|
2703
|
+
// wired up permanently would swallow the browser/app's Backspace on
|
|
2704
|
+
// every grid/list page (including detail="none" and detail="route",
|
|
2705
|
+
// which never open one). `detailOpen` is only ever true for the panel
|
|
2706
|
+
// and modal modes, so it is the precise precondition here.
|
|
2707
|
+
onBack: page.detailOpen ? () => {
|
|
2708
|
+
page.setDetailOpen(false);
|
|
2709
|
+
page.setSelectedItem(null);
|
|
2710
|
+
} : void 0
|
|
2711
|
+
});
|
|
2901
2712
|
const showCreateButton = onCreate || useBuiltInCreate;
|
|
2902
2713
|
const createButton = showCreateButton ? /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: handleCreate, children: [
|
|
2903
2714
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-1" }),
|
|
@@ -2908,15 +2719,83 @@ function ResourcePage(props) {
|
|
|
2908
2719
|
createButton
|
|
2909
2720
|
] }) : void 0;
|
|
2910
2721
|
const isEmpty = !isLoading && !hasError && page.data.length === 0;
|
|
2911
|
-
const
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2722
|
+
const cardActionsFor = (item) => ({
|
|
2723
|
+
...actions,
|
|
2724
|
+
open: () => handleRowClick(item)
|
|
2725
|
+
});
|
|
2726
|
+
const rowActivationProps = (item, label, testId) => ({
|
|
2727
|
+
role: "button",
|
|
2728
|
+
tabIndex: 0,
|
|
2729
|
+
"aria-label": label || void 0,
|
|
2730
|
+
"data-testid": testId,
|
|
2731
|
+
onClick: () => handleRowClick(item),
|
|
2732
|
+
onKeyDown: (e) => {
|
|
2733
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
2734
|
+
e.preventDefault();
|
|
2735
|
+
handleRowClick(item);
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
const renderDefaultCard = (item) => {
|
|
2740
|
+
const cols = page.columns;
|
|
2741
|
+
const titleCol = cols[0];
|
|
2742
|
+
const titleVal = titleCol ? String(item[titleCol.key] ?? "") : "";
|
|
2743
|
+
const badgeCol = cols[1];
|
|
2744
|
+
const badgeVal = badgeCol ? item[badgeCol.key] : null;
|
|
2745
|
+
const priceCol = cols.find(
|
|
2746
|
+
(c, i) => i > 1 && /price|cost|amount|total/i.test(c.key)
|
|
2747
|
+
);
|
|
2748
|
+
const priceVal = priceCol ? item[priceCol.key] : null;
|
|
2749
|
+
const metaCols = cols.filter(
|
|
2750
|
+
(c) => c !== titleCol && c !== badgeCol && c !== priceCol
|
|
2751
|
+
);
|
|
2752
|
+
return /* @__PURE__ */ jsxs(
|
|
2753
|
+
Card,
|
|
2754
|
+
{
|
|
2755
|
+
...rowActivationProps(item, titleVal, "resource-card"),
|
|
2756
|
+
className: "h-full cursor-pointer hover:shadow-md motion-safe:transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2757
|
+
children: [
|
|
2758
|
+
/* @__PURE__ */ jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base truncate", children: titleVal }) }),
|
|
2759
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2760
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2761
|
+
badgeCol && /* @__PURE__ */ jsx("span", { children: badgeCol.render ? badgeCol.render(item, badgeVal, actions) : badgeVal != null ? String(badgeVal) : "\u2014" }),
|
|
2762
|
+
priceVal != null && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: String(priceVal) })
|
|
2763
|
+
] }),
|
|
2764
|
+
metaCols.map((col) => {
|
|
2765
|
+
const val = item[col.key];
|
|
2766
|
+
return /* @__PURE__ */ jsx(
|
|
2767
|
+
"p",
|
|
2768
|
+
{
|
|
2769
|
+
className: "text-xs text-muted-foreground truncate",
|
|
2770
|
+
children: col.render ? col.render(item, val, actions) : val != null ? String(val) : "\u2014"
|
|
2771
|
+
},
|
|
2772
|
+
col.key
|
|
2773
|
+
);
|
|
2774
|
+
})
|
|
2775
|
+
] }) })
|
|
2776
|
+
]
|
|
2777
|
+
}
|
|
2778
|
+
);
|
|
2779
|
+
};
|
|
2780
|
+
const renderDefaultListItem = (item) => {
|
|
2781
|
+
const cols = page.columns;
|
|
2782
|
+
const titleCol = cols[0];
|
|
2783
|
+
const titleVal = titleCol ? String(item[titleCol.key] ?? "") : "";
|
|
2784
|
+
return /* @__PURE__ */ jsxs(
|
|
2785
|
+
"div",
|
|
2786
|
+
{
|
|
2787
|
+
...rowActivationProps(item, titleVal, "resource-list-row"),
|
|
2788
|
+
className: "flex items-center justify-between px-3 py-2 border-b cursor-pointer hover:bg-muted/50 motion-safe:transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
|
2789
|
+
children: [
|
|
2790
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-sm truncate", children: titleVal }),
|
|
2791
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: cols.slice(1, 4).map((col) => {
|
|
2792
|
+
const val = item[col.key];
|
|
2793
|
+
return /* @__PURE__ */ jsx("span", { children: col.render ? col.render(item, val, actions) : val != null ? String(val) : "\u2014" }, col.key);
|
|
2794
|
+
}) })
|
|
2795
|
+
]
|
|
2796
|
+
}
|
|
2797
|
+
);
|
|
2798
|
+
};
|
|
2920
2799
|
return /* @__PURE__ */ jsxs(
|
|
2921
2800
|
DataPageShell,
|
|
2922
2801
|
{
|
|
@@ -2931,25 +2810,30 @@ function ResourcePage(props) {
|
|
|
2931
2810
|
onRetry: isClientMode ? () => resourceHook.list.refetch() : void 0,
|
|
2932
2811
|
viewMode: page.viewMode,
|
|
2933
2812
|
onViewModeChange: page.setViewMode,
|
|
2934
|
-
pageSize:
|
|
2935
|
-
onPageSizeChange:
|
|
2813
|
+
pageSize: effectivePageSize,
|
|
2814
|
+
onPageSizeChange: handlePageSizeChange,
|
|
2936
2815
|
density: settings.density,
|
|
2937
2816
|
onDensityChange: (d) => updateSetting("density", d),
|
|
2938
2817
|
createAction,
|
|
2939
2818
|
hasActiveFilters: page.hasActiveFilters,
|
|
2940
|
-
onClearFilters:
|
|
2819
|
+
onClearFilters: handleClearFilters,
|
|
2941
2820
|
emptyAction: emptyState,
|
|
2942
2821
|
filters: /* @__PURE__ */ jsx(
|
|
2943
2822
|
DataFilters,
|
|
2944
2823
|
{
|
|
2945
2824
|
search: page.filterConfig.search,
|
|
2946
|
-
onSearchChange:
|
|
2825
|
+
onSearchChange: handleSearchChange,
|
|
2947
2826
|
searchPlaceholder,
|
|
2948
2827
|
sort: page.filterConfig.sort,
|
|
2949
|
-
onSortChange:
|
|
2828
|
+
onSortChange: handleSortSelect,
|
|
2950
2829
|
sortOptions: page.filterConfig.sortOptions,
|
|
2951
|
-
statusChips:
|
|
2952
|
-
|
|
2830
|
+
statusChips: statusChipsConfig,
|
|
2831
|
+
savedViews,
|
|
2832
|
+
onLoadView,
|
|
2833
|
+
onSaveView,
|
|
2834
|
+
onDeleteView,
|
|
2835
|
+
canSaveViews,
|
|
2836
|
+
onClearAll: page.hasActiveFilters ? handleClearFilters : void 0
|
|
2953
2837
|
}
|
|
2954
2838
|
),
|
|
2955
2839
|
children: [
|
|
@@ -2975,7 +2859,10 @@ function ResourcePage(props) {
|
|
|
2975
2859
|
{
|
|
2976
2860
|
items: page.data,
|
|
2977
2861
|
viewMode: page.viewMode,
|
|
2862
|
+
gridCols: gridColsProp,
|
|
2978
2863
|
getKey: (item) => String(item.id ?? ""),
|
|
2864
|
+
focusedIndex: keyboardNav.focusedIndex,
|
|
2865
|
+
keyboardContainerRef: keyboardNav.containerRef,
|
|
2979
2866
|
renderTable: (items) => /* @__PURE__ */ jsx(
|
|
2980
2867
|
DataTable,
|
|
2981
2868
|
{
|
|
@@ -2988,72 +2875,109 @@ function ResourcePage(props) {
|
|
|
2988
2875
|
onToggleSelect: handleToggleSelect,
|
|
2989
2876
|
onToggleAll: handleToggleAll,
|
|
2990
2877
|
density: settings.density,
|
|
2991
|
-
pageSize:
|
|
2878
|
+
pageSize: effectivePageSize,
|
|
2879
|
+
pageSizeOptions,
|
|
2880
|
+
columnVisibility,
|
|
2881
|
+
columnVisibilityKey,
|
|
2882
|
+
resizableColumns,
|
|
2883
|
+
resizeKey,
|
|
2884
|
+
stickyHeader,
|
|
2885
|
+
stickyFirstColumn,
|
|
2886
|
+
pagination: isServerControlled ? false : void 0
|
|
2992
2887
|
}
|
|
2993
2888
|
),
|
|
2994
|
-
renderCard: (item) =>
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
{
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
}
|
|
3033
|
-
);
|
|
3034
|
-
},
|
|
3035
|
-
renderListItem: (item) => {
|
|
3036
|
-
const cols = page.columns;
|
|
3037
|
-
const titleCol = cols[0];
|
|
3038
|
-
const titleVal = titleCol ? String(item[titleCol.key] ?? "") : "";
|
|
3039
|
-
return /* @__PURE__ */ jsxs(
|
|
3040
|
-
"div",
|
|
2889
|
+
renderCard: (item, index) => renderCardProp ? renderCardProp(item, index, cardActionsFor(item)) : renderDefaultCard(item),
|
|
2890
|
+
renderListItem: (item, index) => renderCardProp ? renderCardProp(item, index, cardActionsFor(item)) : renderDefaultListItem(item)
|
|
2891
|
+
}
|
|
2892
|
+
),
|
|
2893
|
+
isServerControlled && onPageChange && pagerMisconfigured && /* @__PURE__ */ jsxs(
|
|
2894
|
+
"div",
|
|
2895
|
+
{
|
|
2896
|
+
className: "flex items-center gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive",
|
|
2897
|
+
"data-testid": "resource-page-pagination-error",
|
|
2898
|
+
role: "alert",
|
|
2899
|
+
children: [
|
|
2900
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
|
|
2901
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2902
|
+
"Pagination unavailable:",
|
|
2903
|
+
" ",
|
|
2904
|
+
missingPagerProps.map((name, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2905
|
+
index > 0 ? " and " : null,
|
|
2906
|
+
/* @__PURE__ */ jsx("code", { children: name })
|
|
2907
|
+
] }, name)),
|
|
2908
|
+
" ",
|
|
2909
|
+
missingPagerProps.length > 1 ? "are" : "is",
|
|
2910
|
+
" required when",
|
|
2911
|
+
" ",
|
|
2912
|
+
/* @__PURE__ */ jsx("code", { children: "onPageChange" }),
|
|
2913
|
+
" is supplied."
|
|
2914
|
+
] })
|
|
2915
|
+
]
|
|
2916
|
+
}
|
|
2917
|
+
),
|
|
2918
|
+
isServerControlled && onPageChange && !pagerMisconfigured && /* @__PURE__ */ jsxs(
|
|
2919
|
+
"nav",
|
|
2920
|
+
{
|
|
2921
|
+
"aria-label": "Pagination",
|
|
2922
|
+
className: "flex flex-col sm:flex-row items-center justify-between gap-2 px-3 py-2 text-sm",
|
|
2923
|
+
"data-testid": "resource-page-pagination",
|
|
2924
|
+
children: [
|
|
2925
|
+
/* @__PURE__ */ jsx(
|
|
2926
|
+
"span",
|
|
3041
2927
|
{
|
|
3042
|
-
className: "
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: cols.slice(1, 4).map((col) => {
|
|
3047
|
-
const val = item[col.key];
|
|
3048
|
-
return /* @__PURE__ */ jsx("span", { children: col.render ? col.render(item, val, actions) : val != null ? String(val) : "\u2014" }, col.key);
|
|
3049
|
-
}) })
|
|
3050
|
-
]
|
|
2928
|
+
className: "text-muted-foreground",
|
|
2929
|
+
"data-testid": "resource-page-range",
|
|
2930
|
+
"aria-live": "polite",
|
|
2931
|
+
children: displayTotal === 0 ? "No records" : `Showing ${rangeFrom}-${rangeTo} of ${displayTotal}`
|
|
3051
2932
|
}
|
|
3052
|
-
)
|
|
3053
|
-
|
|
2933
|
+
),
|
|
2934
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2935
|
+
/* @__PURE__ */ jsxs(
|
|
2936
|
+
Button,
|
|
2937
|
+
{
|
|
2938
|
+
variant: "outline",
|
|
2939
|
+
size: "sm",
|
|
2940
|
+
disabled: currentPage <= 1,
|
|
2941
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
2942
|
+
testID: "resource-page-prev",
|
|
2943
|
+
children: [
|
|
2944
|
+
/* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4 mr-1", "aria-hidden": "true" }),
|
|
2945
|
+
"Previous"
|
|
2946
|
+
]
|
|
2947
|
+
}
|
|
2948
|
+
),
|
|
2949
|
+
/* @__PURE__ */ jsxs(
|
|
2950
|
+
"span",
|
|
2951
|
+
{
|
|
2952
|
+
className: "text-muted-foreground",
|
|
2953
|
+
"data-testid": "resource-page-indicator",
|
|
2954
|
+
children: [
|
|
2955
|
+
"Page ",
|
|
2956
|
+
currentPage,
|
|
2957
|
+
" of ",
|
|
2958
|
+
totalPages
|
|
2959
|
+
]
|
|
2960
|
+
}
|
|
2961
|
+
),
|
|
2962
|
+
/* @__PURE__ */ jsxs(
|
|
2963
|
+
Button,
|
|
2964
|
+
{
|
|
2965
|
+
variant: "outline",
|
|
2966
|
+
size: "sm",
|
|
2967
|
+
disabled: currentPage >= totalPages,
|
|
2968
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
2969
|
+
testID: "resource-page-next",
|
|
2970
|
+
children: [
|
|
2971
|
+
"Next",
|
|
2972
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 ml-1", "aria-hidden": "true" })
|
|
2973
|
+
]
|
|
2974
|
+
}
|
|
2975
|
+
)
|
|
2976
|
+
] })
|
|
2977
|
+
]
|
|
3054
2978
|
}
|
|
3055
2979
|
),
|
|
3056
|
-
detail === "panel" && /* @__PURE__ */ jsx(
|
|
2980
|
+
(detail === "panel" || detail === "modal") && /* @__PURE__ */ jsx(
|
|
3057
2981
|
DetailPanel,
|
|
3058
2982
|
{
|
|
3059
2983
|
item: page.selectedItem,
|
|
@@ -3068,48 +2992,10 @@ function ResourcePage(props) {
|
|
|
3068
2992
|
onDelete,
|
|
3069
2993
|
fields: detailFields,
|
|
3070
2994
|
width: detailWidth,
|
|
2995
|
+
layout: detail === "modal" ? "dialog" : "sheet",
|
|
3071
2996
|
children: renderDetailProp ? (item) => renderDetailProp(item) : void 0
|
|
3072
2997
|
}
|
|
3073
2998
|
),
|
|
3074
|
-
detail === "modal" && /* @__PURE__ */ jsx(
|
|
3075
|
-
Dialog,
|
|
3076
|
-
{
|
|
3077
|
-
open: page.detailOpen,
|
|
3078
|
-
onOpenChange: (open) => {
|
|
3079
|
-
page.setDetailOpen(open);
|
|
3080
|
-
if (!open) page.setSelectedItem(null);
|
|
3081
|
-
},
|
|
3082
|
-
children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
3083
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
3084
|
-
/* @__PURE__ */ jsx(DialogTitle, { children: detailTitle }),
|
|
3085
|
-
detailSubtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: detailSubtitle })
|
|
3086
|
-
] }),
|
|
3087
|
-
/* @__PURE__ */ jsxs("div", { className: "py-4", children: [
|
|
3088
|
-
modalDetailContent,
|
|
3089
|
-
(onEdit || useBuiltInEdit || onDelete) && page.selectedItem && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-4 pt-4 border-t", children: [
|
|
3090
|
-
(onEdit || useBuiltInEdit) && /* @__PURE__ */ jsx(
|
|
3091
|
-
Button,
|
|
3092
|
-
{
|
|
3093
|
-
variant: "outline",
|
|
3094
|
-
size: "sm",
|
|
3095
|
-
onClick: () => handleEdit(page.selectedItem),
|
|
3096
|
-
children: "Edit"
|
|
3097
|
-
}
|
|
3098
|
-
),
|
|
3099
|
-
onDelete && /* @__PURE__ */ jsx(
|
|
3100
|
-
Button,
|
|
3101
|
-
{
|
|
3102
|
-
variant: "destructive",
|
|
3103
|
-
size: "sm",
|
|
3104
|
-
onClick: () => onDelete(page.selectedItem),
|
|
3105
|
-
children: "Delete"
|
|
3106
|
-
}
|
|
3107
|
-
)
|
|
3108
|
-
] })
|
|
3109
|
-
] })
|
|
3110
|
-
] })
|
|
3111
|
-
}
|
|
3112
|
-
),
|
|
3113
2999
|
(useBuiltInCreate || useBuiltInEdit) && resourceName && /* @__PURE__ */ jsx(
|
|
3114
3000
|
ResourceForm,
|
|
3115
3001
|
{
|
|
@@ -3136,769 +3022,80 @@ function ResourcePage(props) {
|
|
|
3136
3022
|
}
|
|
3137
3023
|
);
|
|
3138
3024
|
}
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
showThemeToggle: true,
|
|
3143
|
-
showCollapse: true,
|
|
3144
|
-
showUserSlot: true,
|
|
3145
|
-
showFooter: true,
|
|
3146
|
-
showSecondaryNav: true,
|
|
3147
|
-
showMobileBottomNav: true,
|
|
3148
|
-
defaultCollapsed: false,
|
|
3149
|
-
configurable: void 0,
|
|
3150
|
-
density: "comfortable",
|
|
3151
|
-
railWidth: "narrow",
|
|
3152
|
-
scrollRoot: "container"
|
|
3153
|
-
};
|
|
3154
|
-
function readStoredCollapsed(key) {
|
|
3155
|
-
if (typeof window === "undefined") return void 0;
|
|
3156
|
-
try {
|
|
3157
|
-
const raw = localStorage.getItem(`${key}:collapsed`);
|
|
3158
|
-
if (raw === "1") return true;
|
|
3159
|
-
if (raw === "0") return false;
|
|
3160
|
-
return void 0;
|
|
3161
|
-
} catch {
|
|
3162
|
-
return void 0;
|
|
3163
|
-
}
|
|
3025
|
+
function pick(record, field) {
|
|
3026
|
+
const value = field ? record[field] : record.name ?? record.title ?? record.id;
|
|
3027
|
+
return value == null ? "" : String(value);
|
|
3164
3028
|
}
|
|
3165
|
-
function
|
|
3166
|
-
if (typeof window === "undefined") return;
|
|
3167
|
-
try {
|
|
3168
|
-
localStorage.setItem(`${key}:collapsed`, collapsed ? "1" : "0");
|
|
3169
|
-
} catch {
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
|
-
function ThemeToggle({ testId }) {
|
|
3173
|
-
const [dark, setDark] = useState(false);
|
|
3174
|
-
useEffect(() => {
|
|
3175
|
-
const stored = localStorage.getItem("theme");
|
|
3176
|
-
const prefersDark = window.matchMedia(
|
|
3177
|
-
"(prefers-color-scheme: dark)"
|
|
3178
|
-
).matches;
|
|
3179
|
-
const isDark = stored === "dark" || !stored && prefersDark;
|
|
3180
|
-
setDark(isDark);
|
|
3181
|
-
document.documentElement.classList.toggle("dark", isDark);
|
|
3182
|
-
}, []);
|
|
3183
|
-
function toggle() {
|
|
3184
|
-
const next = !dark;
|
|
3185
|
-
setDark(next);
|
|
3186
|
-
document.documentElement.classList.toggle("dark", next);
|
|
3187
|
-
localStorage.setItem("theme", next ? "dark" : "light");
|
|
3188
|
-
}
|
|
3029
|
+
function NotFound() {
|
|
3189
3030
|
return /* @__PURE__ */ jsx(
|
|
3190
|
-
|
|
3031
|
+
EmptyState,
|
|
3191
3032
|
{
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
onClick: toggle,
|
|
3195
|
-
className: "h-8 w-8",
|
|
3196
|
-
title: "Toggle theme",
|
|
3197
|
-
"aria-label": "Toggle theme",
|
|
3198
|
-
"data-testid": testId,
|
|
3199
|
-
testID: testId,
|
|
3200
|
-
children: dark ? /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" })
|
|
3033
|
+
title: "Not found",
|
|
3034
|
+
description: "This record no longer exists, or you don't have access to it."
|
|
3201
3035
|
}
|
|
3202
3036
|
);
|
|
3203
3037
|
}
|
|
3204
|
-
function
|
|
3205
|
-
if (
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
if (isActive(item.to, activePath)) return true;
|
|
3209
|
-
return Boolean(
|
|
3210
|
-
item.children?.some((child) => itemIsActive(child, activePath, isActive))
|
|
3211
|
-
);
|
|
3038
|
+
function isNotFoundError(error) {
|
|
3039
|
+
if (!(error instanceof Error)) return false;
|
|
3040
|
+
if (error.code === "PGRST116") return true;
|
|
3041
|
+
return /\[MockProvider\] Record not found/i.test(error.message) || /switchboard-data-provider: no ".*" row with id/i.test(error.message);
|
|
3212
3042
|
}
|
|
3213
|
-
function
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
return /* @__PURE__ */ jsxs(
|
|
3226
|
-
"span",
|
|
3227
|
-
{
|
|
3228
|
-
title: item.label,
|
|
3229
|
-
className: cn(
|
|
3230
|
-
"flex items-center gap-3 rounded-lg text-sm font-medium opacity-40",
|
|
3231
|
-
pad,
|
|
3232
|
-
collapsed && "justify-center px-2"
|
|
3233
|
-
),
|
|
3234
|
-
"aria-disabled": true,
|
|
3235
|
-
children: [
|
|
3236
|
-
/* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4 shrink-0" }),
|
|
3237
|
-
!collapsed ? /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label }) : null
|
|
3238
|
-
]
|
|
3239
|
-
}
|
|
3240
|
-
);
|
|
3241
|
-
}
|
|
3242
|
-
return /* @__PURE__ */ jsxs(
|
|
3243
|
-
LinkComp,
|
|
3244
|
-
{
|
|
3245
|
-
href: item.to,
|
|
3246
|
-
onClick: onNavClick,
|
|
3247
|
-
title: collapsed ? item.label : void 0,
|
|
3248
|
-
"aria-label": collapsed ? item.label : void 0,
|
|
3249
|
-
"aria-current": active ? "page" : void 0,
|
|
3250
|
-
className: cn(
|
|
3251
|
-
"flex items-center gap-3 rounded-lg text-sm font-medium transition-colors",
|
|
3252
|
-
pad,
|
|
3253
|
-
collapsed && "justify-center px-2",
|
|
3254
|
-
active ? "bg-sidebar-accent text-sidebar-primary" : "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
3255
|
-
),
|
|
3256
|
-
children: [
|
|
3257
|
-
/* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4 shrink-0" }),
|
|
3258
|
-
!collapsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3259
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
3260
|
-
item.badge != null ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "h-5 shrink-0 px-1.5 text-[10px]", children: item.badge }) : null
|
|
3261
|
-
] }) : null
|
|
3262
|
-
]
|
|
3263
|
-
}
|
|
3264
|
-
);
|
|
3265
|
-
}
|
|
3266
|
-
function NavGroup({
|
|
3267
|
-
item,
|
|
3268
|
-
collapsed,
|
|
3269
|
-
density,
|
|
3270
|
-
onNavClick,
|
|
3271
|
-
linkComponent,
|
|
3272
|
-
activePath,
|
|
3273
|
-
isActive
|
|
3043
|
+
function ResourceDetailPage({
|
|
3044
|
+
resource,
|
|
3045
|
+
id,
|
|
3046
|
+
titleField,
|
|
3047
|
+
subtitleField,
|
|
3048
|
+
select,
|
|
3049
|
+
breadcrumb,
|
|
3050
|
+
actions,
|
|
3051
|
+
sidebar,
|
|
3052
|
+
children,
|
|
3053
|
+
className,
|
|
3054
|
+
testID
|
|
3274
3055
|
}) {
|
|
3275
|
-
const
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
{
|
|
3287
|
-
item,
|
|
3288
|
-
collapsed,
|
|
3289
|
-
density,
|
|
3290
|
-
onNavClick,
|
|
3291
|
-
linkComponent,
|
|
3292
|
-
activePath,
|
|
3293
|
-
isActive
|
|
3294
|
-
}
|
|
3295
|
-
);
|
|
3056
|
+
const { data, isLoading, isError, error } = useOne(resource, id, {
|
|
3057
|
+
select,
|
|
3058
|
+
// `useOne` defaults to `enabled: !!id`, which is wrong for a numeric
|
|
3059
|
+
// primary key: id `0` is falsy, so the query would never run and the page
|
|
3060
|
+
// would report a record that exists as missing, without ever asking the
|
|
3061
|
+
// provider. `Identifier` is `string | number`, so this is reachable.
|
|
3062
|
+
// Presence is the question, not truthiness.
|
|
3063
|
+
enabled: id != null
|
|
3064
|
+
});
|
|
3065
|
+
if (id == null || isLoading) {
|
|
3066
|
+
return /* @__PURE__ */ jsx(PageLoading, { testID: testID ? `${testID}-loading` : void 0 });
|
|
3296
3067
|
}
|
|
3297
|
-
if (
|
|
3298
|
-
|
|
3068
|
+
if (isError) {
|
|
3069
|
+
if (isNotFoundError(error)) return /* @__PURE__ */ jsx(NotFound, {});
|
|
3299
3070
|
return /* @__PURE__ */ jsx(
|
|
3300
|
-
|
|
3071
|
+
EmptyState,
|
|
3301
3072
|
{
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
onNavClick,
|
|
3306
|
-
linkComponent,
|
|
3307
|
-
activePath,
|
|
3308
|
-
isActive
|
|
3073
|
+
icon: AlertTriangle,
|
|
3074
|
+
title: "Couldn't load this record",
|
|
3075
|
+
description: error instanceof Error ? error.message : void 0
|
|
3309
3076
|
}
|
|
3310
3077
|
);
|
|
3311
3078
|
}
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
const pad = density === "compact" ? "px-2.5 py-1.5" : "px-3 py-2";
|
|
3316
|
-
const LinkComp = linkComponent;
|
|
3317
|
-
const parentClass = cn(
|
|
3318
|
-
"flex min-w-0 flex-1 items-center gap-3 rounded-lg text-sm font-medium transition-colors",
|
|
3319
|
-
pad,
|
|
3320
|
-
groupHighlight ? "bg-sidebar-accent/60 text-sidebar-primary" : "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
3321
|
-
);
|
|
3322
|
-
return /* @__PURE__ */ jsx(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
3323
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", "data-testid": `nav-group-${item.label}`, children: [
|
|
3324
|
-
item.to && !item.disabled ? /* @__PURE__ */ jsxs(
|
|
3325
|
-
LinkComp,
|
|
3326
|
-
{
|
|
3327
|
-
href: item.to,
|
|
3328
|
-
onClick: onNavClick,
|
|
3329
|
-
"aria-current": selfExact ? "page" : void 0,
|
|
3330
|
-
className: parentClass,
|
|
3331
|
-
children: [
|
|
3332
|
-
/* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4 shrink-0" }),
|
|
3333
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label })
|
|
3334
|
-
]
|
|
3335
|
-
}
|
|
3336
|
-
) : /* @__PURE__ */ jsxs(
|
|
3337
|
-
"button",
|
|
3338
|
-
{
|
|
3339
|
-
type: "button",
|
|
3340
|
-
className: parentClass,
|
|
3341
|
-
onClick: () => setOpen((o) => !o),
|
|
3342
|
-
"aria-expanded": open,
|
|
3343
|
-
"aria-disabled": item.disabled || void 0,
|
|
3344
|
-
disabled: item.disabled,
|
|
3345
|
-
children: [
|
|
3346
|
-
/* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4 shrink-0" }),
|
|
3347
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label })
|
|
3348
|
-
]
|
|
3349
|
-
}
|
|
3350
|
-
),
|
|
3351
|
-
/* @__PURE__ */ jsx(
|
|
3352
|
-
"button",
|
|
3353
|
-
{
|
|
3354
|
-
type: "button",
|
|
3355
|
-
className: cn(
|
|
3356
|
-
"shrink-0 rounded-lg p-1.5 text-sidebar-foreground transition-colors hover:bg-sidebar-accent",
|
|
3357
|
-
groupHighlight && "text-sidebar-primary",
|
|
3358
|
-
item.disabled && "pointer-events-none opacity-40"
|
|
3359
|
-
),
|
|
3360
|
-
onClick: () => setOpen((o) => !o),
|
|
3361
|
-
"aria-expanded": open,
|
|
3362
|
-
"aria-label": open ? `Collapse ${item.label}` : `Expand ${item.label}`,
|
|
3363
|
-
"aria-disabled": item.disabled || void 0,
|
|
3364
|
-
disabled: item.disabled,
|
|
3365
|
-
"data-testid": `nav-group-toggle-${item.label}`,
|
|
3366
|
-
children: /* @__PURE__ */ jsx(
|
|
3367
|
-
ChevronDown,
|
|
3368
|
-
{
|
|
3369
|
-
className: cn(
|
|
3370
|
-
"h-3.5 w-3.5 opacity-60 transition-transform",
|
|
3371
|
-
open && "rotate-180"
|
|
3372
|
-
)
|
|
3373
|
-
}
|
|
3374
|
-
)
|
|
3375
|
-
}
|
|
3376
|
-
)
|
|
3377
|
-
] }),
|
|
3378
|
-
/* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", { className: "ml-3 space-y-0.5 border-l border-sidebar-border pl-2", children: children.map((child) => /* @__PURE__ */ jsx(
|
|
3379
|
-
NavLinkRow,
|
|
3380
|
-
{
|
|
3381
|
-
item: child,
|
|
3382
|
-
collapsed: false,
|
|
3383
|
-
density,
|
|
3384
|
-
onNavClick,
|
|
3385
|
-
linkComponent,
|
|
3386
|
-
activePath,
|
|
3387
|
-
isActive
|
|
3388
|
-
},
|
|
3389
|
-
child.to + child.label
|
|
3390
|
-
)) }) })
|
|
3391
|
-
] }) });
|
|
3392
|
-
}
|
|
3393
|
-
function SidebarNav({
|
|
3394
|
-
navItems,
|
|
3395
|
-
secondaryNavItems,
|
|
3396
|
-
secondaryNavLabel,
|
|
3397
|
-
showSecondary,
|
|
3398
|
-
collapsed,
|
|
3399
|
-
density,
|
|
3400
|
-
onNavClick,
|
|
3401
|
-
linkComponent,
|
|
3402
|
-
activePath,
|
|
3403
|
-
isActive
|
|
3404
|
-
}) {
|
|
3405
|
-
return /* @__PURE__ */ jsxs(
|
|
3406
|
-
"nav",
|
|
3407
|
-
{
|
|
3408
|
-
className: cn(
|
|
3409
|
-
"flex-1 space-y-1 overflow-y-auto",
|
|
3410
|
-
collapsed ? "p-2" : "p-3"
|
|
3411
|
-
),
|
|
3412
|
-
"aria-label": "Main",
|
|
3413
|
-
children: [
|
|
3414
|
-
navItems.map((item) => /* @__PURE__ */ jsx(
|
|
3415
|
-
NavGroup,
|
|
3416
|
-
{
|
|
3417
|
-
item,
|
|
3418
|
-
collapsed,
|
|
3419
|
-
density,
|
|
3420
|
-
onNavClick,
|
|
3421
|
-
linkComponent,
|
|
3422
|
-
activePath,
|
|
3423
|
-
isActive
|
|
3424
|
-
},
|
|
3425
|
-
item.to + item.label
|
|
3426
|
-
)),
|
|
3427
|
-
showSecondary && secondaryNavItems && secondaryNavItems.length > 0 ? /* @__PURE__ */ jsxs(
|
|
3428
|
-
"div",
|
|
3429
|
-
{
|
|
3430
|
-
className: cn(
|
|
3431
|
-
"mt-4 space-y-1 border-t border-sidebar-border pt-4",
|
|
3432
|
-
collapsed && "mt-2 pt-2"
|
|
3433
|
-
),
|
|
3434
|
-
children: [
|
|
3435
|
-
!collapsed ? /* @__PURE__ */ jsx("p", { className: "mb-2 px-3 text-xs font-medium uppercase tracking-wider text-sidebar-foreground/40", children: secondaryNavLabel }) : null,
|
|
3436
|
-
secondaryNavItems.map((item) => /* @__PURE__ */ jsx(
|
|
3437
|
-
NavGroup,
|
|
3438
|
-
{
|
|
3439
|
-
item,
|
|
3440
|
-
collapsed,
|
|
3441
|
-
density,
|
|
3442
|
-
onNavClick,
|
|
3443
|
-
linkComponent,
|
|
3444
|
-
activePath,
|
|
3445
|
-
isActive
|
|
3446
|
-
},
|
|
3447
|
-
item.to + item.label
|
|
3448
|
-
))
|
|
3449
|
-
]
|
|
3450
|
-
}
|
|
3451
|
-
) : null
|
|
3452
|
-
]
|
|
3453
|
-
}
|
|
3454
|
-
);
|
|
3455
|
-
}
|
|
3456
|
-
function SidebarBrand({
|
|
3457
|
-
appName,
|
|
3458
|
-
appLogo,
|
|
3459
|
-
logo,
|
|
3460
|
-
showLogo,
|
|
3461
|
-
showAppName,
|
|
3462
|
-
collapsed
|
|
3463
|
-
}) {
|
|
3464
|
-
if (!showLogo && !showAppName) return null;
|
|
3465
|
-
return /* @__PURE__ */ jsxs(
|
|
3466
|
-
"div",
|
|
3467
|
-
{
|
|
3468
|
-
className: cn(
|
|
3469
|
-
"flex min-w-0 items-center gap-2",
|
|
3470
|
-
collapsed && "justify-center"
|
|
3471
|
-
),
|
|
3472
|
-
children: [
|
|
3473
|
-
showLogo ? logo ? /* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden", children: logo }) : appLogo ? /* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-primary", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-primary-foreground", children: appLogo }) }) : null : null,
|
|
3474
|
-
showAppName && !collapsed ? /* @__PURE__ */ jsx("span", { className: "truncate font-semibold text-sidebar-foreground", children: appName }) : null
|
|
3475
|
-
]
|
|
3476
|
-
}
|
|
3477
|
-
);
|
|
3478
|
-
}
|
|
3479
|
-
function AppShell({
|
|
3480
|
-
appName,
|
|
3481
|
-
appLogo,
|
|
3482
|
-
logo,
|
|
3483
|
-
navItems,
|
|
3484
|
-
secondaryNavItems,
|
|
3485
|
-
secondaryNavLabel = "More",
|
|
3486
|
-
mobileNavItems,
|
|
3487
|
-
headerSlot,
|
|
3488
|
-
collapsedHeaderSlot,
|
|
3489
|
-
footer,
|
|
3490
|
-
userSlot,
|
|
3491
|
-
children,
|
|
3492
|
-
showThemeToggle: showThemeToggleProp,
|
|
3493
|
-
options: optionsProp,
|
|
3494
|
-
optionsStorageKey,
|
|
3495
|
-
collapsed: collapsedProp,
|
|
3496
|
-
onCollapsedChange,
|
|
3497
|
-
linkComponent = DefaultLink,
|
|
3498
|
-
activePath,
|
|
3499
|
-
isActive = isPathActive
|
|
3500
|
-
}) {
|
|
3501
|
-
const [mobileOpen, setMobileOpen] = useState(false);
|
|
3502
|
-
const [userOverrides, setUserOverrides] = useState(
|
|
3503
|
-
{}
|
|
3504
|
-
);
|
|
3505
|
-
const [hydratedKey, setHydratedKey] = useState(
|
|
3506
|
-
optionsStorageKey ? void 0 : ""
|
|
3507
|
-
);
|
|
3508
|
-
useEffect(() => {
|
|
3509
|
-
setMobileOpen(false);
|
|
3510
|
-
}, [activePath]);
|
|
3511
|
-
const hasSecondary = Boolean(secondaryNavItems && secondaryNavItems.length);
|
|
3512
|
-
const hasUser = userSlot != null;
|
|
3513
|
-
const hasFooter = footer != null;
|
|
3514
|
-
const hasLogo = Boolean(logo || appLogo);
|
|
3515
|
-
useEffect(() => {
|
|
3516
|
-
if (!optionsStorageKey) {
|
|
3517
|
-
setUserOverrides({});
|
|
3518
|
-
setHydratedKey("");
|
|
3519
|
-
return;
|
|
3520
|
-
}
|
|
3521
|
-
setUserOverrides(readStoredOptions(optionsStorageKey));
|
|
3522
|
-
setHydratedKey(optionsStorageKey);
|
|
3523
|
-
}, [optionsStorageKey]);
|
|
3524
|
-
useEffect(() => {
|
|
3525
|
-
if (!optionsStorageKey || hydratedKey !== optionsStorageKey) return;
|
|
3526
|
-
writeStoredOptions(optionsStorageKey, userOverrides);
|
|
3527
|
-
}, [optionsStorageKey, userOverrides, hydratedKey]);
|
|
3528
|
-
const lockedOptions = optionsProp?.lockedOptions;
|
|
3529
|
-
const resolved = useMemo(() => {
|
|
3530
|
-
const merged = {
|
|
3531
|
-
...OPTION_DEFAULTS2,
|
|
3532
|
-
...showThemeToggleProp !== void 0 ? { showThemeToggle: showThemeToggleProp } : {},
|
|
3533
|
-
...optionsProp,
|
|
3534
|
-
...userOverrides
|
|
3535
|
-
};
|
|
3536
|
-
if (merged.configurable === void 0) {
|
|
3537
|
-
merged.configurable = hasSecondary || hasUser || hasFooter || Boolean(merged.showCollapse) || Boolean(merged.showThemeToggle);
|
|
3538
|
-
}
|
|
3539
|
-
if (lockedOptions?.length) {
|
|
3540
|
-
const defaults = OPTION_DEFAULTS2;
|
|
3541
|
-
const devOptions = optionsProp;
|
|
3542
|
-
const target = merged;
|
|
3543
|
-
for (const key of lockedOptions) {
|
|
3544
|
-
target[key] = devOptions?.[key] ?? defaults[key];
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
return merged;
|
|
3548
|
-
}, [
|
|
3549
|
-
optionsProp,
|
|
3550
|
-
userOverrides,
|
|
3551
|
-
showThemeToggleProp,
|
|
3552
|
-
hasSecondary,
|
|
3553
|
-
hasUser,
|
|
3554
|
-
hasFooter,
|
|
3555
|
-
lockedOptions
|
|
3556
|
-
]);
|
|
3557
|
-
const patchOption = useCallback(
|
|
3558
|
-
(key, value) => {
|
|
3559
|
-
if (lockedOptions?.includes(key)) return;
|
|
3560
|
-
setUserOverrides((prev) => ({ ...prev, [key]: value }));
|
|
3561
|
-
},
|
|
3562
|
-
[lockedOptions]
|
|
3563
|
-
);
|
|
3564
|
-
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(
|
|
3565
|
-
() => optionsProp?.defaultCollapsed ?? OPTION_DEFAULTS2.defaultCollapsed
|
|
3566
|
-
);
|
|
3567
|
-
useEffect(() => {
|
|
3568
|
-
if (!optionsStorageKey || collapsedProp !== void 0) return;
|
|
3569
|
-
const stored = readStoredCollapsed(optionsStorageKey);
|
|
3570
|
-
if (stored !== void 0) setUncontrolledCollapsed(stored);
|
|
3571
|
-
}, [optionsStorageKey, collapsedProp]);
|
|
3572
|
-
const isCollapseControlled = collapsedProp !== void 0;
|
|
3573
|
-
const collapsed = isCollapseControlled ? collapsedProp : uncontrolledCollapsed;
|
|
3574
|
-
const setCollapsed = (next) => {
|
|
3575
|
-
if (!isCollapseControlled) {
|
|
3576
|
-
setUncontrolledCollapsed(next);
|
|
3577
|
-
if (optionsStorageKey) writeStoredCollapsed(optionsStorageKey, next);
|
|
3578
|
-
}
|
|
3579
|
-
onCollapsedChange?.(next);
|
|
3580
|
-
};
|
|
3581
|
-
const density = resolved.density ?? "comfortable";
|
|
3582
|
-
const scrollWindow = resolved.scrollRoot === "window";
|
|
3583
|
-
const railExpanded = resolved.railWidth === "wide" ? "md:w-64" : "md:w-52";
|
|
3584
|
-
const railClass = collapsed ? "md:w-14" : railExpanded;
|
|
3585
|
-
const bottomItems = (mobileNavItems ?? navItems.filter((i) => !i.children || i.children.length === 0)).filter((i) => !i.disabled);
|
|
3586
|
-
const toggles = [
|
|
3587
|
-
{ key: "showLogo", label: "Logo", available: hasLogo },
|
|
3588
|
-
{ key: "showAppName", label: "App name", available: true },
|
|
3589
|
-
{
|
|
3590
|
-
key: "showThemeToggle",
|
|
3591
|
-
label: "Theme toggle",
|
|
3592
|
-
available: true
|
|
3593
|
-
},
|
|
3594
|
-
{ key: "showCollapse", label: "Collapse control", available: true },
|
|
3595
|
-
{
|
|
3596
|
-
key: "showSecondaryNav",
|
|
3597
|
-
label: "Secondary nav",
|
|
3598
|
-
available: hasSecondary
|
|
3599
|
-
},
|
|
3600
|
-
{ key: "showFooter", label: "Footer", available: hasFooter },
|
|
3601
|
-
{ key: "showUserSlot", label: "User block", available: hasUser },
|
|
3602
|
-
{
|
|
3603
|
-
key: "showMobileBottomNav",
|
|
3604
|
-
label: "Mobile bottom nav",
|
|
3605
|
-
available: bottomItems.length > 0
|
|
3606
|
-
}
|
|
3607
|
-
].filter((t) => t.available && !lockedOptions?.includes(t.key));
|
|
3608
|
-
const showTheme = resolved.showThemeToggle !== false;
|
|
3609
|
-
const showCollapseCtrl = resolved.showCollapse !== false;
|
|
3610
|
-
const showSecondary = hasSecondary && resolved.showSecondaryNav !== false;
|
|
3611
|
-
const showFooterSlot = hasFooter && resolved.showFooter !== false;
|
|
3612
|
-
const showUser = hasUser && resolved.showUserSlot !== false;
|
|
3613
|
-
const showMobileBottom = bottomItems.length > 0 && resolved.showMobileBottomNav !== false;
|
|
3614
|
-
const optionsControl = resolved.configurable && toggles.length > 0 ? /* @__PURE__ */ jsxs(Popover, { children: [
|
|
3615
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
3616
|
-
Button,
|
|
3617
|
-
{
|
|
3618
|
-
type: "button",
|
|
3619
|
-
variant: "ghost",
|
|
3620
|
-
size: "icon",
|
|
3621
|
-
className: "h-8 w-8",
|
|
3622
|
-
title: "Sidebar options",
|
|
3623
|
-
"aria-label": "Sidebar options",
|
|
3624
|
-
"data-testid": "app-shell-options",
|
|
3625
|
-
testID: "app-shell-options",
|
|
3626
|
-
children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4" })
|
|
3627
|
-
}
|
|
3628
|
-
) }),
|
|
3629
|
-
/* @__PURE__ */ jsxs(PopoverContent, { align: "start", side: "top", className: "w-64 space-y-3", children: [
|
|
3630
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
3631
|
-
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Sidebar options" }),
|
|
3632
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Customize this sidebar. Saved on this device when a storage key is set." })
|
|
3633
|
-
] }),
|
|
3634
|
-
/* @__PURE__ */ jsx("ul", { className: "space-y-3", children: toggles.map((t) => {
|
|
3635
|
-
const checked = Boolean(resolved[t.key] ?? true);
|
|
3636
|
-
return /* @__PURE__ */ jsxs(
|
|
3637
|
-
"li",
|
|
3638
|
-
{
|
|
3639
|
-
className: "flex items-center justify-between gap-3",
|
|
3640
|
-
children: [
|
|
3641
|
-
/* @__PURE__ */ jsx(
|
|
3642
|
-
Label,
|
|
3643
|
-
{
|
|
3644
|
-
htmlFor: `app-shell-opt-${t.key}`,
|
|
3645
|
-
className: "text-sm font-normal",
|
|
3646
|
-
children: t.label
|
|
3647
|
-
}
|
|
3648
|
-
),
|
|
3649
|
-
/* @__PURE__ */ jsx(
|
|
3650
|
-
Switch,
|
|
3651
|
-
{
|
|
3652
|
-
id: `app-shell-opt-${t.key}`,
|
|
3653
|
-
checked,
|
|
3654
|
-
onCheckedChange: (v) => patchOption(t.key, v)
|
|
3655
|
-
}
|
|
3656
|
-
)
|
|
3657
|
-
]
|
|
3658
|
-
},
|
|
3659
|
-
t.key
|
|
3660
|
-
);
|
|
3661
|
-
}) }),
|
|
3662
|
-
optionsStorageKey && Object.keys(userOverrides).length > 0 ? /* @__PURE__ */ jsx(
|
|
3663
|
-
Button,
|
|
3664
|
-
{
|
|
3665
|
-
type: "button",
|
|
3666
|
-
variant: "ghost",
|
|
3667
|
-
size: "sm",
|
|
3668
|
-
className: "h-8 w-full text-xs",
|
|
3669
|
-
onClick: () => setUserOverrides({}),
|
|
3670
|
-
"data-testid": "app-shell-options-reset",
|
|
3671
|
-
"aria-label": "Reset sidebar options",
|
|
3672
|
-
testID: "app-shell-options-reset",
|
|
3673
|
-
children: "Reset to defaults"
|
|
3674
|
-
}
|
|
3675
|
-
) : null
|
|
3676
|
-
] })
|
|
3677
|
-
] }) : null;
|
|
3678
|
-
const sidebarChrome = (opts) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3679
|
-
/* @__PURE__ */ jsxs(
|
|
3680
|
-
"div",
|
|
3681
|
-
{
|
|
3682
|
-
className: cn(
|
|
3683
|
-
"flex h-14 shrink-0 items-center gap-2 border-b border-sidebar-border",
|
|
3684
|
-
collapsed && !opts.mobile ? "justify-center px-2" : "px-3"
|
|
3685
|
-
),
|
|
3686
|
-
children: [
|
|
3687
|
-
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
3688
|
-
SidebarBrand,
|
|
3689
|
-
{
|
|
3690
|
-
appName,
|
|
3691
|
-
appLogo,
|
|
3692
|
-
logo,
|
|
3693
|
-
showLogo: resolved.showLogo !== false,
|
|
3694
|
-
showAppName: resolved.showAppName !== false,
|
|
3695
|
-
collapsed: collapsed && !opts.mobile
|
|
3696
|
-
}
|
|
3697
|
-
) }),
|
|
3698
|
-
opts.mobile ? /* @__PURE__ */ jsx(
|
|
3699
|
-
Button,
|
|
3700
|
-
{
|
|
3701
|
-
variant: "ghost",
|
|
3702
|
-
size: "icon",
|
|
3703
|
-
onClick: () => setMobileOpen(false),
|
|
3704
|
-
"aria-label": "Close navigation",
|
|
3705
|
-
"data-testid": "app-shell-mobile-close",
|
|
3706
|
-
testID: "app-shell-mobile-close",
|
|
3707
|
-
children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
|
|
3708
|
-
}
|
|
3709
|
-
) : /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
3710
|
-
showCollapseCtrl ? /* @__PURE__ */ jsx(
|
|
3711
|
-
Button,
|
|
3712
|
-
{
|
|
3713
|
-
variant: "ghost",
|
|
3714
|
-
size: "icon",
|
|
3715
|
-
className: "h-8 w-8",
|
|
3716
|
-
onClick: () => setCollapsed(!collapsed),
|
|
3717
|
-
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3718
|
-
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3719
|
-
"aria-pressed": collapsed,
|
|
3720
|
-
"data-testid": "app-shell-collapse",
|
|
3721
|
-
testID: "app-shell-collapse",
|
|
3722
|
-
children: collapsed ? /* @__PURE__ */ jsx(PanelLeft, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(PanelLeftClose, { className: "h-4 w-4" })
|
|
3723
|
-
}
|
|
3724
|
-
) : null,
|
|
3725
|
-
!collapsed ? optionsControl : null
|
|
3726
|
-
] })
|
|
3727
|
-
]
|
|
3728
|
-
}
|
|
3729
|
-
),
|
|
3730
|
-
collapsed && !opts.mobile ? collapsedHeaderSlot ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-sidebar-border p-2", children: collapsedHeaderSlot }) : null : headerSlot ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-sidebar-border", children: headerSlot }) : null,
|
|
3731
|
-
/* @__PURE__ */ jsx(
|
|
3732
|
-
SidebarNav,
|
|
3733
|
-
{
|
|
3734
|
-
navItems,
|
|
3735
|
-
secondaryNavItems,
|
|
3736
|
-
secondaryNavLabel,
|
|
3737
|
-
showSecondary,
|
|
3738
|
-
collapsed: collapsed && !opts.mobile,
|
|
3739
|
-
density,
|
|
3740
|
-
onNavClick: opts.mobile ? () => setMobileOpen(false) : void 0,
|
|
3741
|
-
linkComponent,
|
|
3742
|
-
activePath,
|
|
3743
|
-
isActive
|
|
3744
|
-
}
|
|
3745
|
-
),
|
|
3746
|
-
(showFooterSlot || showUser || showTheme || collapsed && optionsControl) && !opts.mobile ? /* @__PURE__ */ jsxs("div", { className: "mt-auto shrink-0 space-y-2 border-t border-sidebar-border p-2", children: [
|
|
3747
|
-
showFooterSlot && !collapsed ? footer : null,
|
|
3748
|
-
showUser ? /* @__PURE__ */ jsx(
|
|
3749
|
-
"div",
|
|
3750
|
-
{
|
|
3751
|
-
className: cn(
|
|
3752
|
-
collapsed && "flex justify-center [&_[data-shell-user-detail]]:hidden"
|
|
3753
|
-
),
|
|
3754
|
-
children: userSlot
|
|
3755
|
-
}
|
|
3756
|
-
) : null,
|
|
3757
|
-
/* @__PURE__ */ jsxs(
|
|
3758
|
-
"div",
|
|
3759
|
-
{
|
|
3760
|
-
className: cn(
|
|
3761
|
-
"flex items-center gap-1",
|
|
3762
|
-
collapsed ? "flex-col" : "justify-end"
|
|
3763
|
-
),
|
|
3764
|
-
children: [
|
|
3765
|
-
collapsed ? optionsControl : null,
|
|
3766
|
-
showTheme ? /* @__PURE__ */ jsx(ThemeToggle, { testId: "app-shell-theme-toggle-desktop" }) : null
|
|
3767
|
-
]
|
|
3768
|
-
}
|
|
3769
|
-
)
|
|
3770
|
-
] }) : null,
|
|
3771
|
-
opts.mobile && (showFooterSlot || showUser || showTheme) ? /* @__PURE__ */ jsxs("div", { className: "mt-auto shrink-0 space-y-2 border-t border-sidebar-border p-3", children: [
|
|
3772
|
-
showFooterSlot ? footer : null,
|
|
3773
|
-
showUser ? userSlot : null,
|
|
3774
|
-
showTheme ? /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(ThemeToggle, { testId: "app-shell-theme-toggle-mobile-drawer" }) }) : null
|
|
3775
|
-
] }) : null
|
|
3776
|
-
] });
|
|
3777
|
-
return /* @__PURE__ */ jsxs(
|
|
3778
|
-
"div",
|
|
3079
|
+
if (!data) return /* @__PURE__ */ jsx(NotFound, {});
|
|
3080
|
+
return /* @__PURE__ */ jsx(
|
|
3081
|
+
DetailPage,
|
|
3779
3082
|
{
|
|
3780
|
-
className
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
),
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
className: cn(
|
|
3789
|
-
"hidden flex-col border-r border-sidebar-border bg-sidebar transition-[width] duration-200 md:flex",
|
|
3790
|
-
scrollWindow && "sticky top-0 h-screen",
|
|
3791
|
-
railClass
|
|
3792
|
-
),
|
|
3793
|
-
"data-collapsed": collapsed || void 0,
|
|
3794
|
-
"data-testid": "app-shell-sidebar",
|
|
3795
|
-
children: sidebarChrome({})
|
|
3796
|
-
}
|
|
3797
|
-
),
|
|
3798
|
-
mobileOpen ? /* @__PURE__ */ jsx(
|
|
3799
|
-
"div",
|
|
3800
|
-
{
|
|
3801
|
-
className: "fixed inset-0 z-40 bg-black/50 md:hidden",
|
|
3802
|
-
onClick: () => setMobileOpen(false),
|
|
3803
|
-
"aria-hidden": true
|
|
3804
|
-
}
|
|
3805
|
-
) : null,
|
|
3806
|
-
/* @__PURE__ */ jsx(
|
|
3807
|
-
"aside",
|
|
3808
|
-
{
|
|
3809
|
-
className: cn(
|
|
3810
|
-
"fixed inset-y-0 left-0 z-50 flex w-60 flex-col border-r border-sidebar-border bg-sidebar transition-transform md:hidden",
|
|
3811
|
-
mobileOpen ? "translate-x-0" : "-translate-x-full pointer-events-none"
|
|
3812
|
-
),
|
|
3813
|
-
id: "app-shell-mobile-nav",
|
|
3814
|
-
"aria-hidden": !mobileOpen,
|
|
3815
|
-
inert: !mobileOpen || void 0,
|
|
3816
|
-
children: sidebarChrome({ mobile: true })
|
|
3817
|
-
}
|
|
3818
|
-
),
|
|
3819
|
-
/* @__PURE__ */ jsxs(
|
|
3820
|
-
"div",
|
|
3821
|
-
{
|
|
3822
|
-
className: cn(
|
|
3823
|
-
"flex min-w-0 flex-1 flex-col",
|
|
3824
|
-
!scrollWindow && "overflow-hidden"
|
|
3825
|
-
),
|
|
3826
|
-
children: [
|
|
3827
|
-
/* @__PURE__ */ jsxs(
|
|
3828
|
-
"header",
|
|
3829
|
-
{
|
|
3830
|
-
className: cn(
|
|
3831
|
-
"flex h-14 items-center gap-3 border-b px-4 md:hidden",
|
|
3832
|
-
scrollWindow && "sticky top-0 z-20 bg-background"
|
|
3833
|
-
),
|
|
3834
|
-
children: [
|
|
3835
|
-
/* @__PURE__ */ jsx(
|
|
3836
|
-
Button,
|
|
3837
|
-
{
|
|
3838
|
-
variant: "ghost",
|
|
3839
|
-
size: "icon",
|
|
3840
|
-
onClick: () => setMobileOpen(true),
|
|
3841
|
-
"aria-label": "Open navigation",
|
|
3842
|
-
"aria-expanded": mobileOpen,
|
|
3843
|
-
"aria-controls": "app-shell-mobile-nav",
|
|
3844
|
-
"data-testid": "app-shell-mobile-open",
|
|
3845
|
-
testID: "app-shell-mobile-open",
|
|
3846
|
-
children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
|
|
3847
|
-
}
|
|
3848
|
-
),
|
|
3849
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-semibold", children: appName }),
|
|
3850
|
-
showTheme ? /* @__PURE__ */ jsx(ThemeToggle, { testId: "app-shell-theme-toggle-mobile-header" }) : null
|
|
3851
|
-
]
|
|
3852
|
-
}
|
|
3853
|
-
),
|
|
3854
|
-
/* @__PURE__ */ jsx(
|
|
3855
|
-
"main",
|
|
3856
|
-
{
|
|
3857
|
-
className: cn(
|
|
3858
|
-
"flex-1",
|
|
3859
|
-
!scrollWindow && "overflow-y-auto",
|
|
3860
|
-
showMobileBottom ? "pb-16 md:pb-0" : "pb-0"
|
|
3861
|
-
),
|
|
3862
|
-
children: /* @__PURE__ */ jsx("div", { className: "min-w-0 p-4 sm:p-6 lg:p-8", children })
|
|
3863
|
-
}
|
|
3864
|
-
),
|
|
3865
|
-
showMobileBottom ? /* @__PURE__ */ jsx(
|
|
3866
|
-
"nav",
|
|
3867
|
-
{
|
|
3868
|
-
className: "fixed bottom-0 left-0 right-0 z-30 flex border-t bg-background md:hidden",
|
|
3869
|
-
"aria-label": "Primary",
|
|
3870
|
-
children: bottomItems.map((item) => {
|
|
3871
|
-
const LinkComp = linkComponent;
|
|
3872
|
-
const active = itemIsActive(item, activePath, isActive);
|
|
3873
|
-
return /* @__PURE__ */ jsxs(
|
|
3874
|
-
LinkComp,
|
|
3875
|
-
{
|
|
3876
|
-
href: item.to,
|
|
3877
|
-
title: item.label,
|
|
3878
|
-
"aria-label": item.label,
|
|
3879
|
-
"aria-current": active ? "page" : void 0,
|
|
3880
|
-
className: cn(
|
|
3881
|
-
"flex flex-1 flex-col items-center gap-1 py-2 text-xs font-medium transition-colors",
|
|
3882
|
-
active ? "text-primary" : "text-muted-foreground"
|
|
3883
|
-
),
|
|
3884
|
-
children: [
|
|
3885
|
-
/* @__PURE__ */ jsx(item.icon, { className: "h-5 w-5" }),
|
|
3886
|
-
/* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-0.5", children: item.label })
|
|
3887
|
-
]
|
|
3888
|
-
},
|
|
3889
|
-
item.to + item.label
|
|
3890
|
-
);
|
|
3891
|
-
})
|
|
3892
|
-
}
|
|
3893
|
-
) : null
|
|
3894
|
-
]
|
|
3895
|
-
}
|
|
3896
|
-
)
|
|
3897
|
-
]
|
|
3083
|
+
className,
|
|
3084
|
+
testID,
|
|
3085
|
+
breadcrumb,
|
|
3086
|
+
title: pick(data, titleField),
|
|
3087
|
+
subtitle: subtitleField ? pick(data, subtitleField) : void 0,
|
|
3088
|
+
actions: actions?.(data),
|
|
3089
|
+
sidebar: sidebar?.(data),
|
|
3090
|
+
children: children(data)
|
|
3898
3091
|
}
|
|
3899
3092
|
);
|
|
3900
3093
|
}
|
|
3901
3094
|
|
|
3902
|
-
|
|
3095
|
+
// src/components/data/index.ts
|
|
3096
|
+
var AppShell2 = AppShell;
|
|
3097
|
+
var PageHeader2 = PageHeader;
|
|
3098
|
+
|
|
3099
|
+
export { AppShell2 as AppShell, BadgeCell, CurrencyCell, DataBulkBar, DataFilters, DataGrid, DataList, DataPageShell, DataTable, DateCell, DetailPanel, FieldArrayRenderer, FileUploadField, FilterCombobox, KanbanBoard, LinkCell, NumberCell, PageHeader2 as PageHeader, RelationField, ResourceDetailPage, ResourceForm, ResourcePage, StatCard, ThumbnailCell, WizardForm };
|
|
3903
3100
|
//# sourceMappingURL=index.js.map
|
|
3904
3101
|
//# sourceMappingURL=index.js.map
|