@marktiderman/genesis-ui 2.10.1 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/SKILL.md +59 -1
  2. package/dist/AppShell-DpQdcLE-.d.ts +347 -0
  3. package/dist/{chunk-C7PQ54JI.js → chunk-3TWCZYZY.js} +43 -13
  4. package/dist/chunk-3TWCZYZY.js.map +1 -0
  5. package/dist/{chunk-WGMEVX3Y.js → chunk-KC43CNMA.js} +2 -2
  6. package/dist/{chunk-WGMEVX3Y.js.map → chunk-KC43CNMA.js.map} +1 -1
  7. package/dist/{chunk-UYI3GLFJ.js → chunk-SZMXNC5Q.js} +722 -159
  8. package/dist/chunk-SZMXNC5Q.js.map +1 -0
  9. package/dist/{chunk-OITWCIG2.js → chunk-XGG5RUDE.js} +3 -3
  10. package/dist/{chunk-OITWCIG2.js.map → chunk-XGG5RUDE.js.map} +1 -1
  11. package/dist/components/data/index.d.ts +5 -5
  12. package/dist/components/data/index.js +32 -6
  13. package/dist/components/data/index.js.map +1 -1
  14. package/dist/components/layout/index.d.ts +2 -2
  15. package/dist/components/layout/index.js +3 -2
  16. package/dist/components/rich-text/rich-text-editor.js +1 -1
  17. package/dist/hooks/index.d.ts +2 -2
  18. package/dist/hooks/index.js +3 -3
  19. package/dist/hooks/use-data-filters.d.ts +1 -1
  20. package/dist/hooks/use-data-filters.js +2 -2
  21. package/dist/hooks/use-resource-url-state.d.ts +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +2 -2
  24. package/dist/{navigation-Bha0R3Fu.d.ts → navigation-By1DrzaM.d.ts} +24 -0
  25. package/dist/router/react-router.d.ts +1 -1
  26. package/dist/router/tanstack-router.d.ts +1 -1
  27. package/dist/router/tanstack-router.js +1 -1
  28. package/dist/{use-resource-table-DCVf_lEG.d.ts → use-resource-table-DrTkD5O1.d.ts} +32 -3
  29. package/package.json +4 -3
  30. package/dist/AppShell-BVr4V0UK.d.ts +0 -174
  31. package/dist/chunk-C7PQ54JI.js.map +0 -1
  32. package/dist/chunk-UYI3GLFJ.js.map +0 -1
@@ -1,5 +1,5 @@
1
- export { A as AppShell, a as AppShellOptions, b as AppShellProps, N as NavItem, P as ParentNavigation } from '../../AppShell-BVr4V0UK.js';
2
- export { G as GenesisLinkProps, L as LinkComponent, N as NavigationNode, R as ResolvedNavigation, r as resolveNavigation } from '../../navigation-Bha0R3Fu.js';
1
+ export { A as AppShell, a as AppShellOptions, b as AppShellPageHeader, c as AppShellProps, d as AppShellSubNavEnd, N as NavItem, P as ParentNavigation, S as SubNavItem, e as SubNavMode, f as SubNavTabs, g as SubNavTabsProps, U as UseAppShellSubNavOptions, u as useAppShellSubNav } from '../../AppShell-DpQdcLE-.js';
2
+ export { G as GenesisLinkProps, L as LinkComponent, N as NavigationNode, R as ResolvedNavigation, r as resolveNavigation } from '../../navigation-By1DrzaM.js';
3
3
  export { P as PageHeader, a as PageHeaderOptions, b as PageHeaderProps } from '../../PageHeader-V9lVkZtF.js';
4
4
  export { DetailPage, DetailPageProps } from './detail-page.js';
5
5
  export { FormPage, FormPageProps } from './form-page.js';
@@ -1,4 +1,4 @@
1
- export { AppShell, PageHeader } from '../../chunk-UYI3GLFJ.js';
1
+ export { AppShell, AppShellPageHeader, AppShellSubNavEnd, PageHeader, SubNavTabs, useAppShellSubNav } from '../../chunk-SZMXNC5Q.js';
2
2
  import '../../chunk-46TZGMFW.js';
3
3
  export { Container, Stack, containerVariants, stackVariants } from '../../chunk-4CQHPWJD.js';
4
4
  import '../../chunk-B2GIBUQD.js';
@@ -6,6 +6,7 @@ import '../../chunk-NPNADZHM.js';
6
6
  import '../../chunk-FK42ZGGV.js';
7
7
  import '../../chunk-QJ6P2DW6.js';
8
8
  import '../../chunk-27ELYTGE.js';
9
+ import '../../chunk-G5YKBPBF.js';
9
10
  import '../../chunk-22XB3Q6H.js';
10
11
  export { DashboardPage, Grid, gridVariants } from '../../chunk-ARJI2JUV.js';
11
12
  export { DetailPage } from '../../chunk-AFZ76Q26.js';
@@ -17,6 +18,6 @@ export { GAP_CLASSES, spaceScale } from '../../chunk-AVFZ4P4B.js';
17
18
  import '../../chunk-NWSCYLPT.js';
18
19
  import '../../chunk-F47U5KNW.js';
19
20
  import '../../chunk-NZ5WBA4R.js';
20
- export { resolveNavigation } from '../../chunk-WGMEVX3Y.js';
21
+ export { resolveNavigation } from '../../chunk-KC43CNMA.js';
21
22
  //# sourceMappingURL=index.js.map
22
23
  //# sourceMappingURL=index.js.map
@@ -2,9 +2,9 @@
2
2
  import { parseVideoUrl, sanitizeVideoEmbedAttrs, videoEmbedTitle, VIDEO_IFRAME_ATTRS, videoEmbedSrc, isRichTextDoc, isSafeUrl, sanitizeRichTextDoc, richTextClassName, richTextToHtml, RichText, normalizeLinkUrl, isRichTextEmpty, richTextToPlainText } from '../../chunk-ZDHWNQTR.js';
3
3
  import { ToolbarButton, Toolbar, ToolbarSeparator, ToolbarToggleGroup, ToolbarToggleItem } from '../../chunk-YYEGAFUE.js';
4
4
  import '../../chunk-C46ITXE4.js';
5
- import { Tooltip } from '../../chunk-G5YKBPBF.js';
6
5
  import { Kbd } from '../../chunk-FFSDFQQN.js';
7
6
  import { Input } from '../../chunk-QSXVL5UB.js';
7
+ import { Tooltip } from '../../chunk-G5YKBPBF.js';
8
8
  import { Popover, PopoverTrigger, PopoverContent } from '../../chunk-22XB3Q6H.js';
9
9
  import { Button } from '../../chunk-NWSCYLPT.js';
10
10
  import { Label } from '../../chunk-F47U5KNW.js';
@@ -6,11 +6,11 @@ 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 { R as ResourceTableState, u as useResourceTable } from '../use-resource-table-DCVf_lEG.js';
9
+ export { R as ResourceTableState, u as useResourceTable } from '../use-resource-table-DrTkD5O1.js';
10
10
  export { ResourceUrlParams, ResourceUrlState, ResourceUrlStateOptions, useResourceUrlState } from './use-resource-url-state.js';
11
11
  export { R as ResourceActions, a as ResourceColumnDef, U as UseResourcePageProps, b as UseResourcePageReturn, u as useResourcePage } from '../use-resource-page-DaJzuq3M.js';
12
12
  export { CommandPalette, CommandPaletteItem, CommandPaletteProps, useCommandPaletteHotkey } from '../components/ui/command-palette.js';
13
- import '../navigation-Bha0R3Fu.js';
13
+ import '../navigation-By1DrzaM.js';
14
14
  import 'react';
15
15
  import '../view-toggle-CahQ87PW.js';
16
16
  import 'lucide-react';
@@ -1,4 +1,4 @@
1
- export { useResourceTable } from '../chunk-C7PQ54JI.js';
1
+ export { useResourceTable } from '../chunk-3TWCZYZY.js';
2
2
  export { useResourcePage } from '../chunk-RKPS7ERS.js';
3
3
  export { useResourceUrlState } from '../chunk-DIV4BYXX.js';
4
4
  export { useSavedViews } from '../chunk-GCQFVMPI.js';
@@ -9,8 +9,8 @@ export { CommandPalette, useCommandPaletteHotkey } from '../chunk-CNTWQSUT.js';
9
9
  import '../chunk-SEFK4NZV.js';
10
10
  import '../chunk-7XMZVISM.js';
11
11
  import '../chunk-NZ5WBA4R.js';
12
- export { useDataFilters } from '../chunk-OITWCIG2.js';
13
- import '../chunk-WGMEVX3Y.js';
12
+ export { useDataFilters } from '../chunk-XGG5RUDE.js';
13
+ import '../chunk-KC43CNMA.js';
14
14
  export { useKeyboardNavigation } from '../chunk-YJ6MPS6U.js';
15
15
  export { useIsMobile } from '../chunk-VFO3I7PV.js';
16
16
  export { createPrefetch } from '../chunk-HSHIZHYR.js';
@@ -1,4 +1,4 @@
1
- import { S as SearchParamsAdapter } from '../navigation-Bha0R3Fu.js';
1
+ import { S as SearchParamsAdapter } from '../navigation-By1DrzaM.js';
2
2
  import 'react';
3
3
 
4
4
  type FilterType = "string" | "multi";
@@ -1,4 +1,4 @@
1
- export { useDataFilters } from '../chunk-OITWCIG2.js';
2
- import '../chunk-WGMEVX3Y.js';
1
+ export { useDataFilters } from '../chunk-XGG5RUDE.js';
2
+ import '../chunk-KC43CNMA.js';
3
3
  //# sourceMappingURL=use-data-filters.js.map
4
4
  //# sourceMappingURL=use-data-filters.js.map
@@ -1,4 +1,4 @@
1
- import { S as SearchParamsAdapter } from '../navigation-Bha0R3Fu.js';
1
+ import { S as SearchParamsAdapter } from '../navigation-By1DrzaM.js';
2
2
  import { SortParam } from '@marktiderman/genesis-core/provider';
3
3
  import 'react';
4
4
 
package/dist/index.d.ts CHANGED
@@ -68,7 +68,7 @@ export { DetailPage, DetailPageProps } from './components/layout/detail-page.js'
68
68
  export { FormPage, FormPageProps } from './components/layout/form-page.js';
69
69
  export { SettingsPage, SettingsPageProps, SettingsPageSection } from './components/layout/settings-page.js';
70
70
  export { cn } from './utils.js';
71
- export { D as DefaultLink, G as GenesisLinkProps, I as IsPathActiveOptions, L as LinkComponent, a as NavigateFn, N as NavigationNode, R as ResolvedNavigation, S as SearchParamsAdapter, d as defaultNavigate, i as isPathActive, r as resolveNavigation, u as useBrowserSearchParams } from './navigation-Bha0R3Fu.js';
71
+ export { D as DefaultLink, G as GenesisLinkProps, I as IsPathActiveOptions, L as LinkComponent, a as NavigateFn, N as NavigationNode, R as ResolvedNavigation, S as SearchParamsAdapter, d as defaultNavigate, i as isPathActive, r as resolveNavigation, u as useBrowserSearchParams } from './navigation-By1DrzaM.js';
72
72
  export { S as SlotOverride, a as SlotPropsFor, b as Slots, r as renderSlot } from './slots-tR0wf89f.js';
73
73
  export { toast } from 'sonner';
74
74
  import 'class-variance-authority/types';
package/dist/index.js CHANGED
@@ -32,7 +32,6 @@ export { UserAvatar, userAvatarVariants } from './chunk-XBX6QMR5.js';
32
32
  export { Avatar, AvatarFallback, AvatarImage } from './chunk-LNFF2RBD.js';
33
33
  export { Toolbar, ToolbarButton, ToolbarLink, ToolbarSeparator, ToolbarToggleGroup, ToolbarToggleItem, toolbarVariants } from './chunk-YYEGAFUE.js';
34
34
  export { Toggle, toggleVariants } from './chunk-C46ITXE4.js';
35
- export { Tooltip } from './chunk-G5YKBPBF.js';
36
35
  export { Kbd } from './chunk-FFSDFQQN.js';
37
36
  export { renderSlot } from './chunk-7S7LKQBD.js';
38
37
  export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from './chunk-N2ZFNOOT.js';
@@ -54,6 +53,7 @@ export { Badge } from './chunk-NPNADZHM.js';
54
53
  export { Select, SelectContent, SelectGroup, SelectItem, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue } from './chunk-FK42ZGGV.js';
55
54
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './chunk-QJ6P2DW6.js';
56
55
  export { Switch } from './chunk-27ELYTGE.js';
56
+ export { Tooltip } from './chunk-G5YKBPBF.js';
57
57
  export { Popover, PopoverContent, PopoverTrigger } from './chunk-22XB3Q6H.js';
58
58
  export { DashboardPage, Grid, gridVariants } from './chunk-ARJI2JUV.js';
59
59
  export { DetailPage } from './chunk-AFZ76Q26.js';
@@ -71,6 +71,6 @@ export { CommandPalette, useCommandPaletteHotkey } from './chunk-CNTWQSUT.js';
71
71
  export { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from './chunk-SEFK4NZV.js';
72
72
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-7XMZVISM.js';
73
73
  export { cn } from './chunk-NZ5WBA4R.js';
74
- export { DefaultLink, defaultNavigate, isPathActive, resolveNavigation, useBrowserSearchParams } from './chunk-WGMEVX3Y.js';
74
+ export { DefaultLink, defaultNavigate, isPathActive, resolveNavigation, useBrowserSearchParams } from './chunk-KC43CNMA.js';
75
75
  //# sourceMappingURL=index.js.map
76
76
  //# sourceMappingURL=index.js.map
@@ -92,6 +92,30 @@ interface NavigationNode<T> {
92
92
  /** Contextual nav items to show while this node is current. */
93
93
  items: T[];
94
94
  children?: NavigationNode<T>[];
95
+ /**
96
+ * Ask the app shell to open its desktop sidebar collapsed (icon rail) while
97
+ * this node, or a descendant that doesn't set its own value, is current.
98
+ * The nearest node in the resolved trail that sets it wins, so
99
+ * `defaultCollapsed: false` on a child re-opens it under a collapsed
100
+ * parent. Only a default: once the user has toggled the sidebar, their
101
+ * choice wins everywhere. `AppShell` reads it; `resolveNavigation` copies
102
+ * it through untouched.
103
+ *
104
+ * @stability Beta
105
+ */
106
+ defaultCollapsed?: boolean;
107
+ /**
108
+ * How the app shell shows this node's `items` (its child pages, e.g. a
109
+ * form's Questions / Logic / Responses / Settings). `"tabs"` (across the
110
+ * top of the content) or `"sidebar"` (nested under the active item) turn
111
+ * shell sub-navigation on, which also gives phones a back item plus the
112
+ * children in the bottom bar. `"section"` is the legacy rendering (the
113
+ * shell's default) and `"off"` hides them. The nearest node in the trail
114
+ * that sets it wins over the shell's `options.subNav`.
115
+ *
116
+ * @stability Beta
117
+ */
118
+ subNav?: "section" | "tabs" | "sidebar" | "off";
95
119
  }
96
120
  /**
97
121
  * Result of {@link resolveNavigation}. `current`, `parent` and every `trail`
@@ -1,4 +1,4 @@
1
- import { L as LinkComponent, a as NavigateFn, S as SearchParamsAdapter } from '../navigation-Bha0R3Fu.js';
1
+ import { L as LinkComponent, a as NavigateFn, S as SearchParamsAdapter } from '../navigation-By1DrzaM.js';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { L as LinkComponent, a as NavigateFn, S as SearchParamsAdapter } from '../navigation-Bha0R3Fu.js';
1
+ import { L as LinkComponent, a as NavigateFn, S as SearchParamsAdapter } from '../navigation-By1DrzaM.js';
2
2
  import 'react';
3
3
 
4
4
  /**
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { isExternalHref, splitNavigationHref } from '../chunk-FUVWKTPL.js';
3
- import { DefaultLink } from '../chunk-WGMEVX3Y.js';
3
+ import { DefaultLink } from '../chunk-KC43CNMA.js';
4
4
  import { useCallback, useMemo } from 'react';
5
5
  import { useRouter, useRouterState, useLinkProps } from '@tanstack/react-router';
6
6
  import { jsx } from 'react/jsx-runtime';
@@ -12,7 +12,7 @@ import { b as Slots, a as SlotPropsFor } from './slots-tR0wf89f.js';
12
12
  import { ViewModeDefault } from './hooks/use-view-preference.js';
13
13
  import { ResourceUrlStateOptions } from './hooks/use-resource-url-state.js';
14
14
  import { FilterParam, SortParam } from '@marktiderman/genesis-core/provider';
15
- import { a as NavigateFn, S as SearchParamsAdapter } from './navigation-Bha0R3Fu.js';
15
+ import { a as NavigateFn, S as SearchParamsAdapter } from './navigation-By1DrzaM.js';
16
16
 
17
17
  interface DataPageShellProps {
18
18
  /** Display title for the page */
@@ -589,8 +589,14 @@ interface ResourcePageProps<T extends Record<string, unknown> = Record<string, u
589
589
  * columns to match — so the search box is hidden without them. Table
590
590
  * header sorting is withdrawn, as in server-data mode; the sort control
591
591
  * in the filter row drives the query.
592
+ * - `"cursor"`: loads `perPage` rows (`resourceOptions.defaultPerPage`,
593
+ * else the stored page size) and a "Load more" button appends the next
594
+ * page, by cursor where the provider serves it
595
+ * (`capabilities().cursorPagination`) and by offset otherwise. The
596
+ * server orders by `resourceOptions.defaultSort`; search, sort and
597
+ * filters in the toolbar act on the rows loaded so far.
592
598
  */
593
- pagination?: "client" | "server";
599
+ pagination?: "client" | "server" | "cursor";
594
600
  /**
595
601
  * `pagination="client"` only: the most rows fetched. Default 1000. An
596
602
  * explicit `resourceOptions.defaultPerPage` wins. Keep it at or under the
@@ -959,6 +965,12 @@ interface ResourcePageProps<T extends Record<string, unknown> = Record<string, u
959
965
  */
960
966
  onNavigate?: NavigateFn;
961
967
  resourceOptions?: UseResourceOptions<T>;
968
+ /**
969
+ * `resource` mode: refetch the list (and the open record) when the
970
+ * provider reports a change, e.g. Supabase Realtime. Shorthand for
971
+ * `resourceOptions.live`, which wins. See core's `UseResourceOptions.live`.
972
+ */
973
+ live?: UseResourceOptions<T>["live"];
962
974
  /**
963
975
  * Keep the list's state in the URL: the open record (`?id=`), the search
964
976
  * (`q`), the sort (`sort=field:asc`) and, with `pagination="server"`, the
@@ -1018,13 +1030,30 @@ interface ResourceTableState<T extends Record<string, unknown> = Record<string,
1018
1030
  * current page.
1019
1031
  */
1020
1032
  rows: T[];
1021
- /** How many rows match, across all pages. */
1033
+ /**
1034
+ * How many rows match, across all pages. With `pagination="cursor"` it is
1035
+ * the server's count while no search or status filter is active; with one,
1036
+ * only loaded rows are filtered, so it counts the loaded rows that match.
1037
+ */
1022
1038
  total: number;
1023
1039
  loading: boolean;
1024
1040
  /** The read failed. */
1025
1041
  error: boolean;
1026
1042
  /** True when more than `clientRowLimit` rows exist and only that many were loaded. */
1027
1043
  truncated: boolean;
1044
+ /**
1045
+ * `pagination="cursor"`: whether more rows can be loaded, whether a page
1046
+ * is loading, and `load()` to append the next page. Undefined otherwise.
1047
+ */
1048
+ loadMore?: {
1049
+ hasMore: boolean;
1050
+ loading: boolean;
1051
+ load: () => void;
1052
+ /** Rows loaded so far. */
1053
+ loaded: number;
1054
+ /** Rows the latest load added (0 before the first "Load more"). */
1055
+ lastLoaded: number;
1056
+ };
1028
1057
  /** The columns, resolved to DataTable's format. */
1029
1058
  columns: DataTableColumn<T>[];
1030
1059
  /** Write actions for cell renderers (update, remove, …). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marktiderman/genesis-ui",
3
- "version": "2.10.1",
3
+ "version": "2.12.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -378,7 +378,7 @@
378
378
  "vaul": "^1.0.0"
379
379
  },
380
380
  "dependencies": {
381
- "@marktiderman/genesis-core": "^1.5.1",
381
+ "@marktiderman/genesis-core": "^1.6.0",
382
382
  "@tanstack/react-table": "^8.21.3",
383
383
  "@tanstack/react-virtual": "^3.14.0",
384
384
  "class-variance-authority": "^0.7.1",
@@ -459,6 +459,7 @@
459
459
  "build": "tsup && node scripts/stamp-use-client.mjs && cp src/styles.css dist/styles.css && node ../../scripts/check-exports-resolve.mjs",
460
460
  "clean": "rm -rf dist",
461
461
  "check:exports": "node ../../scripts/check-exports-resolve.mjs",
462
- "test": "vitest run"
462
+ "test": "vitest run",
463
+ "typecheck": "tsc -p tsconfig.type-tests.json"
463
464
  }
464
465
  }
@@ -1,174 +0,0 @@
1
- import * as React from 'react';
2
- import { ReactNode } from 'react';
3
- import { LucideIcon } from 'lucide-react';
4
- import { N as NavigationNode, L as LinkComponent } from './navigation-Bha0R3Fu.js';
5
-
6
- interface NavItem {
7
- to: string;
8
- icon: LucideIcon;
9
- label: string;
10
- /** Nested items — rendered as a collapsible group when the rail is expanded */
11
- children?: NavItem[];
12
- badge?: string | number;
13
- disabled?: boolean;
14
- /**
15
- * Exact-match active state (e.g. overview `/`). Exact on the path only, so
16
- * an `activePath` carrying `?search#hash` still matches.
17
- */
18
- end?: boolean;
19
- }
20
- /**
21
- * The "up" link AppShell renders above page content: a real link to the
22
- * logical parent, never `history.back()`.
23
- *
24
- * @stability Beta
25
- */
26
- interface ParentNavigation {
27
- href: string;
28
- label: string;
29
- }
30
- /**
31
- * Declarative chrome for AppShell — developer defaults + optional
32
- * in-sidebar user toggles (Notion/Linear “customize chrome” pattern).
33
- *
34
- * @stability Beta
35
- */
36
- interface AppShellOptions {
37
- showLogo?: boolean;
38
- showAppName?: boolean;
39
- showThemeToggle?: boolean;
40
- /** Desktop rail collapse control */
41
- showCollapse?: boolean;
42
- showUserSlot?: boolean;
43
- showFooter?: boolean;
44
- showSecondaryNav?: boolean;
45
- /** Mobile fixed bottom tab bar */
46
- showMobileBottomNav?: boolean;
47
- defaultCollapsed?: boolean;
48
- /**
49
- * Show the in-sidebar Sidebar options popover so users can customize chrome.
50
- * Default true when collapse / secondary / theme / slots are available.
51
- */
52
- configurable?: boolean;
53
- /**
54
- * Toggle keys the developer has decided on and users may not override —
55
- * e.g. hiding `showThemeToggle` for a brand that manages theme elsewhere.
56
- * Locked keys are dropped from the options popover and any stored user
57
- * override for them is ignored on resolve.
58
- */
59
- lockedOptions?: (keyof AppShellOptions)[];
60
- /** Comfortable (default) vs compact row padding */
61
- density?: "comfortable" | "compact";
62
- /** Expanded rail width in rem-ish tokens: narrow ≈ 13rem, wide ≈ 16rem */
63
- railWidth?: "narrow" | "wide";
64
- /**
65
- * Where page content scrolls.
66
- * - `container` (default): main panel scrolls — classic app-shell chrome.
67
- * - `window`: document/window scrolls with a sticky rail so React Router
68
- * `ScrollRestoration` keeps working (dashboard dogfood).
69
- */
70
- scrollRoot?: "container" | "window";
71
- }
72
- /**
73
- * @stability Beta
74
- */
75
- interface AppShellProps {
76
- /** App name shown in sidebar header */
77
- appName: string;
78
- /** App logo letter or short text (ignored when `logo` is set) */
79
- appLogo?: string;
80
- /** Custom logo node — preferred over `appLogo` letter tile */
81
- logo?: ReactNode;
82
- /**
83
- * Primary navigation items. Optional when `navigation` is set: the tree
84
- * root's `items` are the global nav then.
85
- */
86
- navItems?: NavItem[];
87
- /**
88
- * The app's logical navigation hierarchy. AppShell resolves it against
89
- * `activePath` (see `resolveNavigation`) and derives:
90
- * - the sidebar's global items from the root's `items` (unless `navItems`),
91
- * - a contextual section from the current node's `items`, labelled with
92
- * the node's `label` (`$param` segments in `to` filled from the URL),
93
- * - the mobile tab bar: the contextual items when there are any, else the
94
- * global top-level items (unless `mobileNavItems`),
95
- * - a back link to the current node's logical parent (unless
96
- * `parentNavigation`).
97
- *
98
- * @stability Beta
99
- */
100
- navigation?: NavigationNode<NavItem>;
101
- /**
102
- * Back-to-parent link rendered in the content header, above `children`, on
103
- * mobile and desktop. Derived from `navigation` when omitted; `null` hides
104
- * it. Use this instead of placing a back row inside page content.
105
- *
106
- * @stability Beta
107
- */
108
- parentNavigation?: ParentNavigation | null;
109
- /** Secondary nav (e.g. “More”) — rendered below a divider when shown */
110
- secondaryNavItems?: NavItem[];
111
- /** Label above secondary nav (default “More”) */
112
- secondaryNavLabel?: string;
113
- /**
114
- * Items for the mobile bottom tab bar. Defaults to top-level `navItems`
115
- * (no children). Pass a short list for apps with large sidebars; pass `[]`
116
- * and set `options.showMobileBottomNav: false` to hide.
117
- */
118
- mobileNavItems?: NavItem[];
119
- /** Slot below the logo row (product switcher, workspace picker, …) */
120
- headerSlot?: ReactNode;
121
- /**
122
- * Compact slot shown in the **collapsed** desktop rail, where `headerSlot`
123
- * is hidden for space. Use it to keep a core affordance reachable without
124
- * expanding — e.g. an icon-only product switcher. Omit to hide the header
125
- * region entirely while collapsed.
126
- */
127
- collapsedHeaderSlot?: ReactNode;
128
- /** Footer region above the user slot (version, links) */
129
- footer?: ReactNode;
130
- /**
131
- * User / account block at the bottom of the sidebar. When the rail is
132
- * collapsed, AppShell hides any descendant carrying the
133
- * `data-shell-user-detail` attribute (e.g. name/email text) so only a
134
- * compact element (avatar, initial) remains — tag the detail wrapper you
135
- * want hidden in the collapsed rail with that attribute.
136
- */
137
- userSlot?: ReactNode;
138
- /** Page content */
139
- children: ReactNode;
140
- /**
141
- * @deprecated Prefer `options.showThemeToggle`. Kept for sample-app
142
- * back-compat; merges into resolved options when `options` omits it.
143
- */
144
- showThemeToggle?: boolean;
145
- /** Chrome config (developer defaults + optional in-sidebar menu) */
146
- options?: AppShellOptions;
147
- /** Persist user sidebar-option overrides + collapse state (localStorage) */
148
- optionsStorageKey?: string;
149
- /** Controlled collapse (desktop rail) */
150
- collapsed?: boolean;
151
- onCollapsedChange?: (collapsed: boolean) => void;
152
- /**
153
- * Injectable link component. Defaults to a plain `<a>` (no router). Pass a
154
- * router adapter — e.g. React Router `({ href, ...p }) => <Link to={href} {...p} />`
155
- * or Next.js `next/link` — to get client-side navigation.
156
- */
157
- linkComponent?: LinkComponent;
158
- /**
159
- * Current location used to highlight the active nav item. Pass the full
160
- * location, `pathname + search + hash` (React Router: `useLocation()`), so
161
- * items whose `to` names a query or hash (`/admin?tab=users`) can become
162
- * active. A pathname alone still works for path-only items, `end` included.
163
- * Omit to disable active highlighting.
164
- */
165
- activePath?: string;
166
- /**
167
- * Optional custom active-state matcher. Defaults to a prefix match (with `/`
168
- * treated as exact), mirroring React Router `NavLink`.
169
- */
170
- isActive?: (to: string, activePath?: string) => boolean;
171
- }
172
- declare function AppShell({ appName, appLogo, logo, navItems: navItemsProp, navigation, parentNavigation: parentNavigationProp, secondaryNavItems, secondaryNavLabel, mobileNavItems, headerSlot, collapsedHeaderSlot, footer, userSlot, children, showThemeToggle: showThemeToggleProp, options: optionsProp, optionsStorageKey, collapsed: collapsedProp, onCollapsedChange, linkComponent, activePath, isActive, }: AppShellProps): React.JSX.Element;
173
-
174
- export { AppShell as A, type NavItem as N, type ParentNavigation as P, type AppShellOptions as a, type AppShellProps as b };