@devalok/shilp-sutra 0.56.0 → 0.59.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/MIGRATION.md +198 -0
- package/dist/_chunks/badge-group.js +75 -174
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chat.js +270 -253
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/document-preview.js +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js +1 -1
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/image-preview.js +71 -70
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +2 -2
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/motion-preference.js +15 -0
- package/dist/_chunks/motion-preference.js.map +1 -0
- package/dist/_chunks/motion-provider.js +1 -1
- package/dist/_chunks/motion-provider.js.map +1 -1
- package/dist/_chunks/oauth-button.js +1 -1
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/popover.js +50 -49
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives-internal.js +29 -29
- package/dist/_chunks/primitives-internal.js.map +1 -1
- package/dist/_chunks/shared.js +48 -47
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js +36 -36
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js +4 -4
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/ai/block-renderer.js +8 -8
- package/dist/ai/blocks/text.js +1 -1
- package/dist/ai/blocks/text.js.map +1 -1
- package/dist/ai/command-bar.js +67 -67
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +35 -35
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/index.js +4 -4
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js +109 -108
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.d.ts +7 -2
- package/dist/composed/avatar-group.d.ts.map +1 -1
- package/dist/composed/avatar-group.js +3 -3
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/command-palette.js +137 -137
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +2 -2
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js +9 -9
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/diff.d.ts +23 -2
- package/dist/composed/diff.d.ts.map +1 -1
- package/dist/composed/diff.js +341 -260
- package/dist/composed/diff.js.map +1 -1
- package/dist/composed/emoji-picker.js +3 -3
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js +4 -4
- package/dist/composed/error-boundary.js +2 -2
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/shared.d.ts.map +1 -1
- package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js +152 -151
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.d.ts.map +1 -1
- package/dist/composed/filter-bar.js +53 -52
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.d.ts.map +1 -1
- package/dist/composed/form-section.js +38 -37
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/inline-edit.js +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/loading-skeleton.js +3 -3
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js +1 -1
- package/dist/composed/member-picker.js.map +1 -1
- package/dist/composed/multi-select-popover.d.ts.map +1 -1
- package/dist/composed/multi-select-popover.js +109 -108
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-skeletons.js +4 -4
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/responsive-modal.js +1 -1
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +473 -472
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +6 -6
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +5 -5
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +29 -28
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -3
- package/dist/hooks/use-container-size.d.ts +18 -0
- package/dist/hooks/use-container-size.d.ts.map +1 -0
- package/dist/hooks/use-container-size.js +28 -0
- package/dist/hooks/use-container-size.js.map +1 -0
- package/dist/motion/index.d.ts +1 -0
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/index.js +2 -15
- package/dist/motion/motion-preference.d.ts +36 -0
- package/dist/motion/motion-preference.d.ts.map +1 -0
- package/dist/motion/motion-provider.d.ts +2 -1
- package/dist/motion/motion-provider.d.ts.map +1 -1
- package/dist/motion/primitives-index.js +103 -102
- package/dist/motion/primitives-index.js.map +1 -1
- package/dist/motion/primitives.d.ts.map +1 -1
- package/dist/shell/app-shell.d.ts +101 -0
- package/dist/shell/app-shell.d.ts.map +1 -0
- package/dist/shell/app-shell.js +76 -0
- package/dist/shell/app-shell.js.map +1 -0
- package/dist/shell/bottom-navbar.js +21 -21
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/index.d.ts +2 -1
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +6 -5
- package/dist/shell/notification-center.d.ts +17 -0
- package/dist/shell/notification-center.d.ts.map +1 -1
- package/dist/shell/notification-center.js +110 -105
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +1 -1
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/top-bar.js +7 -7
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/generate-scale.d.ts +49 -0
- package/dist/tokens/generate-scale.d.ts.map +1 -1
- package/dist/tokens/index.css +1 -0
- package/dist/tokens/palettes.css +292 -0
- package/dist/tokens/primitives.css +29 -26
- package/dist/tokens/semantic.css +170 -47
- package/dist/tokens/shilp-sutra.css +1 -0
- package/dist/tokens/utilities.css +10 -7
- package/dist/tokens/variants.css +1 -1
- package/dist/ui/accordion.d.ts.map +1 -1
- package/dist/ui/accordion.js +27 -26
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.d.ts.map +1 -1
- package/dist/ui/alert-dialog.js +60 -59
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +55 -113
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.js +80 -80
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.d.ts.map +1 -1
- package/dist/ui/avatar.js +71 -70
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-indicator.d.ts +4 -8
- package/dist/ui/badge-indicator.d.ts.map +1 -1
- package/dist/ui/badge-indicator.js +3 -8
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/badge.d.ts +55 -34
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +43 -41
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/button-group.d.ts.map +1 -1
- package/dist/ui/button-group.js +3 -23
- package/dist/ui/button-group.js.map +1 -1
- package/dist/ui/button.d.ts +10 -1
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +79 -212
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +78 -75
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/radar-chart.d.ts.map +1 -1
- package/dist/ui/charts/radar-chart.js +1 -1
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/chat/date-separator.d.ts +8 -1
- package/dist/ui/chat/date-separator.d.ts.map +1 -1
- package/dist/ui/chat/message-list.d.ts.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
- package/dist/ui/checkbox.js +1 -1
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/code.js +2 -2
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +151 -150
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.d.ts +14 -0
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +156 -152
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.d.ts.map +1 -1
- package/dist/ui/context-menu.js +70 -69
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.d.ts +3 -1
- package/dist/ui/data-table-body.d.ts.map +1 -1
- package/dist/ui/data-table-body.js +93 -92
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.d.ts +7 -1
- package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +14 -8
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.d.ts.map +1 -1
- package/dist/ui/data-table-card.js +66 -47
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-context.d.ts +4 -0
- package/dist/ui/data-table-context.d.ts.map +1 -1
- package/dist/ui/data-table-context.js +2 -2
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js +50 -46
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +3 -3
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.d.ts +11 -1
- package/dist/ui/data-table-toolbar.d.ts.map +1 -1
- package/dist/ui/data-table-toolbar.js +7 -7
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.d.ts +52 -5
- package/dist/ui/data-table.d.ts.map +1 -1
- package/dist/ui/data-table.js +181 -169
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/dialog.d.ts.map +1 -1
- package/dist/ui/dialog.js +62 -61
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.d.ts.map +1 -1
- package/dist/ui/dot.js +10 -41
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/ui/dropdown-menu.js +79 -78
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.d.ts.map +1 -1
- package/dist/ui/file-upload.js +117 -116
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +27 -26
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/hover-card.d.ts.map +1 -1
- package/dist/ui/hover-card.js +26 -25
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/icon.js +7 -7
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +3 -3
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js +8 -8
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/menubar.d.ts.map +1 -1
- package/dist/ui/menubar.js +73 -72
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.d.ts.map +1 -1
- package/dist/ui/navigation-menu.js +80 -79
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js +3 -3
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/popover.d.ts.map +1 -1
- package/dist/ui/progress-ring.js +2 -2
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.d.ts.map +1 -1
- package/dist/ui/progress.js +82 -74
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.d.ts.map +1 -1
- package/dist/ui/radio.js +32 -31
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/search-input.d.ts.map +1 -1
- package/dist/ui/search-input.js +28 -27
- package/dist/ui/search-input.js.map +1 -1
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +67 -66
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +1 -1
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.d.ts.map +1 -1
- package/dist/ui/sidebar.js +14 -14
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/slider.d.ts +63 -9
- package/dist/ui/slider.d.ts.map +1 -1
- package/dist/ui/slider.js +75 -33
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.d.ts +8 -2
- package/dist/ui/split-button.d.ts.map +1 -1
- package/dist/ui/split-button.js +49 -95
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +89 -88
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.js +16 -16
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +63 -62
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/surface.d.ts.map +1 -1
- package/dist/ui/surface.js +2 -2
- package/dist/ui/surface.js.map +1 -1
- package/dist/ui/switch.js +1 -1
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table.js +3 -3
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +68 -67
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/textarea.js +5 -5
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +196 -195
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.d.ts.map +1 -1
- package/dist/ui/toggle.js +26 -24
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.d.ts.map +1 -1
- package/dist/ui/tooltip.js +37 -36
- package/dist/ui/tooltip.js.map +1 -1
- package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
- package/docs/components/composed/avatar-group.md +4 -4
- package/docs/components/composed/diff.md +10 -2
- package/docs/components/composed/schedule-view.md +1 -1
- package/docs/components/shell/app-shell.md +132 -0
- package/docs/components/ui/avatar.md +1 -1
- package/docs/components/ui/button.md +1 -1
- package/docs/components/ui/chat.md +7 -1
- package/docs/components/ui/color-swatch.md +1 -1
- package/docs/components/ui/data-table-toolbar.md +6 -2
- package/docs/components/ui/data-table.md +41 -7
- package/docs/components/ui/dot.md +1 -1
- package/docs/components/ui/progress.md +1 -0
- package/docs/components/ui/surface.md +3 -3
- package/docs/components/ui/table.md +2 -2
- package/docs/recipes/customize-brand.md +58 -0
- package/docs/recipes/install-astro.md +1 -0
- package/docs/recipes/install-next-app-router.md +1 -0
- package/docs/recipes/install-next-pages.md +22 -1
- package/docs/recipes/install-remix.md +1 -0
- package/docs/recipes/install-tanstack-start.md +1 -0
- package/docs/recipes/install-vite.md +2 -0
- package/docs/recipes/server-components.md +7 -4
- package/docs/recipes/troubleshoot.md +1 -0
- package/llms.txt +2 -1
- package/make-kit/Guidelines.md +2 -2
- package/make-kit/components/button.md +1 -1
- package/make-kit/components/card.md +6 -6
- package/make-kit/components/surface.md +4 -4
- package/make-kit/foundations/color.md +4 -4
- package/make-kit/foundations/dark-mode.md +1 -1
- package/make-kit/foundations/radius.md +1 -1
- package/make-kit/foundations/surfaces.md +9 -9
- package/mcp-manifest.json +358 -35
- package/package.json +8 -4
- package/skill/SKILL.md +12 -6
- package/skill/references/components.md +2 -1
- package/skill/references/customize-brand.md +58 -0
- package/skill/references/server-components.md +7 -4
- package/skill/references/setup-astro.md +1 -0
- package/skill/references/setup-next-app-router.md +1 -0
- package/skill/references/setup-next-pages.md +22 -1
- package/skill/references/setup-remix.md +1 -0
- package/skill/references/setup-tanstack-start.md +1 -0
- package/skill/references/setup-vite.md +2 -0
- package/skill/references/troubleshoot.md +1 -0
- package/dist/motion/check-motion-provider.d.ts +0 -2
- package/dist/motion/check-motion-provider.d.ts.map +0 -1
- package/dist/motion/index.js.map +0 -1
- package/dist/primitives/react-toast.d.ts +0 -120
- package/dist/ui/charts/_internal/scales.d.ts +0 -5
- package/dist/ui/charts/_internal/scales.d.ts.map +0 -1
- package/dist/ui/lib/slot.d.ts +0 -8
- package/dist/ui/lib/slot.d.ts.map +0 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { ComponentProps } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* AppShell — the frame that lets a bar span above BOTH the sidebar and the
|
|
4
|
+
* content.
|
|
5
|
+
*
|
|
6
|
+
* This is the one shape the library could not express. `SidebarProvider`
|
|
7
|
+
* renders a single flex row, so a bar can only live *inside* the content pane —
|
|
8
|
+
* which is why every shadcn example puts its `<header>` inside `SidebarInset`.
|
|
9
|
+
* Carbon can do it because its `Header` is a sibling above `SideNav`; this is
|
|
10
|
+
* that arrangement.
|
|
11
|
+
*
|
|
12
|
+
* Compose it with the components you already have:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <AppShell variant="inset" chrome="dim">
|
|
16
|
+
* <AppShellBar><TopBar … /></AppShellBar>
|
|
17
|
+
* <AppShellBody>
|
|
18
|
+
* <AppShellSidebar><Sidebar … /></AppShellSidebar>
|
|
19
|
+
* <AppShellCanvas>{children}</AppShellCanvas>
|
|
20
|
+
* </AppShellBody>
|
|
21
|
+
* </AppShell>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## The two inset arrangements
|
|
25
|
+
*
|
|
26
|
+
* `chrome` decides which plane the frame takes and which the work takes. It is
|
|
27
|
+
* not a lightness switch — the two planes swap roles, and which one is lighter
|
|
28
|
+
* flips between themes:
|
|
29
|
+
*
|
|
30
|
+
* | | light chrome | light canvas | dark chrome | dark canvas |
|
|
31
|
+
* |---|---|---|---|---|
|
|
32
|
+
* | `dim` | `#eeeeee` | `#ffffff` | `#0a0a0a` | `#171717` |
|
|
33
|
+
* | `bright` | `#ffffff` | `#eeeeee` | `#171717` | `#0a0a0a` |
|
|
34
|
+
*
|
|
35
|
+
* Both come from the same two tokens — `surface-sunken` and `surface-panel` —
|
|
36
|
+
* swapped. No third tier, and no per-theme special case.
|
|
37
|
+
*
|
|
38
|
+
* With `dim` the brand tint lands on the frame and the work area stays neutral.
|
|
39
|
+
* With `bright` it is the reverse. That choice matters more than the lightness:
|
|
40
|
+
* it decides whether your brand colour surrounds the work or sits underneath it.
|
|
41
|
+
*
|
|
42
|
+
* See docs/plans/2026-08-26-surface-model-rebuild.md.
|
|
43
|
+
*/
|
|
44
|
+
type Variant = 'flat' | 'inset';
|
|
45
|
+
type Chrome = 'dim' | 'bright';
|
|
46
|
+
export interface AppShellProps extends ComponentProps<'div'> {
|
|
47
|
+
/**
|
|
48
|
+
* `flat` — chrome and content share one surface; a hairline on the sidebar
|
|
49
|
+
* does the separating. `inset` — the content sits in a rounded panel inside
|
|
50
|
+
* the chrome. @default 'flat'
|
|
51
|
+
*/
|
|
52
|
+
variant?: Variant;
|
|
53
|
+
/**
|
|
54
|
+
* Which plane the chrome takes when `variant="inset"`. Ignored when flat.
|
|
55
|
+
* @default 'dim'
|
|
56
|
+
*/
|
|
57
|
+
chrome?: Chrome;
|
|
58
|
+
}
|
|
59
|
+
declare const AppShell: import('react').ForwardRefExoticComponent<Omit<AppShellProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
60
|
+
export interface AppShellBarProps extends ComponentProps<'header'> {
|
|
61
|
+
/**
|
|
62
|
+
* Draw a hairline under the bar. Defaults to `true` when flat (the bar is its
|
|
63
|
+
* own region and needs the edge) and `false` when inset (the bar is part of a
|
|
64
|
+
* continuous chrome plane, and a border would cut it in half).
|
|
65
|
+
*/
|
|
66
|
+
bordered?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The full-width bar. Sits above the sidebar and the canvas, which is the whole
|
|
70
|
+
* point of this component.
|
|
71
|
+
*
|
|
72
|
+
* Height is a MINIMUM, not a fixed value — `TopBar` sizes to its content, and a
|
|
73
|
+
* two-line workspace switcher legitimately needs more room than a one-line one.
|
|
74
|
+
* Fixing it would clip.
|
|
75
|
+
*/
|
|
76
|
+
declare const AppShellBar: import('react').ForwardRefExoticComponent<Omit<AppShellBarProps, "ref"> & import('react').RefAttributes<HTMLElement>>;
|
|
77
|
+
/** The row beneath the bar: sidebar alongside canvas. */
|
|
78
|
+
declare const AppShellBody: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
79
|
+
export interface AppShellSidebarProps extends ComponentProps<'div'> {
|
|
80
|
+
/** Render at the collapsed icon width instead of the full width. */
|
|
81
|
+
collapsed?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fixed-width slot for the sidebar. Widths come from the same constants
|
|
85
|
+
* `Sidebar` uses (16rem expanded, 3rem collapsed), so the two agree whether or
|
|
86
|
+
* not you compose them together.
|
|
87
|
+
*/
|
|
88
|
+
declare const AppShellSidebar: import('react').ForwardRefExoticComponent<Omit<AppShellSidebarProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
89
|
+
/**
|
|
90
|
+
* The content pane.
|
|
91
|
+
*
|
|
92
|
+
* When inset, the panel is flush to the bar and the sidebar and floats only off
|
|
93
|
+
* the bottom-right. It reads as the frame opening up rather than as a card
|
|
94
|
+
* dropped into the middle — a symmetric gap fights that.
|
|
95
|
+
*
|
|
96
|
+
* No shadow. The inset canvas is a frame, not a floating thing; shadows are
|
|
97
|
+
* reserved for what genuinely floats.
|
|
98
|
+
*/
|
|
99
|
+
declare const AppShellCanvas: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
100
|
+
export { AppShell, AppShellBar, AppShellBody, AppShellCanvas, AppShellSidebar };
|
|
101
|
+
//# sourceMappingURL=app-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/shell/app-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAK3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAA;AAC/B,KAAK,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;AAe9B,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC1D;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,QAAA,MAAM,QAAQ,uHAmBb,CAAA;AAGD,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAChE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,WAAW,uHAiBhB,CAAA;AAGD,yDAAyD;AACzD,QAAA,MAAM,YAAY,2MAKjB,CAAA;AAGD,MAAM,WAAW,oBAAqB,SAAQ,cAAc,CAAC,KAAK,CAAC;IACjE,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED;;;;GAIG;AACH,QAAA,MAAM,eAAe,8HAkBpB,CAAA;AAGD;;;;;;;;;GASG;AACH,QAAA,MAAM,cAAc,qMAgCnB,CAAA;AAGD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../ui/lib/utils.js";
|
|
3
|
+
import { createContext as t, forwardRef as n, useContext as r } from "react";
|
|
4
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
5
|
+
//#region src/shell/app-shell.tsx
|
|
6
|
+
var a = t({
|
|
7
|
+
variant: "flat",
|
|
8
|
+
chrome: "dim"
|
|
9
|
+
});
|
|
10
|
+
function o(e) {
|
|
11
|
+
let t = r(a);
|
|
12
|
+
if (!t) throw Error(`${e} must be rendered inside <AppShell>.`);
|
|
13
|
+
return t;
|
|
14
|
+
}
|
|
15
|
+
var s = n(({ variant: t = "flat", chrome: n = "dim", className: r, children: o, ...s }, c) => /* @__PURE__ */ i(a.Provider, {
|
|
16
|
+
value: {
|
|
17
|
+
variant: t,
|
|
18
|
+
chrome: n
|
|
19
|
+
},
|
|
20
|
+
children: /* @__PURE__ */ i("div", {
|
|
21
|
+
ref: c,
|
|
22
|
+
className: e("flex min-h-svh flex-col", t === "flat" && "bg-surface-base", t === "inset" && n === "dim" && "bg-surface-sunken", t === "inset" && n === "bright" && "bg-surface-panel", r),
|
|
23
|
+
...s,
|
|
24
|
+
children: o
|
|
25
|
+
})
|
|
26
|
+
}));
|
|
27
|
+
s.displayName = "AppShell";
|
|
28
|
+
var c = n(({ bordered: t, className: n, ...r }, a) => {
|
|
29
|
+
let { variant: s } = o("AppShellBar");
|
|
30
|
+
return /* @__PURE__ */ i("header", {
|
|
31
|
+
ref: a,
|
|
32
|
+
className: e("flex w-full shrink-0 items-center", s === "flat" ? "min-h-ds-xl" : "min-h-ds-lg", (t ?? s === "flat") && "border-b border-surface-border", n),
|
|
33
|
+
...r
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
c.displayName = "AppShellBar";
|
|
37
|
+
var l = n(({ className: t, ...n }, r) => /* @__PURE__ */ i("div", {
|
|
38
|
+
ref: r,
|
|
39
|
+
className: e("flex min-h-0 flex-1", t),
|
|
40
|
+
...n
|
|
41
|
+
}));
|
|
42
|
+
l.displayName = "AppShellBody";
|
|
43
|
+
var u = n(({ collapsed: t = !1, className: n, style: r, ...a }, s) => {
|
|
44
|
+
let { variant: c } = o("AppShellSidebar");
|
|
45
|
+
return /* @__PURE__ */ i("div", {
|
|
46
|
+
ref: s,
|
|
47
|
+
"data-collapsed": t || void 0,
|
|
48
|
+
style: {
|
|
49
|
+
width: t ? "3rem" : "16rem",
|
|
50
|
+
...r
|
|
51
|
+
},
|
|
52
|
+
className: e("flex shrink-0 flex-col", c === "flat" && "border-r border-surface-border", n),
|
|
53
|
+
...a
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
u.displayName = "AppShellSidebar";
|
|
57
|
+
var d = n(({ className: t, children: n, ...r }, a) => {
|
|
58
|
+
let { variant: s, chrome: c } = o("AppShellCanvas");
|
|
59
|
+
return s === "flat" ? /* @__PURE__ */ i("main", {
|
|
60
|
+
ref: a,
|
|
61
|
+
className: e("flex min-w-0 flex-1 flex-col bg-surface-base", t),
|
|
62
|
+
...r,
|
|
63
|
+
children: n
|
|
64
|
+
}) : /* @__PURE__ */ i("div", {
|
|
65
|
+
className: "flex min-w-0 flex-1 pb-ds-03 pr-ds-03",
|
|
66
|
+
children: /* @__PURE__ */ i("main", {
|
|
67
|
+
ref: a,
|
|
68
|
+
className: e("flex min-w-0 flex-1 flex-col overflow-hidden rounded-overlay-lg", c === "dim" ? "bg-surface-panel" : "bg-surface-sunken", t),
|
|
69
|
+
...r,
|
|
70
|
+
children: n
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
d.displayName = "AppShellCanvas";
|
|
75
|
+
//#endregion
|
|
76
|
+
export { s as AppShell, c as AppShellBar, l as AppShellBody, d as AppShellCanvas, u as AppShellSidebar };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell.js","names":[],"sources":["../../src/shell/app-shell.tsx"],"sourcesContent":["'use client'\n\nimport type { ComponentProps } from 'react'\nimport { createContext, forwardRef, useContext } from 'react'\n\nimport { cn } from '../ui/lib/utils'\n\n/**\n * AppShell — the frame that lets a bar span above BOTH the sidebar and the\n * content.\n *\n * This is the one shape the library could not express. `SidebarProvider`\n * renders a single flex row, so a bar can only live *inside* the content pane —\n * which is why every shadcn example puts its `<header>` inside `SidebarInset`.\n * Carbon can do it because its `Header` is a sibling above `SideNav`; this is\n * that arrangement.\n *\n * Compose it with the components you already have:\n *\n * ```tsx\n * <AppShell variant=\"inset\" chrome=\"dim\">\n * <AppShellBar><TopBar … /></AppShellBar>\n * <AppShellBody>\n * <AppShellSidebar><Sidebar … /></AppShellSidebar>\n * <AppShellCanvas>{children}</AppShellCanvas>\n * </AppShellBody>\n * </AppShell>\n * ```\n *\n * ## The two inset arrangements\n *\n * `chrome` decides which plane the frame takes and which the work takes. It is\n * not a lightness switch — the two planes swap roles, and which one is lighter\n * flips between themes:\n *\n * | | light chrome | light canvas | dark chrome | dark canvas |\n * |---|---|---|---|---|\n * | `dim` | `#eeeeee` | `#ffffff` | `#0a0a0a` | `#171717` |\n * | `bright` | `#ffffff` | `#eeeeee` | `#171717` | `#0a0a0a` |\n *\n * Both come from the same two tokens — `surface-sunken` and `surface-panel` —\n * swapped. No third tier, and no per-theme special case.\n *\n * With `dim` the brand tint lands on the frame and the work area stays neutral.\n * With `bright` it is the reverse. That choice matters more than the lightness:\n * it decides whether your brand colour surrounds the work or sits underneath it.\n *\n * See docs/plans/2026-08-26-surface-model-rebuild.md.\n */\n\ntype Variant = 'flat' | 'inset'\ntype Chrome = 'dim' | 'bright'\n\ninterface ShellContext {\n variant: Variant\n chrome: Chrome\n}\n\nconst AppShellContext = createContext<ShellContext>({ variant: 'flat', chrome: 'dim' })\n\nfunction useAppShell(part: string): ShellContext {\n const ctx = useContext(AppShellContext)\n if (!ctx) throw new Error(`${part} must be rendered inside <AppShell>.`)\n return ctx\n}\n\nexport interface AppShellProps extends ComponentProps<'div'> {\n /**\n * `flat` — chrome and content share one surface; a hairline on the sidebar\n * does the separating. `inset` — the content sits in a rounded panel inside\n * the chrome. @default 'flat'\n */\n variant?: Variant\n /**\n * Which plane the chrome takes when `variant=\"inset\"`. Ignored when flat.\n * @default 'dim'\n */\n chrome?: Chrome\n}\n\nconst AppShell = forwardRef<HTMLDivElement, AppShellProps>(\n ({ variant = 'flat', chrome = 'dim', className, children, ...props }, ref) => (\n <AppShellContext.Provider value={{ variant, chrome }}>\n <div\n ref={ref}\n className={cn(\n 'flex min-h-svh flex-col',\n variant === 'flat' && 'bg-surface-base',\n // the two inset arrangements are the same pair of tokens, swapped\n variant === 'inset' && chrome === 'dim' && 'bg-surface-sunken',\n variant === 'inset' && chrome === 'bright' && 'bg-surface-panel',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </AppShellContext.Provider>\n ),\n)\nAppShell.displayName = 'AppShell'\n\nexport interface AppShellBarProps extends ComponentProps<'header'> {\n /**\n * Draw a hairline under the bar. Defaults to `true` when flat (the bar is its\n * own region and needs the edge) and `false` when inset (the bar is part of a\n * continuous chrome plane, and a border would cut it in half).\n */\n bordered?: boolean\n}\n\n/**\n * The full-width bar. Sits above the sidebar and the canvas, which is the whole\n * point of this component.\n *\n * Height is a MINIMUM, not a fixed value — `TopBar` sizes to its content, and a\n * two-line workspace switcher legitimately needs more room than a one-line one.\n * Fixing it would clip.\n */\nconst AppShellBar = forwardRef<HTMLElement, AppShellBarProps>(\n ({ bordered, className, ...props }, ref) => {\n const { variant } = useAppShell('AppShellBar')\n const showBorder = bordered ?? variant === 'flat'\n return (\n <header\n ref={ref}\n className={cn(\n 'flex w-full shrink-0 items-center',\n variant === 'flat' ? 'min-h-ds-xl' : 'min-h-ds-lg',\n showBorder && 'border-b border-surface-border',\n className,\n )}\n {...props}\n />\n )\n },\n)\nAppShellBar.displayName = 'AppShellBar'\n\n/** The row beneath the bar: sidebar alongside canvas. */\nconst AppShellBody = forwardRef<HTMLDivElement, ComponentProps<'div'>>(\n ({ className, ...props }, ref) => (\n // min-h-0 so a scrolling canvas does not stretch the row past the viewport\n <div ref={ref} className={cn('flex min-h-0 flex-1', className)} {...props} />\n ),\n)\nAppShellBody.displayName = 'AppShellBody'\n\nexport interface AppShellSidebarProps extends ComponentProps<'div'> {\n /** Render at the collapsed icon width instead of the full width. */\n collapsed?: boolean\n}\n\n/**\n * Fixed-width slot for the sidebar. Widths come from the same constants\n * `Sidebar` uses (16rem expanded, 3rem collapsed), so the two agree whether or\n * not you compose them together.\n */\nconst AppShellSidebar = forwardRef<HTMLDivElement, AppShellSidebarProps>(\n ({ collapsed = false, className, style, ...props }, ref) => {\n const { variant } = useAppShell('AppShellSidebar')\n return (\n <div\n ref={ref}\n data-collapsed={collapsed || undefined}\n style={{ width: collapsed ? '3rem' : '16rem', ...style }}\n className={cn(\n 'flex shrink-0 flex-col',\n // flat has no chrome plane of its own, so the edge does the work\n variant === 'flat' && 'border-r border-surface-border',\n className,\n )}\n {...props}\n />\n )\n },\n)\nAppShellSidebar.displayName = 'AppShellSidebar'\n\n/**\n * The content pane.\n *\n * When inset, the panel is flush to the bar and the sidebar and floats only off\n * the bottom-right. It reads as the frame opening up rather than as a card\n * dropped into the middle — a symmetric gap fights that.\n *\n * No shadow. The inset canvas is a frame, not a floating thing; shadows are\n * reserved for what genuinely floats.\n */\nconst AppShellCanvas = forwardRef<HTMLDivElement, ComponentProps<'main'>>(\n ({ className, children, ...props }, ref) => {\n const { variant, chrome } = useAppShell('AppShellCanvas')\n\n if (variant === 'flat') {\n return (\n <main\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col bg-surface-base', className)}\n {...props}\n >\n {children}\n </main>\n )\n }\n\n return (\n <div className=\"flex min-w-0 flex-1 pb-ds-03 pr-ds-03\">\n <main\n ref={ref}\n className={cn(\n 'flex min-w-0 flex-1 flex-col overflow-hidden rounded-overlay-lg',\n chrome === 'dim' ? 'bg-surface-panel' : 'bg-surface-sunken',\n className,\n )}\n {...props}\n >\n {children}\n </main>\n </div>\n )\n },\n)\nAppShellCanvas.displayName = 'AppShellCanvas'\n\nexport { AppShell, AppShellBar, AppShellBody, AppShellCanvas, AppShellSidebar }\n"],"mappings":";;;;;AA0DA,IAAM,IAAkB,EAA4B;CAAE,SAAS;CAAQ,QAAQ;AAAM,CAAC;AAEtF,SAAS,EAAY,GAA4B;CAC/C,IAAM,IAAM,EAAW,CAAe;CACtC,IAAI,CAAC,GAAK,MAAU,MAAM,GAAG,EAAK,qCAAqC;CACvE,OAAO;AACT;AAgBA,IAAM,IAAW,GACd,EAAE,aAAU,QAAQ,YAAS,OAAO,cAAW,aAAU,GAAG,KAAS,MACpE,kBAAC,EAAgB,UAAjB;CAA0B,OAAO;EAAE;EAAS;CAAO;WACjD,kBAAC,OAAD;EACO;EACL,WAAW,EACT,2BACA,MAAY,UAAU,mBAEtB,MAAY,WAAW,MAAW,SAAS,qBAC3C,MAAY,WAAW,MAAW,YAAY,oBAC9C,CACF;EACA,GAAI;EAEH;CACE,CAAA;AACmB,CAAA,CAE9B;AACA,EAAS,cAAc;AAmBvB,IAAM,IAAc,GACjB,EAAE,aAAU,cAAW,GAAG,KAAS,MAAQ;CAC1C,IAAM,EAAE,eAAY,EAAY,aAAa;CAE7C,OACE,kBAAC,UAAD;EACO;EACL,WAAW,EACT,qCACA,MAAY,SAAS,gBAAgB,gBANxB,KAAY,MAAY,WAOvB,kCACd,CACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AACA,EAAY,cAAc;AAG1B,IAAM,IAAe,GAClB,EAAE,cAAW,GAAG,KAAS,MAExB,kBAAC,OAAD;CAAU;CAAK,WAAW,EAAG,uBAAuB,CAAS;CAAG,GAAI;AAAQ,CAAA,CAEhF;AACA,EAAa,cAAc;AAY3B,IAAM,IAAkB,GACrB,EAAE,eAAY,IAAO,cAAW,UAAO,GAAG,KAAS,MAAQ;CAC1D,IAAM,EAAE,eAAY,EAAY,iBAAiB;CACjD,OACE,kBAAC,OAAD;EACO;EACL,kBAAgB,KAAa,KAAA;EAC7B,OAAO;GAAE,OAAO,IAAY,SAAS;GAAS,GAAG;EAAM;EACvD,WAAW,EACT,0BAEA,MAAY,UAAU,kCACtB,CACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AACA,EAAgB,cAAc;AAY9B,IAAM,IAAiB,GACpB,EAAE,cAAW,aAAU,GAAG,KAAS,MAAQ;CAC1C,IAAM,EAAE,YAAS,cAAW,EAAY,gBAAgB;CAcxD,OAZI,MAAY,SAEZ,kBAAC,QAAD;EACO;EACL,WAAW,EAAG,gDAAgD,CAAS;EACvE,GAAI;EAEH;CACG,CAAA,IAKR,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,QAAD;GACO;GACL,WAAW,EACT,mEACA,MAAW,QAAQ,qBAAqB,qBACxC,CACF;GACA,GAAI;GAEH;EACG,CAAA;CACH,CAAA;AAET,CACF;AACA,EAAe,cAAc"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { springs as e } from "../ui/lib/motion.js";
|
|
3
|
+
import { IconProvider as t } from "../ui/icon-context.js";
|
|
4
4
|
import { cn as n } from "../ui/lib/utils.js";
|
|
5
5
|
import { Icon as r } from "../ui/icon.js";
|
|
6
6
|
import { normalizeIcon as i } from "../_chunks/normalize-icon.js";
|
|
@@ -29,24 +29,24 @@ function b({ count: e }) {
|
|
|
29
29
|
children: t
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
function x({ indicator:
|
|
33
|
-
if (
|
|
32
|
+
function x({ indicator: t, layoutId: n, reduced: r }) {
|
|
33
|
+
if (t === "none") return null;
|
|
34
34
|
let i = {
|
|
35
35
|
layoutId: n,
|
|
36
36
|
"aria-hidden": !0,
|
|
37
|
-
transition: r ? { duration: 0 } :
|
|
37
|
+
transition: r ? { duration: 0 } : e.snappy,
|
|
38
38
|
initial: !r && { opacity: 0 },
|
|
39
39
|
animate: { opacity: 1 }
|
|
40
40
|
};
|
|
41
|
-
return
|
|
41
|
+
return t === "underline" ? /* @__PURE__ */ m(_.span, {
|
|
42
42
|
...i,
|
|
43
43
|
className: "absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9"
|
|
44
|
-
}) :
|
|
44
|
+
}) : t === "tint" ? /* @__PURE__ */ m(_.span, {
|
|
45
45
|
...i,
|
|
46
|
-
className: "absolute inset-0 rounded-control bg-accent-
|
|
46
|
+
className: "absolute inset-0 rounded-control bg-accent-4"
|
|
47
47
|
}) : /* @__PURE__ */ m(_.span, {
|
|
48
48
|
...i,
|
|
49
|
-
className: "absolute inset-0 rounded-pill bg-accent-
|
|
49
|
+
className: "absolute inset-0 rounded-pill bg-accent-4"
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
var S = "relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard";
|
|
@@ -54,7 +54,7 @@ function C({ item: r, isActive: a, indicator: o, indicatorId: s, showLabel: c, r
|
|
|
54
54
|
let u = d();
|
|
55
55
|
return /* @__PURE__ */ m(_.div, {
|
|
56
56
|
whileTap: l ? void 0 : { scale: .96 },
|
|
57
|
-
transition: l ? { duration: 0 } :
|
|
57
|
+
transition: l ? { duration: 0 } : e.snappy,
|
|
58
58
|
className: "flex min-w-0 flex-1 basis-0",
|
|
59
59
|
children: /* @__PURE__ */ h(u, {
|
|
60
60
|
href: r.href,
|
|
@@ -84,7 +84,7 @@ function C({ item: r, isActive: a, indicator: o, indicatorId: s, showLabel: c, r
|
|
|
84
84
|
/* @__PURE__ */ m("span", {
|
|
85
85
|
className: "relative [&>svg]:h-ico-md [&>svg]:w-ico-md",
|
|
86
86
|
"aria-hidden": "true",
|
|
87
|
-
children: /* @__PURE__ */ m(
|
|
87
|
+
children: /* @__PURE__ */ m(t, {
|
|
88
88
|
size: "md",
|
|
89
89
|
children: i(a && r.activeIcon ? r.activeIcon : r.icon)
|
|
90
90
|
})
|
|
@@ -107,7 +107,7 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
|
|
|
107
107
|
...k,
|
|
108
108
|
ref: A,
|
|
109
109
|
"aria-label": "Mobile navigation",
|
|
110
|
-
className: n("fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-
|
|
110
|
+
className: n("fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-base px-ds-05 pb-safe pt-0 md:hidden", O),
|
|
111
111
|
children: [L.map((e) => /* @__PURE__ */ m(C, {
|
|
112
112
|
item: e,
|
|
113
113
|
isActive: I(e.href, e.exact),
|
|
@@ -124,7 +124,7 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
|
|
|
124
124
|
type: "button",
|
|
125
125
|
"aria-label": "More navigation options",
|
|
126
126
|
whileTap: M ? void 0 : { scale: .96 },
|
|
127
|
-
transition: M ? { duration: 0 } :
|
|
127
|
+
transition: M ? { duration: 0 } : e.snappy,
|
|
128
128
|
className: n(S, "min-w-0 flex-1 basis-0", B ? "font-semibold text-accent-11" : "text-surface-fg-subtle"),
|
|
129
129
|
children: [B && E === "tint" && /* @__PURE__ */ m(x, {
|
|
130
130
|
indicator: "tint",
|
|
@@ -158,25 +158,25 @@ var w = f.forwardRef(({ currentPath: a = "/", user: b = null, primaryItems: w =
|
|
|
158
158
|
className: "rounded-t-bubble",
|
|
159
159
|
children: [/* @__PURE__ */ m(c, { children: /* @__PURE__ */ m(l, { children: "More" }) }), /* @__PURE__ */ m("div", {
|
|
160
160
|
className: "grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04",
|
|
161
|
-
children: R.map((
|
|
162
|
-
let r = I(
|
|
161
|
+
children: R.map((e) => {
|
|
162
|
+
let r = I(e.href, e.exact);
|
|
163
163
|
return /* @__PURE__ */ h(j, {
|
|
164
|
-
href:
|
|
164
|
+
href: e.href,
|
|
165
165
|
onClick: () => P(!1),
|
|
166
166
|
"aria-current": r ? "page" : void 0,
|
|
167
|
-
className: n("flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard", r ? "bg-surface-
|
|
167
|
+
className: n("flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard", r ? "bg-surface-panel-hover text-accent-11" : "text-surface-fg-subtle hover:bg-surface-panel-hover"),
|
|
168
168
|
children: [/* @__PURE__ */ m("span", {
|
|
169
169
|
className: "[&>svg]:h-ico-md [&>svg]:w-ico-md",
|
|
170
170
|
"aria-hidden": "true",
|
|
171
|
-
children: /* @__PURE__ */ m(
|
|
171
|
+
children: /* @__PURE__ */ m(t, {
|
|
172
172
|
size: "md",
|
|
173
|
-
children: i(
|
|
173
|
+
children: i(e.icon)
|
|
174
174
|
})
|
|
175
175
|
}), /* @__PURE__ */ m("span", {
|
|
176
176
|
className: "max-w-full truncate text-center",
|
|
177
|
-
children:
|
|
177
|
+
children: e.title
|
|
178
178
|
})]
|
|
179
|
-
},
|
|
179
|
+
}, e.href);
|
|
180
180
|
})
|
|
181
181
|
})]
|
|
182
182
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven (currentPath / user / items) and router-agnostic via `useLink`.\n * The \"More\" overflow uses the DS `Sheet` primitive, so it inherits focus trap,\n * scroll lock, return-focus, `aria-modal`, and trigger↔panel ARIA wiring.\n */\nimport { IconDots } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useState } from 'react'\n\nimport { Badge } from '../ui/badge'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** Icon shown when the item is active — e.g. a filled variant. Falls back to `icon`. */\n activeIcon?: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n /**\n * Roles allowed to see this item, matched against `user.role`. Omit to show\n * it to everyone. For arbitrary logic, use `canView` instead.\n */\n roles?: string[]\n /**\n * Visibility predicate — full control over whether this item renders.\n * Receives the current `user` (or `null`). Takes precedence over `roles`.\n */\n canView?: (user: BottomNavbarUser | null) => boolean\n}\n\n/**\n * Active-item indicator, animated between items on selection:\n * - `pill` (default) — Material-3 tonal pill behind the icon\n * - `underline` — top accent bar (Material-2 tab style)\n * - `tint` — subtle background tint on the whole active cell\n * - `none` — no shape; rely on the filled `activeIcon` + accent color (iOS)\n */\nexport type BottomNavIndicator = 'pill' | 'underline' | 'tint' | 'none'\n/** Show labels always (default) or only for the selected item (narrow viewports). */\nexport type BottomNavLabelVisibility = 'always' | 'selected'\n\nexport interface BottomNavbarProps extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** Current user. Drives per-item role gating via `item.roles` / `item.canView`. */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow sheet */\n moreItems?: BottomNavItem[]\n /** Active-indicator style. @default 'pill' */\n indicator?: BottomNavIndicator\n /** Label visibility. @default 'always' */\n labelVisibility?: BottomNavLabelVisibility\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n/** Per-item role/visibility gate. `canView` wins; else `roles` matched against user.role; else visible. */\nfunction itemVisible(item: BottomNavItem, user: BottomNavbarUser | null): boolean {\n if (item.canView) return item.canView(user)\n if (item.roles && item.roles.length > 0) {\n return !!user?.role && item.roles.includes(user.role)\n }\n return true\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (composes Badge)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n return (\n <Badge\n color=\"error\"\n variant=\"solid\"\n size=\"xs\"\n aria-label={`${count} notifications`}\n className=\"pointer-events-none absolute -end-1 -top-1 justify-center px-ds-01 tabular-nums motion-safe:animate-in motion-safe:zoom-in-75\"\n >\n {display}\n </Badge>\n )\n}\n\n// -----------------------------------------------------------------------\n// Active indicator (shared-element)\n// -----------------------------------------------------------------------\n\n/**\n * The active-item indicator. A single shared-element (`layoutId`) that SLIDES\n * to the selected item and fades in on first appearance. `none` renders\n * nothing (the filled `activeIcon` + accent color carry the state).\n */\nfunction ActiveIndicator({\n indicator,\n layoutId,\n reduced,\n}: {\n indicator: BottomNavIndicator\n layoutId: string\n reduced: boolean\n}) {\n if (indicator === 'none') return null\n const common = {\n layoutId,\n 'aria-hidden': true as const,\n transition: reduced ? { duration: 0 } : springs.snappy,\n initial: reduced ? false : { opacity: 0 },\n animate: { opacity: 1 },\n }\n if (indicator === 'underline') {\n return <motion.span {...common} className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9\" />\n }\n if (indicator === 'tint') {\n return <motion.span {...common} className=\"absolute inset-0 rounded-control bg-accent-3\" />\n }\n // pill (default) — Material-3 tonal pill behind the icon\n return <motion.span {...common} className=\"absolute inset-0 rounded-pill bg-accent-3\" />\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nconst itemClass =\n 'relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard'\n\nfunction BottomNavLink({\n item,\n isActive,\n indicator,\n indicatorId,\n showLabel,\n reduced,\n}: {\n item: BottomNavItem\n isActive: boolean\n indicator: BottomNavIndicator\n indicatorId: string\n showLabel: boolean\n reduced: boolean\n}) {\n const Link = useLink()\n return (\n <motion.div\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className=\"flex min-w-0 flex-1 basis-0\"\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(itemClass, isActive ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle')}\n >\n {/* tint covers the whole cell — sits behind the content */}\n {isActive && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {isActive && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {isActive && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <span className=\"relative [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">\n {normalizeIcon(isActive && item.activeIcon ? item.activeIcon : item.icon)}\n </IconProvider>\n </span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n {showLabel && <span className=\"max-w-full truncate text-center\">{item.title}</span>}\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user = null,\n primaryItems = [],\n moreItems = [],\n indicator = 'pill',\n labelVisibility = 'always',\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const reduced = useReducedMotion() ?? false\n const [showMore, setShowMore] = useState(false)\n // Scope the shared-element layoutId per instance so two navbars don't animate into each other.\n const instanceId = React.useId()\n const indicatorId = `${instanceId}-nav-indicator`\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') return currentPath === path\n return currentPath.startsWith(path)\n }\n\n // Role/visibility gating\n const visiblePrimary = primaryItems.filter((item) => itemVisible(item, user))\n const visibleMore = moreItems.filter((item) => itemVisible(item, user))\n\n const isMoreActive = visibleMore.some((item) => isActive(item.href, item.exact))\n const moreSelected = showMore || isMoreActive\n const showMoreLabel = labelVisibility === 'always' || moreSelected\n\n return (\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-chrome px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {visiblePrimary.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n indicator={indicator}\n indicatorId={indicatorId}\n showLabel={labelVisibility === 'always' || isActive(item.href, item.exact)}\n reduced={reduced}\n />\n ))}\n\n {visibleMore.length > 0 && (\n <Sheet open={showMore} onOpenChange={setShowMore}>\n <SheetTrigger asChild>\n <motion.button\n type=\"button\"\n aria-label=\"More navigation options\"\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className={cn(\n itemClass,\n 'min-w-0 flex-1 basis-0',\n moreSelected ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {moreSelected && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {moreSelected && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {moreSelected && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <Icon icon={IconDots} />\n </div>\n {showMoreLabel && <span className=\"max-w-full truncate text-center\">More</span>}\n </div>\n </motion.button>\n </SheetTrigger>\n\n <SheetContent side=\"bottom\" className=\"rounded-t-bubble\">\n <SheetHeader>\n <SheetTitle>More</SheetTitle>\n </SheetHeader>\n <div className=\"grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04\">\n {visibleMore.map((item) => {\n const active = isActive(item.href, item.exact)\n return (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard',\n active\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-raised-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"max-w-full truncate text-center\">{item.title}</span>\n </Link>\n )\n })}\n </div>\n </SheetContent>\n </Sheet>\n )}\n </nav>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bottom-navbar.js","names":[],"sources":["../../src/shell/bottom-navbar.tsx"],"sourcesContent":["'use client'\n\n/**\n * BottomNavbar -- Mobile bottom navigation bar.\n *\n * Props-driven (currentPath / user / items) and router-agnostic via `useLink`.\n * The \"More\" overflow uses the DS `Sheet` primitive, so it inherits focus trap,\n * scroll lock, return-focus, `aria-modal`, and trigger↔panel ARIA wiring.\n */\nimport { IconDots } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useState } from 'react'\n\nimport { Badge } from '../ui/badge'\nimport { Icon } from '../ui/icon'\nimport { IconProvider } from '../ui/icon-context'\nimport type { IconInput } from '../ui/lib/icon-input'\nimport { springs } from '../ui/lib/motion'\nimport { normalizeIcon } from '../ui/lib/normalize-icon'\nimport { cn } from '../ui/lib/utils'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface BottomNavbarUser {\n name: string\n role?: string\n}\n\nexport interface BottomNavItem {\n title: string\n href: string\n /** Icon for this nav item. Accepts any `IconInput`. */\n icon: IconInput\n /** Icon shown when the item is active — e.g. a filled variant. Falls back to `icon`. */\n activeIcon?: IconInput\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Notification badge count. 0 or undefined = hidden, 1–99 = shown, >99 = \"99+\" */\n badge?: number\n /**\n * Roles allowed to see this item, matched against `user.role`. Omit to show\n * it to everyone. For arbitrary logic, use `canView` instead.\n */\n roles?: string[]\n /**\n * Visibility predicate — full control over whether this item renders.\n * Receives the current `user` (or `null`). Takes precedence over `roles`.\n */\n canView?: (user: BottomNavbarUser | null) => boolean\n}\n\n/**\n * Active-item indicator, animated between items on selection:\n * - `pill` (default) — Material-3 tonal pill behind the icon\n * - `underline` — top accent bar (Material-2 tab style)\n * - `tint` — subtle background tint on the whole active cell\n * - `none` — no shape; rely on the filled `activeIcon` + accent color (iOS)\n */\nexport type BottomNavIndicator = 'pill' | 'underline' | 'tint' | 'none'\n/** Show labels always (default) or only for the selected item (narrow viewports). */\nexport type BottomNavLabelVisibility = 'always' | 'selected'\n\nexport interface BottomNavbarProps extends React.HTMLAttributes<HTMLElement> {\n /** Currently active pathname */\n currentPath?: string\n /** Current user. Drives per-item role gating via `item.roles` / `item.canView`. */\n user?: BottomNavbarUser | null\n /** Primary nav items shown directly in the bottom bar (max 4 recommended) */\n primaryItems?: BottomNavItem[]\n /** Additional items shown in the \"More\" overflow sheet */\n moreItems?: BottomNavItem[]\n /** Active-indicator style. @default 'pill' */\n indicator?: BottomNavIndicator\n /** Label visibility. @default 'always' */\n labelVisibility?: BottomNavLabelVisibility\n /** Additional className for the nav element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n/** Per-item role/visibility gate. `canView` wins; else `roles` matched against user.role; else visible. */\nfunction itemVisible(item: BottomNavItem, user: BottomNavbarUser | null): boolean {\n if (item.canView) return item.canView(user)\n if (item.roles && item.roles.length > 0) {\n return !!user?.role && item.roles.includes(user.role)\n }\n return true\n}\n\n// -----------------------------------------------------------------------\n// NavBadge (composes Badge)\n// -----------------------------------------------------------------------\n\nfunction NavBadge({ count }: { count: number }) {\n if (!count || count <= 0) return null\n const display = count > 99 ? '99+' : String(count)\n return (\n <Badge\n color=\"error\"\n variant=\"solid\"\n size=\"xs\"\n aria-label={`${count} notifications`}\n className=\"pointer-events-none absolute -end-1 -top-1 justify-center px-ds-01 tabular-nums motion-safe:animate-in motion-safe:zoom-in-75\"\n >\n {display}\n </Badge>\n )\n}\n\n// -----------------------------------------------------------------------\n// Active indicator (shared-element)\n// -----------------------------------------------------------------------\n\n/**\n * The active-item indicator. A single shared-element (`layoutId`) that SLIDES\n * to the selected item and fades in on first appearance. `none` renders\n * nothing (the filled `activeIcon` + accent color carry the state).\n */\nfunction ActiveIndicator({\n indicator,\n layoutId,\n reduced,\n}: {\n indicator: BottomNavIndicator\n layoutId: string\n reduced: boolean\n}) {\n if (indicator === 'none') return null\n const common = {\n layoutId,\n 'aria-hidden': true as const,\n transition: reduced ? { duration: 0 } : springs.snappy,\n initial: reduced ? false : { opacity: 0 },\n animate: { opacity: 1 },\n }\n if (indicator === 'underline') {\n return <motion.span {...common} className=\"absolute top-0 h-[3px] w-full rounded-b-control-inner bg-accent-9\" />\n }\n if (indicator === 'tint') {\n return <motion.span {...common} className=\"absolute inset-0 rounded-control bg-accent-4\" />\n }\n // pill (default) — Material-3 tonal pill behind the icon\n return <motion.span {...common} className=\"absolute inset-0 rounded-pill bg-accent-4\" />\n}\n\n// -----------------------------------------------------------------------\n// BottomNavLink (internal)\n// -----------------------------------------------------------------------\n\nconst itemClass =\n 'relative flex h-16 w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-ds-02 px-ds-01 pt-0 text-body-sm transition-colors duration-fast-02 ease-productive-standard'\n\nfunction BottomNavLink({\n item,\n isActive,\n indicator,\n indicatorId,\n showLabel,\n reduced,\n}: {\n item: BottomNavItem\n isActive: boolean\n indicator: BottomNavIndicator\n indicatorId: string\n showLabel: boolean\n reduced: boolean\n}) {\n const Link = useLink()\n return (\n <motion.div\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className=\"flex min-w-0 flex-1 basis-0\"\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n className={cn(itemClass, isActive ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle')}\n >\n {/* tint covers the whole cell — sits behind the content */}\n {isActive && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {isActive && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {isActive && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <span className=\"relative [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">\n {normalizeIcon(isActive && item.activeIcon ? item.activeIcon : item.icon)}\n </IconProvider>\n </span>\n {item.badge != null && <NavBadge count={item.badge} />}\n </div>\n {showLabel && <span className=\"max-w-full truncate text-center\">{item.title}</span>}\n </div>\n </Link>\n </motion.div>\n )\n}\n\n// -----------------------------------------------------------------------\n// BottomNavbar\n// -----------------------------------------------------------------------\n\nconst BottomNavbar = React.forwardRef<HTMLElement, BottomNavbarProps>(\n (\n {\n currentPath = '/',\n user = null,\n primaryItems = [],\n moreItems = [],\n indicator = 'pill',\n labelVisibility = 'always',\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const reduced = useReducedMotion() ?? false\n const [showMore, setShowMore] = useState(false)\n // Scope the shared-element layoutId per instance so two navbars don't animate into each other.\n const instanceId = React.useId()\n const indicatorId = `${instanceId}-nav-indicator`\n\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') return currentPath === path\n return currentPath.startsWith(path)\n }\n\n // Role/visibility gating\n const visiblePrimary = primaryItems.filter((item) => itemVisible(item, user))\n const visibleMore = moreItems.filter((item) => itemVisible(item, user))\n\n const isMoreActive = visibleMore.some((item) => isActive(item.href, item.exact))\n const moreSelected = showMore || isMoreActive\n const showMoreLabel = labelVisibility === 'always' || moreSelected\n\n return (\n <nav\n {...props}\n ref={ref}\n aria-label=\"Mobile navigation\"\n className={cn(\n 'fixed bottom-0 start-0 end-0 z-sticky flex w-full flex-row items-stretch justify-between border-t border-surface-border-strong bg-surface-base px-ds-05 pb-safe pt-0 md:hidden',\n className,\n )}\n >\n {visiblePrimary.map((item) => (\n <BottomNavLink\n key={item.href}\n item={item}\n isActive={isActive(item.href, item.exact)}\n indicator={indicator}\n indicatorId={indicatorId}\n showLabel={labelVisibility === 'always' || isActive(item.href, item.exact)}\n reduced={reduced}\n />\n ))}\n\n {visibleMore.length > 0 && (\n <Sheet open={showMore} onOpenChange={setShowMore}>\n <SheetTrigger asChild>\n <motion.button\n type=\"button\"\n aria-label=\"More navigation options\"\n whileTap={reduced ? undefined : { scale: 0.96 }}\n transition={reduced ? { duration: 0 } : springs.snappy}\n className={cn(\n itemClass,\n 'min-w-0 flex-1 basis-0',\n moreSelected ? 'font-semibold text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {moreSelected && indicator === 'tint' && (\n <ActiveIndicator indicator=\"tint\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative flex w-full min-w-0 flex-col items-center gap-ds-02\">\n {moreSelected && indicator === 'underline' && (\n <ActiveIndicator indicator=\"underline\" layoutId={indicatorId} reduced={reduced} />\n )}\n <div className=\"relative px-ds-04 py-ds-01\">\n {moreSelected && indicator === 'pill' && (\n <ActiveIndicator indicator=\"pill\" layoutId={indicatorId} reduced={reduced} />\n )}\n <Icon icon={IconDots} />\n </div>\n {showMoreLabel && <span className=\"max-w-full truncate text-center\">More</span>}\n </div>\n </motion.button>\n </SheetTrigger>\n\n <SheetContent side=\"bottom\" className=\"rounded-t-bubble\">\n <SheetHeader>\n <SheetTitle>More</SheetTitle>\n </SheetHeader>\n <div className=\"grid grid-cols-[repeat(auto-fit,minmax(72px,1fr))] gap-ds-03 pt-ds-04\">\n {visibleMore.map((item) => {\n const active = isActive(item.href, item.exact)\n return (\n <Link\n key={item.href}\n href={item.href}\n onClick={() => setShowMore(false)}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex min-w-0 flex-col items-center gap-ds-02b rounded-overlay-lg p-ds-04 text-body-sm transition-colors ease-productive-standard',\n active\n ? 'bg-surface-panel-hover text-accent-11'\n : 'text-surface-fg-subtle hover:bg-surface-panel-hover',\n )}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n <IconProvider size=\"md\">{normalizeIcon(item.icon)}</IconProvider>\n </span>\n <span className=\"max-w-full truncate text-center\">{item.title}</span>\n </Link>\n )\n })}\n </div>\n </SheetContent>\n </Sheet>\n )}\n </nav>\n )\n },\n)\nBottomNavbar.displayName = 'BottomNavbar'\n\nexport { BottomNavbar }\n"],"mappings":"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"}
|
package/dist/shell/index.d.ts
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
export { AppCommandPalette, type AppCommandPaletteProps, type AppCommandPaletteUser, type SearchResult, type SearchResultGroup, } from './app-command-palette.js';
|
|
15
15
|
export { BottomNavbar, type BottomNavbarProps, type BottomNavbarUser, type BottomNavItem, } from './bottom-navbar.js';
|
|
16
16
|
export { type CommandPageItem, type CommandRegistry, CommandRegistryProvider, type CommandRegistryProviderProps, useCommandRegistry, } from './command-registry.js';
|
|
17
|
+
export { AppShell, AppShellBar, type AppShellBarProps, AppShellBody, AppShellCanvas, type AppShellProps, AppShellSidebar, type AppShellSidebarProps, } from './app-shell.js';
|
|
17
18
|
export { LinkProvider, type LinkProviderProps, useLink } from './link-context.js';
|
|
18
|
-
export { type Notification, NotificationCenter, type NotificationCenterProps, } from './notification-center.js';
|
|
19
|
+
export { type Notification, NotificationCenter, type NotificationCenterProps, type NotificationUnreadStyle, } from './notification-center.js';
|
|
19
20
|
export { type NotificationPreference, NotificationPreferences, type NotificationPreferencesProps, type NotificationProject, } from './notification-preferences.js';
|
|
20
21
|
export { TopBar, type TopBarProps, type TopBarUser, type UserMenuItem, } from './top-bar.js';
|
|
21
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAC,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EACL,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,QAAQ,EACR,WAAW,EACX,KAAK,gBAAgB,EACrB,YAAY,EACZ,cAAc,EACd,KAAK,aAAa,EAClB,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAC,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7E,OAAO,EACL,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,WAAW,CAAA"}
|
package/dist/shell/index.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import { LinkProvider as e, useLink as t } from "../_chunks/link-context.js";
|
|
3
3
|
import { CommandRegistryProvider as n, useCommandRegistry as r } from "./command-registry.js";
|
|
4
4
|
import { AppCommandPalette as i } from "./app-command-palette.js";
|
|
5
|
+
import { AppShell as a, AppShellBar as o, AppShellBody as s, AppShellCanvas as c, AppShellSidebar as l } from "./app-shell.js";
|
|
5
6
|
import "./link-context.js";
|
|
6
|
-
import { BottomNavbar as
|
|
7
|
-
import { NotificationCenter as
|
|
8
|
-
import { NotificationPreferences as
|
|
9
|
-
import { TopBar as
|
|
10
|
-
export { i as AppCommandPalette, a as BottomNavbar, n as CommandRegistryProvider, e as LinkProvider,
|
|
7
|
+
import { BottomNavbar as u } from "./bottom-navbar.js";
|
|
8
|
+
import { NotificationCenter as d } from "./notification-center.js";
|
|
9
|
+
import { NotificationPreferences as f } from "./notification-preferences.js";
|
|
10
|
+
import { TopBar as p } from "./top-bar.js";
|
|
11
|
+
export { i as AppCommandPalette, a as AppShell, o as AppShellBar, s as AppShellBody, c as AppShellCanvas, l as AppShellSidebar, u as BottomNavbar, n as CommandRegistryProvider, e as LinkProvider, d as NotificationCenter, f as NotificationPreferences, p as TopBar, r as useCommandRegistry, t as useLink };
|
|
@@ -23,6 +23,8 @@ export interface Notification {
|
|
|
23
23
|
/** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */
|
|
24
24
|
actions?: NotificationAction[];
|
|
25
25
|
}
|
|
26
|
+
/** Visual weight of an unread row. See `NotificationCenterProps.unreadStyle`. */
|
|
27
|
+
export type NotificationUnreadStyle = 'tint' | 'strong' | 'none';
|
|
26
28
|
export interface NotificationCenterProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
27
29
|
/** List of notifications to display */
|
|
28
30
|
notifications?: Notification[];
|
|
@@ -54,6 +56,21 @@ export interface NotificationCenterProps extends React.ButtonHTMLAttributes<HTML
|
|
|
54
56
|
footerSlot?: React.ReactNode;
|
|
55
57
|
/** Called when the user dismisses a notification. Renders an X button per row when provided. */
|
|
56
58
|
onDismiss?: (id: string) => void;
|
|
59
|
+
/**
|
|
60
|
+
* How an unread row announces itself.
|
|
61
|
+
*
|
|
62
|
+
* - `tint` (default) — an accent wash plus a bold title. The conventional
|
|
63
|
+
* look, and the quietest fill that still reads louder than a hovered
|
|
64
|
+
* already-read row in both themes.
|
|
65
|
+
* - `strong` — a heavier wash, for inboxes where unread has to carry across
|
|
66
|
+
* a long list at a glance.
|
|
67
|
+
* - `none` — no wash at all. The tier dot (which already fades to 20% once
|
|
68
|
+
* read) and the bold title carry the state on their own. The calmest
|
|
69
|
+
* option, and the one that scales best down a long list.
|
|
70
|
+
*
|
|
71
|
+
* @default 'tint'
|
|
72
|
+
*/
|
|
73
|
+
unreadStyle?: NotificationUnreadStyle;
|
|
57
74
|
/** Additional className for the popover content container */
|
|
58
75
|
popoverClassName?: string;
|
|
59
76
|
/** Additional className */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-center.d.ts","sourceRoot":"","sources":["../../src/shell/notification-center.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgC9B,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,8EAA8E;IAC9E,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IACvC,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAC/B;AAED,MAAM,WAAW,uBACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,GAAG,IAAI,CAAA;IACpE,wEAAwE;IACxE,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,gGAAgG;IAChG,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;
|
|
1
|
+
{"version":3,"file":"notification-center.d.ts","sourceRoot":"","sources":["../../src/shell/notification-center.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgC9B,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,8EAA8E;IAC9E,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IACvC,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAC/B;AAED,iFAAiF;AACjF,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEhE,MAAM,WAAW,uBACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,GAAG,IAAI,CAAA;IACpE,wEAAwE;IACxE,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,gGAAgG;IAChG,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,uBAAuB,CAAA;IACrC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA4LD,QAAA,MAAM,kBAAkB,mGAuPvB,CAAA;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|