@marktiderman/genesis-ui 2.8.0 → 2.9.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/SKILL.md +58 -4
- package/dist/chunk-DIV4BYXX.js +58 -0
- package/dist/chunk-DIV4BYXX.js.map +1 -0
- package/dist/{chunk-DWCAC2E7.js → chunk-RKPS7ERS.js} +5 -4
- package/dist/chunk-RKPS7ERS.js.map +1 -0
- package/dist/components/data/index.d.ts +88 -25
- package/dist/components/data/index.js +702 -224
- package/dist/components/data/index.js.map +1 -1
- package/dist/components/layout/index.js +7 -7
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/use-resource-page.d.ts +1 -1
- package/dist/hooks/use-resource-page.js +1 -1
- package/dist/hooks/use-resource-url-state.d.ts +68 -0
- package/dist/hooks/use-resource-url-state.js +3 -0
- package/dist/hooks/use-resource-url-state.js.map +1 -0
- package/dist/index.js +19 -19
- package/dist/{use-resource-page-D4byuwAs.d.ts → use-resource-page-BDnnCssE.d.ts} +63 -2
- package/package.json +4 -8
- package/dist/chunk-DWCAC2E7.js.map +0 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export { AppShell, PageHeader } from '../../chunk-UYI3GLFJ.js';
|
|
2
2
|
import '../../chunk-46TZGMFW.js';
|
|
3
3
|
export { Container, Stack, containerVariants, stackVariants } from '../../chunk-4CQHPWJD.js';
|
|
4
|
-
export { DashboardPage, Grid, gridVariants } from '../../chunk-ARJI2JUV.js';
|
|
5
|
-
export { FormPage } from '../../chunk-MPI33I4K.js';
|
|
6
|
-
import '../../chunk-OZZTPE7F.js';
|
|
7
|
-
export { Section, SettingsPage, sectionHeadingVariants } from '../../chunk-P64MFQXZ.js';
|
|
8
4
|
import '../../chunk-B2GIBUQD.js';
|
|
9
5
|
import '../../chunk-NPNADZHM.js';
|
|
10
|
-
export { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
11
|
-
export { Split, splitVariants } from '../../chunk-D2LIXA2Y.js';
|
|
12
|
-
export { GAP_CLASSES, spaceScale } from '../../chunk-AVFZ4P4B.js';
|
|
13
6
|
import '../../chunk-FK42ZGGV.js';
|
|
14
7
|
import '../../chunk-QJ6P2DW6.js';
|
|
15
8
|
import '../../chunk-27ELYTGE.js';
|
|
16
9
|
import '../../chunk-22XB3Q6H.js';
|
|
10
|
+
export { DashboardPage, Grid, gridVariants } from '../../chunk-ARJI2JUV.js';
|
|
11
|
+
export { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
12
|
+
export { FormPage } from '../../chunk-MPI33I4K.js';
|
|
13
|
+
import '../../chunk-OZZTPE7F.js';
|
|
14
|
+
export { Section, SettingsPage, sectionHeadingVariants } from '../../chunk-P64MFQXZ.js';
|
|
15
|
+
export { Split, splitVariants } from '../../chunk-D2LIXA2Y.js';
|
|
16
|
+
export { GAP_CLASSES, spaceScale } from '../../chunk-AVFZ4P4B.js';
|
|
17
17
|
import '../../chunk-NWSCYLPT.js';
|
|
18
18
|
import '../../chunk-F47U5KNW.js';
|
|
19
19
|
import '../../chunk-NZ5WBA4R.js';
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export { ResponsiveViewMode, ViewModeDefault, useViewPreference } from './use-vi
|
|
|
6
6
|
export { Density, ViewSettings, useViewSettings } from './use-view-settings.js';
|
|
7
7
|
export { UseSavedViewsReturn, useSavedViews } from './use-saved-views.js';
|
|
8
8
|
export { RouteMap, createPrefetch } from './use-prefetch.js';
|
|
9
|
-
export {
|
|
9
|
+
export { ResourceUrlParams, ResourceUrlState, ResourceUrlStateOptions, useResourceUrlState } from './use-resource-url-state.js';
|
|
10
|
+
export { R as ResourceActions, a as ResourceColumnDef, U as UseResourcePageProps, b as UseResourcePageReturn, u as useResourcePage } from '../use-resource-page-BDnnCssE.js';
|
|
10
11
|
export { CommandPalette, CommandPaletteItem, CommandPaletteProps, useCommandPaletteHotkey } from '../components/ui/command-palette.js';
|
|
11
12
|
import '../navigation-Bha0R3Fu.js';
|
|
12
13
|
import 'react';
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { useResourcePage } from '../chunk-
|
|
1
|
+
export { useResourcePage } from '../chunk-RKPS7ERS.js';
|
|
2
|
+
export { useResourceUrlState } from '../chunk-DIV4BYXX.js';
|
|
2
3
|
export { useSavedViews } from '../chunk-GCQFVMPI.js';
|
|
3
4
|
export { useViewPreference } from '../chunk-PKFDGGZV.js';
|
|
4
5
|
export { useViewSettings } from '../chunk-OZ7ZAYCS.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'react';
|
|
2
|
-
export { R as ResourceActions, a as ResourceColumnDef, U as UseResourcePageProps, b as UseResourcePageReturn, t as titleCase, u as useResourcePage } from '../use-resource-page-
|
|
2
|
+
export { R as ResourceActions, a as ResourceColumnDef, U as UseResourcePageProps, b as UseResourcePageReturn, t as titleCase, u as useResourcePage } from '../use-resource-page-BDnnCssE.js';
|
|
3
3
|
import '../view-toggle-CahQ87PW.js';
|
|
4
4
|
import '@marktiderman/genesis-core/provider';
|
|
5
5
|
import './use-view-preference.js';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { S as SearchParamsAdapter } from '../navigation-Bha0R3Fu.js';
|
|
2
|
+
import { SortParam } from '@marktiderman/genesis-core/provider';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The query-string names a list keeps its state under. Rename one when two
|
|
7
|
+
* lists share a page, or when `id` already means something in your routes.
|
|
8
|
+
*
|
|
9
|
+
* @stability Beta
|
|
10
|
+
*/
|
|
11
|
+
interface ResourceUrlParams {
|
|
12
|
+
/** The open record's key. Default `"id"`. */
|
|
13
|
+
detail?: string;
|
|
14
|
+
/** The page number (from 1). Default `"page"`. */
|
|
15
|
+
page?: string;
|
|
16
|
+
/** `field:asc` or `field:desc`. Default `"sort"`. */
|
|
17
|
+
sort?: string;
|
|
18
|
+
/** The search text. Default `"q"`. */
|
|
19
|
+
q?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Where a list's state lives in the URL: the router's search params, plus
|
|
23
|
+
* optional names for each value.
|
|
24
|
+
*
|
|
25
|
+
* @stability Beta
|
|
26
|
+
*/
|
|
27
|
+
interface ResourceUrlStateOptions {
|
|
28
|
+
searchParams: SearchParamsAdapter;
|
|
29
|
+
params?: ResourceUrlParams;
|
|
30
|
+
}
|
|
31
|
+
/** @stability Beta */
|
|
32
|
+
interface ResourceUrlState {
|
|
33
|
+
/** The open record's key, or null when no record is open. */
|
|
34
|
+
detailId: string | null;
|
|
35
|
+
/** Open a record (a new history entry, so Back closes it) or close it (null; replaces). */
|
|
36
|
+
setDetailId: (id: string | null) => void;
|
|
37
|
+
/** The page from the URL, or null when absent or not a positive integer. */
|
|
38
|
+
page: number | null;
|
|
39
|
+
/** The sort from the URL, or null. */
|
|
40
|
+
sort: SortParam | null;
|
|
41
|
+
/** The search text from the URL ("" when absent). */
|
|
42
|
+
q: string;
|
|
43
|
+
/**
|
|
44
|
+
* Write page, sort and search. Replaces the history entry (typing a search
|
|
45
|
+
* shouldn't fill Back with every keystroke). A default value (page 1, no
|
|
46
|
+
* sort, empty search) is dropped from the URL; `undefined` leaves a value as is.
|
|
47
|
+
*/
|
|
48
|
+
write: (next: {
|
|
49
|
+
page?: number | null;
|
|
50
|
+
sort?: SortParam | null;
|
|
51
|
+
q?: string;
|
|
52
|
+
}) => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A list's peek, page, sort and search, kept in the URL through any
|
|
56
|
+
* {@link SearchParamsAdapter} (the browser's, React Router's or TanStack
|
|
57
|
+
* Router's). The URL is the source of truth: a copied link reopens the same
|
|
58
|
+
* record on the same page, and Back closes a record that was opened.
|
|
59
|
+
*
|
|
60
|
+
* `ResourcePage` uses it when given `urlState`; a server-controlled page
|
|
61
|
+
* that owns its own page/sort/search can call it directly.
|
|
62
|
+
*
|
|
63
|
+
* @stability Beta
|
|
64
|
+
*/
|
|
65
|
+
declare function useResourceUrlState(options: ResourceUrlStateOptions): ResourceUrlState;
|
|
66
|
+
declare function useResourceUrlState(options: ResourceUrlStateOptions | undefined): ResourceUrlState | undefined;
|
|
67
|
+
|
|
68
|
+
export { type ResourceUrlParams, type ResourceUrlState, type ResourceUrlStateOptions, useResourceUrlState };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"use-resource-url-state.js"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
export { VisuallyHidden } from './chunk-SY62XJFA.js';
|
|
1
2
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from './chunk-VXFYETRK.js';
|
|
2
3
|
export { ToggleGroup, ToggleGroupItem } from './chunk-NUXW6NPP.js';
|
|
3
4
|
export { H1, H2, H3, H4, Large, Lead, Muted, P, Small } from './chunk-HVQCZFJ7.js';
|
|
4
|
-
export { VisuallyHidden } from './chunk-SY62XJFA.js';
|
|
5
5
|
export { Slider } from './chunk-PSR47JRA.js';
|
|
6
|
-
export {
|
|
6
|
+
export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, navigationMenuTriggerStyle } from './chunk-THD3YOOZ.js';
|
|
7
7
|
export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from './chunk-IJCT5IJD.js';
|
|
8
8
|
export { PasswordToggleField, PasswordToggleFieldIcon, PasswordToggleFieldInput, PasswordToggleFieldSlot, PasswordToggleFieldToggle } from './chunk-SRIT4NFQ.js';
|
|
9
9
|
export { RadioGroup, RadioGroupItem } from './chunk-ZZ7H7VVX.js';
|
|
@@ -13,7 +13,6 @@ export { HoverCard, HoverCardContent, HoverCardTrigger } from './chunk-P3ZL6FGR.
|
|
|
13
13
|
export { InputGroup, InputGroupInput, InputGroupPrefix, InputGroupSuffix } from './chunk-GJ6XSCNF.js';
|
|
14
14
|
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from './chunk-K23AQNOM.js';
|
|
15
15
|
export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from './chunk-AL5TMEZQ.js';
|
|
16
|
-
export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, navigationMenuTriggerStyle } from './chunk-THD3YOOZ.js';
|
|
17
16
|
export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from './chunk-6TVMQH6M.js';
|
|
18
17
|
export { DatePicker } from './chunk-6XPMU65K.js';
|
|
19
18
|
export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './chunk-JYPENH7T.js';
|
|
@@ -25,43 +24,44 @@ export { ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartToolt
|
|
|
25
24
|
export { AccessibleIcon } from './chunk-JAMLFMDS.js';
|
|
26
25
|
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './chunk-YWFPMND7.js';
|
|
27
26
|
export { AspectRatio } from './chunk-6Q6CLLJ4.js';
|
|
28
|
-
export { Toolbar, ToolbarButton, ToolbarLink, ToolbarSeparator, ToolbarToggleGroup, ToolbarToggleItem, toolbarVariants } from './chunk-YYEGAFUE.js';
|
|
29
|
-
export { Toggle, toggleVariants } from './chunk-C46ITXE4.js';
|
|
30
|
-
export { Tooltip } from './chunk-G5YKBPBF.js';
|
|
31
|
-
export { Kbd } from './chunk-FFSDFQQN.js';
|
|
32
|
-
export { Container, Stack, containerVariants, stackVariants } from './chunk-4CQHPWJD.js';
|
|
33
|
-
export { DashboardPage, Grid, gridVariants } from './chunk-ARJI2JUV.js';
|
|
34
|
-
export { FormPage } from './chunk-MPI33I4K.js';
|
|
35
|
-
export { Alert, AlertDescription, AlertTitle, alertVariants } from './chunk-OZZTPE7F.js';
|
|
36
|
-
export { Section, SettingsPage, sectionHeadingVariants } from './chunk-P64MFQXZ.js';
|
|
37
27
|
export { SortableList } from './chunk-S7NXD37O.js';
|
|
38
28
|
export { StatusBadge, statusBadgeVariants } from './chunk-XMK3T4TA.js';
|
|
39
29
|
export { ToggleRow } from './chunk-6M4NHHKG.js';
|
|
40
30
|
export { SettingsRow } from './chunk-A7AHVDG7.js';
|
|
41
31
|
export { UserAvatar, userAvatarVariants } from './chunk-XBX6QMR5.js';
|
|
42
32
|
export { Avatar, AvatarFallback, AvatarImage } from './chunk-LNFF2RBD.js';
|
|
33
|
+
export { Toolbar, ToolbarButton, ToolbarLink, ToolbarSeparator, ToolbarToggleGroup, ToolbarToggleItem, toolbarVariants } from './chunk-YYEGAFUE.js';
|
|
34
|
+
export { Toggle, toggleVariants } from './chunk-C46ITXE4.js';
|
|
35
|
+
export { Tooltip } from './chunk-G5YKBPBF.js';
|
|
36
|
+
export { Kbd } from './chunk-FFSDFQQN.js';
|
|
43
37
|
export { renderSlot } from './chunk-7S7LKQBD.js';
|
|
38
|
+
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from './chunk-N2ZFNOOT.js';
|
|
44
39
|
export { Textarea } from './chunk-YETMISCE.js';
|
|
45
40
|
export { Separator } from './chunk-SXSCHWZU.js';
|
|
46
41
|
export { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger } from './chunk-XCGZPFT7.js';
|
|
47
42
|
export { Skeleton } from './chunk-QFM4Z2SS.js';
|
|
48
|
-
export {
|
|
43
|
+
export { Toaster, toast } from './chunk-4RAZJ6LL.js';
|
|
49
44
|
export { Progress } from './chunk-W5Y3LG5K.js';
|
|
50
|
-
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-FN3FZVUR.js';
|
|
51
45
|
export { Checkbox } from './chunk-SEBU6JCK.js';
|
|
46
|
+
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-FN3FZVUR.js';
|
|
52
47
|
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from './chunk-4C4ESW6O.js';
|
|
48
|
+
export { PageLoading, pageLoadingVariants } from './chunk-YRYQXU3G.js';
|
|
49
|
+
export { Spinner } from './chunk-OVU3Z2MT.js';
|
|
53
50
|
export { Input } from './chunk-QSXVL5UB.js';
|
|
51
|
+
export { Container, Stack, containerVariants, stackVariants } from './chunk-4CQHPWJD.js';
|
|
54
52
|
export { Collapsible, CollapsibleContent, CollapsibleTrigger } from './chunk-B2GIBUQD.js';
|
|
55
53
|
export { Badge } from './chunk-NPNADZHM.js';
|
|
56
|
-
export { DetailPage } from './chunk-AFZ76Q26.js';
|
|
57
|
-
export { Split, splitVariants } from './chunk-D2LIXA2Y.js';
|
|
58
|
-
export { GAP_CLASSES, spaceScale } from './chunk-AVFZ4P4B.js';
|
|
59
|
-
export { PageLoading, pageLoadingVariants } from './chunk-YRYQXU3G.js';
|
|
60
|
-
export { Spinner } from './chunk-OVU3Z2MT.js';
|
|
61
54
|
export { Select, SelectContent, SelectGroup, SelectItem, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue } from './chunk-FK42ZGGV.js';
|
|
62
55
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './chunk-QJ6P2DW6.js';
|
|
63
56
|
export { Switch } from './chunk-27ELYTGE.js';
|
|
64
57
|
export { Popover, PopoverContent, PopoverTrigger } from './chunk-22XB3Q6H.js';
|
|
58
|
+
export { DashboardPage, Grid, gridVariants } from './chunk-ARJI2JUV.js';
|
|
59
|
+
export { DetailPage } from './chunk-AFZ76Q26.js';
|
|
60
|
+
export { FormPage } from './chunk-MPI33I4K.js';
|
|
61
|
+
export { Alert, AlertDescription, AlertTitle, alertVariants } from './chunk-OZZTPE7F.js';
|
|
62
|
+
export { Section, SettingsPage, sectionHeadingVariants } from './chunk-P64MFQXZ.js';
|
|
63
|
+
export { Split, splitVariants } from './chunk-D2LIXA2Y.js';
|
|
64
|
+
export { GAP_CLASSES, spaceScale } from './chunk-AVFZ4P4B.js';
|
|
65
65
|
export { EmptyState, NoFeaturesFound, NoFeedbackFound, NoSearchResults } from './chunk-65SPT7EA.js';
|
|
66
66
|
export { Button } from './chunk-NWSCYLPT.js';
|
|
67
67
|
export { FormDescription, FormError, FormField, FormLabel } from './chunk-R7QFP6EL.js';
|
|
@@ -72,8 +72,63 @@ interface DataTableProps<T> {
|
|
|
72
72
|
* - spacious: taller (py-3)
|
|
73
73
|
*/
|
|
74
74
|
density?: Density;
|
|
75
|
+
/**
|
|
76
|
+
* Keyboard use of rows when `onRowClick` is set. Each row's open column
|
|
77
|
+
* (see `openColumn`) is a button named by its content, and the table is
|
|
78
|
+
* one tab stop: Tab reaches the current row's button, Enter or Space
|
|
79
|
+
* opens it, ↑/↓ (or j/k) and Home/End move between rows, and x toggles
|
|
80
|
+
* the row's selection when `selectable`. Default true.
|
|
81
|
+
*/
|
|
82
|
+
keyboardNavigation?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* The column whose cell opens the row (as a button), by key. Default: the
|
|
85
|
+
* first visible column that isn't `editable`. A plain-text cell is wrapped
|
|
86
|
+
* by the button; an `editable` or `render` cell keeps its own content (a
|
|
87
|
+
* link or input stays usable) with the open button beside it, shown when
|
|
88
|
+
* focused. `null` makes no cell a button (mouse only).
|
|
89
|
+
*/
|
|
90
|
+
openColumn?: string | null;
|
|
91
|
+
/**
|
|
92
|
+
* Render only the rows in view, for a long table without pagination
|
|
93
|
+
* (`pagination={false}`). The table scrolls inside a box of `height` px
|
|
94
|
+
* (default 600). Ignored while paginated.
|
|
95
|
+
*/
|
|
96
|
+
virtualize?: boolean | {
|
|
97
|
+
height?: number;
|
|
98
|
+
estimateRowHeight?: number;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Columns that stay in view when the table scrolls sideways, by key, on
|
|
102
|
+
* the left and right. `stickyFirstColumn` is shorthand for pinning the
|
|
103
|
+
* first visible column left.
|
|
104
|
+
*/
|
|
105
|
+
pinnedColumns?: {
|
|
106
|
+
left?: string[];
|
|
107
|
+
right?: string[];
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Let users reorder columns: drag a header, or press Alt+←/→ on its sort
|
|
111
|
+
* button. Default true; the order is kept per device under
|
|
112
|
+
* `columnOrderKey`, and "Reset to defaults" in the Columns menu restores it.
|
|
113
|
+
*/
|
|
114
|
+
reorderableColumns?: boolean;
|
|
115
|
+
/** localStorage key for the user's column order. */
|
|
116
|
+
columnOrderKey?: string;
|
|
117
|
+
/**
|
|
118
|
+
* The header sort, controlled: the first entry is the primary sort, later
|
|
119
|
+
* ones break ties (Shift-click adds one). Leave it unset and the table
|
|
120
|
+
* keeps its own sort, starting unsorted.
|
|
121
|
+
*/
|
|
122
|
+
sort?: readonly DataTableSort[];
|
|
123
|
+
/** Called with the next header sort whenever a header is clicked. */
|
|
124
|
+
onSortChange?: (sort: DataTableSort[]) => void;
|
|
75
125
|
}
|
|
76
|
-
|
|
126
|
+
/** One column of a `DataTable` header sort. */
|
|
127
|
+
interface DataTableSort {
|
|
128
|
+
key: string;
|
|
129
|
+
dir: "asc" | "desc";
|
|
130
|
+
}
|
|
131
|
+
declare function DataTable<T>({ items, columns, getKey, onRowClick, selectable, selected, onToggleSelect, onToggleAll, renderActions, emptyMessage, columnVisibility, columnVisibilityKey, resizableColumns, pagination, pageSize: initialPageSize, pageSizeOptions, stickyHeader, resizeKey, stickyFirstColumn, density, keyboardNavigation, openColumn, virtualize, pinnedColumns, reorderableColumns, columnOrderKey, sort: sortProp, onSortChange, }: DataTableProps<T>): React.JSX.Element;
|
|
77
132
|
declare function ThumbnailCell({ src, alt, }: {
|
|
78
133
|
src?: string | null;
|
|
79
134
|
alt: string;
|
|
@@ -136,6 +191,12 @@ interface UseResourcePageProps<T> {
|
|
|
136
191
|
* a table on desktops); only an explicit pick is persisted.
|
|
137
192
|
*/
|
|
138
193
|
defaultView?: ViewModeDefault;
|
|
194
|
+
/**
|
|
195
|
+
* Where the table/cards/list choice is remembered. Default: `resource`,
|
|
196
|
+
* else one key shared by every keyless page — so pages without a
|
|
197
|
+
* `resource` (rows passed in) should each set their own.
|
|
198
|
+
*/
|
|
199
|
+
viewKey?: string;
|
|
139
200
|
/** Detail interaction mode. */
|
|
140
201
|
detail?: "panel" | "modal" | "route" | "none";
|
|
141
202
|
/** Field used for the detail title. Defaults to first column key. */
|
|
@@ -207,4 +268,4 @@ interface UseResourcePageReturn<T> {
|
|
|
207
268
|
declare function titleCase(str: string): string;
|
|
208
269
|
declare function useResourcePage<T = Record<string, unknown>>(props: UseResourcePageProps<T>): UseResourcePageReturn<T>;
|
|
209
270
|
|
|
210
|
-
export { DataTable as D, LinkCell as L, type ResourceActions as R, ThumbnailCell as T, type UseResourcePageProps as U, type ResourceColumnDef as a, type UseResourcePageReturn as b, type DataTableColumn as c, type DataTableProps as d, titleCase as t, useResourcePage as u };
|
|
271
|
+
export { DataTable as D, LinkCell as L, type ResourceActions as R, ThumbnailCell as T, type UseResourcePageProps as U, type ResourceColumnDef as a, type UseResourcePageReturn as b, type DataTableColumn as c, type DataTableProps as d, type DataTableSort as e, titleCase as t, useResourcePage as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marktiderman/genesis-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -355,7 +355,6 @@
|
|
|
355
355
|
"peerDependencies": {
|
|
356
356
|
"@marktiderman/genesis-design-system": "^1.3.1",
|
|
357
357
|
"@tanstack/react-router": "^1.0.0",
|
|
358
|
-
"@tanstack/react-virtual": "^3.14.0",
|
|
359
358
|
"@tiptap/core": "^3.31.0",
|
|
360
359
|
"@tiptap/extensions": "^3.31.0",
|
|
361
360
|
"@tiptap/pm": "^3.31.0",
|
|
@@ -379,7 +378,9 @@
|
|
|
379
378
|
"vaul": "^1.0.0"
|
|
380
379
|
},
|
|
381
380
|
"dependencies": {
|
|
382
|
-
"@marktiderman/genesis-core": "^1.
|
|
381
|
+
"@marktiderman/genesis-core": "^1.5.0",
|
|
382
|
+
"@tanstack/react-table": "^8.21.3",
|
|
383
|
+
"@tanstack/react-virtual": "^3.14.0",
|
|
383
384
|
"class-variance-authority": "^0.7.1",
|
|
384
385
|
"clsx": "^2.1.1",
|
|
385
386
|
"tailwind-merge": "^3.5.0"
|
|
@@ -403,8 +404,6 @@
|
|
|
403
404
|
"@radix-ui/react-toggle-group": "^1.1.0",
|
|
404
405
|
"@tanstack/react-query": "^5.75.0",
|
|
405
406
|
"@tanstack/react-router": "1.170.41",
|
|
406
|
-
"@tanstack/react-table": "^8.21.3",
|
|
407
|
-
"@tanstack/react-virtual": "3.14.13",
|
|
408
407
|
"@testing-library/react": "^16.3.2",
|
|
409
408
|
"@tiptap/core": "3.31.4",
|
|
410
409
|
"@tiptap/extensions": "3.31.4",
|
|
@@ -437,9 +436,6 @@
|
|
|
437
436
|
"@tanstack/react-router": {
|
|
438
437
|
"optional": true
|
|
439
438
|
},
|
|
440
|
-
"@tanstack/react-virtual": {
|
|
441
|
-
"optional": true
|
|
442
|
-
},
|
|
443
439
|
"@tiptap/core": {
|
|
444
440
|
"optional": true
|
|
445
441
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-resource-page.ts"],"names":[],"mappings":"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","file":"chunk-DWCAC2E7.js","sourcesContent":["\"use client\";\n\nimport { useState, useMemo, useCallback, useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { DataTableColumn } from \"../components/data/DataTable\";\nimport type { DataFilterConfig } from \"../components/data/DataFilters\";\nimport type { ViewMode } from \"../components/patterns/view-toggle\";\nimport type { Identifier, FilterParam, SortParam } from \"@marktiderman/genesis-core/provider\";\nimport { useViewPreference, type ViewModeDefault } from \"./use-view-preference\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Actions available inside column render functions. */\nexport interface ResourceActions<T> {\n update: (id: Identifier, data: Partial<T>) => Promise<T>;\n remove: (id: Identifier) => Promise<void>;\n refetch: () => void;\n}\n\n/** Column definition — full config form. */\nexport interface ResourceColumnDef<T> {\n key: string;\n header?: string;\n sortable?: boolean;\n hideBelow?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n /** Starting width, passed straight through to `DataTable` (a number is px). */\n width?: DataTableColumn<T>[\"width\"];\n /** Smallest width the user can resize to, in px. Passed through to `DataTable`. */\n minWidth?: number;\n /** Whether the column shows before the user picks columns. Default true. */\n defaultVisible?: boolean;\n render?: (\n item: T,\n value: unknown,\n actions: ResourceActions<T>,\n ) => ReactNode;\n /** In-place cell editing, passed straight through to `DataTable`. */\n editable?: DataTableColumn<T>[\"editable\"];\n /**\n * The cell's value, when it isn't `item[key]`. Passed straight through to\n * `DataTable`, which also starts an edit from `String(accessor(item))`.\n */\n accessor?: (item: T) => unknown;\n}\n\nexport interface UseResourcePageProps<T> {\n /** Resource name — used for view-preference storage key. */\n resource?: string;\n /** The data to display (pre-fetched or from useResource). */\n data: T[];\n /** Total count of records (before client-side filtering). */\n total: number;\n /** Column definitions. Strings are expanded to `{ key, header, sortable }`. Omit to auto-generate from data keys. */\n columns?: Array<string | ResourceColumnDef<T>>;\n /** Status filter config. String = field name (options auto-derived). Object = explicit field + options. */\n statusFilter?: string | { field: string; options?: string[] };\n /** Fields to search across. Defaults to all string-valued fields in data. */\n searchFields?: string[];\n /** Initial filter params applied on mount. */\n initialFilters?: FilterParam[];\n /** Callback when filters change. */\n onFiltersChange?: (filters: FilterParam[]) => void;\n /**\n * Default view mode, used until the user picks one. Pass\n * `{ mobile, desktop }` for a viewport-dependent default (cards on phones,\n * a table on desktops); only an explicit pick is persisted.\n */\n defaultView?: ViewModeDefault;\n /** Detail interaction mode. */\n detail?: \"panel\" | \"modal\" | \"route\" | \"none\";\n /** Field used for the detail title. Defaults to first column key. */\n titleField?: string;\n /** Field used for the detail subtitle. Defaults to second column key. */\n subtitleField?: string;\n /**\n * Server-controlled mode. The `data` handed in has ALREADY been searched,\n * sorted and paginated by the server, so this hook must not do any of it a\n * second time — `data` is returned untouched and `total` is the server's\n * `total` rather than the length of a client-filtered slice.\n *\n * Search / sort / status state is still tracked (the filter UI stays\n * controlled and `onFiltersChange` still fires) — only the client-side\n * transform of `data` is skipped. Defaults to `false`, so every existing\n * caller keeps its current client-side behavior.\n */\n controlled?: boolean;\n}\n\nexport interface UseResourcePageReturn<T> {\n /** Filtered and sorted data for display. */\n data: T[];\n /** Total count (of the filtered set; the server's `total` when `controlled`). */\n total: number;\n /** Resolved column definitions. */\n columns: ResourceColumnDef<T>[];\n /** Columns mapped to DataTable format. */\n tableColumns: DataTableColumn<T>[];\n /** Ready-to-spread filter config for DataFilters. */\n filterConfig: {\n search: string;\n onSearchChange: (value: string) => void;\n sort: string;\n onSortChange: (sort: string) => void;\n sortOptions: Array<{ value: string; label: string }>;\n statusChips?: {\n options: string[];\n selected: string[];\n onChange: (values: string[]) => void;\n };\n };\n viewMode: ViewMode;\n setViewMode: (mode: ViewMode) => void;\n search: string;\n setSearch: (value: string) => void;\n sort: SortParam | null;\n setSort: (sort: SortParam | null) => void;\n statusValue: string[];\n setStatusValue: (values: string[]) => void;\n selectedItem: T | null;\n setSelectedItem: (item: T | null) => void;\n detailOpen: boolean;\n setDetailOpen: (open: boolean) => void;\n handleRowClick: (item: T) => void;\n titleField: string;\n subtitleField: string;\n statusOptions: string[];\n hasActiveFilters: boolean;\n clearFilters: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a key string to title case.\n * \"created_at\" → \"Created At\"\n * \"firstName\" → \"First Name\"\n */\nexport function titleCase(str: string): string {\n // Split on underscores, hyphens, and camelCase boundaries\n const words = str\n .replace(/([a-z])([A-Z])/g, \"$1 $2\") // camelCase → camel Case\n .replace(/[_-]/g, \" \") // snake_case / kebab-case → spaces\n .split(/\\s+/)\n .filter(Boolean);\n\n return words\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\" \");\n}\n\n/**\n * Resolve column shorthand into full ResourceColumnDef objects.\n * - undefined + data present → auto-generate from Object.keys(data[0]), skip \"id\"\n * - undefined + empty data → empty array\n * - string items → { key, header: titleCase(key), sortable: true }\n * - object items → defaults applied\n */\nfunction resolveColumns<T>(\n columns: Array<string | ResourceColumnDef<T>> | undefined,\n data: T[],\n): ResourceColumnDef<T>[] {\n if (columns === undefined) {\n if (data.length === 0) return [];\n const keys = Object.keys(data[0] as Record<string, unknown>).filter(\n (k) => k !== \"id\",\n );\n return keys.map((key) => ({\n key,\n header: titleCase(key),\n sortable: true,\n }));\n }\n\n return columns.map((col) => {\n if (typeof col === \"string\") {\n return { key: col, header: titleCase(col), sortable: true };\n }\n return {\n ...col,\n header: col.header ?? titleCase(col.key),\n sortable: col.sortable ?? true,\n };\n });\n}\n\n/**\n * Derive the list of string fields in a data set (for default search).\n */\nfunction deriveStringFields<T>(data: T[]): string[] {\n if (data.length === 0) return [];\n const first = data[0] as Record<string, unknown>;\n return Object.keys(first).filter((k) => typeof first[k] === \"string\");\n}\n\n/**\n * Derive unique status options from a data array.\n */\nfunction deriveStatusOptions<T>(data: T[], field: string): string[] {\n const values = new Set<string>();\n for (const item of data) {\n const val = (item as Record<string, unknown>)[field];\n if (val != null) values.add(String(val));\n }\n return Array.from(values).sort();\n}\n\n/**\n * Client-side text search across multiple fields.\n */\nfunction matchesSearch<T>(\n item: T,\n query: string,\n fields: string[],\n): boolean {\n if (!query) return true;\n const lower = query.toLowerCase();\n const record = item as Record<string, unknown>;\n return fields.some((f) => {\n const val = record[f];\n return val != null && String(val).toLowerCase().includes(lower);\n });\n}\n\n/**\n * Client-side sort comparator.\n */\nfunction compareItems<T>(a: T, b: T, sort: SortParam): number {\n const ra = a as Record<string, unknown>;\n const rb = b as Record<string, unknown>;\n const va = ra[sort.field];\n const vb = rb[sort.field];\n const sa = va == null ? \"\" : String(va);\n const sb = vb == null ? \"\" : String(vb);\n const cmp = sa.localeCompare(sb, undefined, {\n numeric: true,\n sensitivity: \"base\",\n });\n return sort.order === \"asc\" ? cmp : -cmp;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport function useResourcePage<T = Record<string, unknown>>(\n props: UseResourcePageProps<T>,\n): UseResourcePageReturn<T> {\n const {\n resource,\n data: rawData,\n total: rawTotal,\n columns: columnsProp,\n statusFilter: statusFilterProp,\n searchFields: searchFieldsProp,\n defaultView = \"table\",\n detail = \"panel\",\n titleField: titleFieldProp,\n subtitleField: subtitleFieldProp,\n initialFilters,\n onFiltersChange,\n controlled = false,\n } = props;\n\n // -- View mode --\n const [viewMode, setViewMode] = useViewPreference(\n resource ?? \"resource-page\",\n defaultView,\n );\n\n // -- Derive initial values from initialFilters --\n const initialSearch = useMemo(() => {\n if (!initialFilters) return \"\";\n const searchFilter = initialFilters.find(\n (f) => f.operator === \"contains\" && f.field === \"__search__\",\n );\n return searchFilter && \"value\" in searchFilter ? String(searchFilter.value ?? \"\") : \"\";\n }, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount\n\n const initialSort = useMemo(() => {\n if (!initialFilters) return null;\n const sortFilter = initialFilters.find(\n (f) => f.field === \"__sort__\",\n );\n if (!sortFilter || !(\"value\" in sortFilter) || typeof sortFilter.value !== \"string\") return null;\n const [field, order] = sortFilter.value.split(\":\");\n if (!field || (order !== \"asc\" && order !== \"desc\")) return null;\n return { field, order } as SortParam;\n }, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount\n\n const initialStatus = useMemo(() => {\n if (!initialFilters) return [];\n const statusFilter = initialFilters.find(\n (f) => f.operator === \"in\" && f.field === \"__status__\",\n );\n if (!statusFilter || statusFilter.operator !== \"in\") return [];\n return statusFilter.value.map((v) => String(v));\n }, []); // eslint-disable-line react-hooks/exhaustive-deps -- only on mount\n\n // -- Search --\n const [search, setSearch] = useState(initialSearch);\n\n // -- Sort --\n const [sort, setSort] = useState<SortParam | null>(initialSort);\n\n // -- Status filter --\n const [statusValue, setStatusValue] = useState<string[]>(initialStatus);\n\n // -- Detail panel --\n const [selectedItem, setSelectedItem] = useState<T | null>(null);\n const [detailOpen, setDetailOpen] = useState(false);\n\n // -- Resolve columns --\n const resolvedColumns = useMemo(\n () => resolveColumns(columnsProp, rawData),\n [columnsProp, rawData],\n );\n\n // -- Title / subtitle fields --\n const titleField =\n titleFieldProp ?? resolvedColumns[0]?.key ?? \"name\";\n const subtitleField =\n subtitleFieldProp ?? resolvedColumns[1]?.key ?? \"\";\n\n // -- Status filter config --\n const statusFieldName = useMemo(() => {\n if (!statusFilterProp) return null;\n return typeof statusFilterProp === \"string\"\n ? statusFilterProp\n : statusFilterProp.field;\n }, [statusFilterProp]);\n\n const statusOptions = useMemo(() => {\n if (!statusFilterProp) return [];\n if (typeof statusFilterProp === \"object\" && statusFilterProp.options) {\n return statusFilterProp.options;\n }\n if (!statusFieldName) return [];\n return deriveStatusOptions(rawData, statusFieldName);\n }, [statusFilterProp, statusFieldName, rawData]);\n\n // -- Search fields --\n const searchFields = useMemo(\n () => searchFieldsProp ?? deriveStringFields(rawData),\n [searchFieldsProp, rawData],\n );\n\n // -- Client-side filtering + sorting --\n // Skipped entirely in controlled mode: the server already applied the\n // search, the sort and the page window, so re-running them here would\n // filter the current page against a query the server has already honoured\n // (and re-sort a slice of rows that is not the full result set).\n const filteredData = useMemo(() => {\n if (controlled) return rawData;\n\n let result = rawData;\n\n // Text search\n if (search) {\n result = result.filter((item) =>\n matchesSearch(item, search, searchFields),\n );\n }\n\n // Status filter\n if (statusFieldName && statusValue.length > 0) {\n result = result.filter((item) => {\n const val = (item as Record<string, unknown>)[statusFieldName];\n return val != null && statusValue.includes(String(val));\n });\n }\n\n // Sort\n if (sort) {\n result = [...result].sort((a, b) => compareItems(a, b, sort));\n }\n\n return result;\n }, [controlled, rawData, search, searchFields, statusFieldName, statusValue, sort]);\n\n // -- Sort options (built from resolved columns) --\n const sortOptions = useMemo(() => {\n const opts: Array<{ value: string; label: string }> = [];\n for (const col of resolvedColumns) {\n if (col.sortable !== false) {\n opts.push({\n value: `${col.key}:asc`,\n label: `${col.header ?? titleCase(col.key)} (A-Z)`,\n });\n opts.push({\n value: `${col.key}:desc`,\n label: `${col.header ?? titleCase(col.key)} (Z-A)`,\n });\n }\n }\n return opts;\n }, [resolvedColumns]);\n\n // -- Sort string for DataFilters select --\n const sortString = sort ? `${sort.field}:${sort.order}` : \"\";\n\n const handleSortChange = useCallback((value: string) => {\n if (!value) {\n setSort(null);\n return;\n }\n const [field, order] = value.split(\":\");\n setSort({ field, order: order as \"asc\" | \"desc\" });\n }, []);\n\n // -- Map to DataTableColumn --\n const tableColumns: DataTableColumn<T>[] = useMemo(\n () =>\n resolvedColumns.map((col) => ({\n key: col.key,\n header: col.header ?? titleCase(col.key),\n sortable: col.sortable ?? true,\n hideBelow: col.hideBelow,\n width: col.width,\n minWidth: col.minWidth,\n defaultVisible: col.defaultVisible,\n editable: col.editable,\n accessor: col.accessor,\n render: col.render\n ? (item: T, value: unknown) =>\n col.render!(item, value, {\n update: async () => {\n throw new Error(\n \"ResourceActions.update not available in server-data mode\",\n );\n },\n remove: async () => {\n throw new Error(\n \"ResourceActions.remove not available in server-data mode\",\n );\n },\n refetch: () => {\n /* no-op in server-data mode */\n },\n })\n : undefined,\n })),\n [resolvedColumns],\n );\n\n // -- Active filters check --\n const hasActiveFilters =\n search !== \"\" || statusValue.length > 0 || sort !== null;\n\n const clearFilters = useCallback(() => {\n setSearch(\"\");\n setStatusValue([]);\n setSort(null);\n }, []);\n\n // -- Notify parent of filter changes --\n const onFiltersChangeRef = useRef(onFiltersChange);\n onFiltersChangeRef.current = onFiltersChange;\n\n useEffect(() => {\n if (!onFiltersChangeRef.current) return;\n const filters: FilterParam[] = [];\n if (search) {\n filters.push({ field: \"__search__\", operator: \"contains\", value: search });\n }\n if (sort) {\n filters.push({ field: \"__sort__\", operator: \"eq\", value: `${sort.field}:${sort.order}` });\n }\n if (statusValue.length > 0) {\n filters.push({ field: \"__status__\", operator: \"in\", value: statusValue });\n }\n onFiltersChangeRef.current(filters);\n }, [search, sort, statusValue]);\n\n // -- Row click --\n const handleRowClick = useCallback(\n (item: T) => {\n if (detail === \"none\") return;\n setSelectedItem(item);\n setDetailOpen(true);\n },\n [detail],\n );\n\n // -- Filter config (ready to spread into DataFilters) --\n const filterConfig = useMemo(\n () => ({\n search,\n onSearchChange: setSearch,\n sort: sortString,\n onSortChange: handleSortChange,\n sortOptions,\n ...(statusFieldName && statusOptions.length > 0\n ? {\n statusChips: {\n options: statusOptions,\n selected: statusValue,\n onChange: setStatusValue,\n },\n }\n : {}),\n }),\n [\n search,\n sortString,\n handleSortChange,\n sortOptions,\n statusFieldName,\n statusOptions,\n statusValue,\n ],\n );\n\n return {\n data: filteredData,\n // Controlled mode: `filteredData` is one server page, so its length is\n // not the record count — the server's total is.\n total: controlled ? rawTotal : filteredData.length,\n columns: resolvedColumns,\n tableColumns,\n filterConfig,\n viewMode,\n setViewMode,\n search,\n setSearch,\n sort,\n setSort,\n statusValue,\n setStatusValue,\n selectedItem,\n setSelectedItem,\n detailOpen,\n setDetailOpen,\n handleRowClick,\n titleField,\n subtitleField,\n statusOptions,\n hasActiveFilters,\n clearFilters,\n };\n}\n"]}
|