@devalok/shilp-sutra 0.53.0 → 0.54.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/AGENTS.md +7 -1
- package/BREAKING.json +29 -0
- package/MIGRATION.md +55 -0
- package/dist/composed/avatar-group.d.ts +11 -9
- package/dist/composed/avatar-group.d.ts.map +1 -1
- package/dist/composed/avatar-group.js +108 -140
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.d.ts +19 -11
- package/dist/composed/bulk-action-bar.d.ts.map +1 -1
- package/dist/composed/bulk-action-bar.js +81 -110
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/error-boundary.d.ts +15 -3
- package/dist/composed/error-boundary.d.ts.map +1 -1
- package/dist/composed/error-boundary.js +43 -26
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/loading-skeleton.d.ts +2 -0
- package/dist/composed/loading-skeleton.d.ts.map +1 -1
- package/dist/composed/loading-skeleton.js +79 -56
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/master-detail.d.ts +21 -8
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js +91 -77
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/page-skeletons.d.ts +6 -0
- package/dist/composed/page-skeletons.d.ts.map +1 -1
- package/dist/composed/page-skeletons.js +93 -71
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/shell/index.d.ts +5 -3
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +2 -3
- package/dist/shell/notification-preferences.d.ts.map +1 -1
- package/dist/shell/notification-preferences.js +2 -0
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/ui/combobox.d.ts +1 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +133 -128
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/file-upload.d.ts.map +1 -1
- package/dist/ui/file-upload.js +124 -138
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.d.ts +7 -0
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +4 -2
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/icon-button.d.ts +2 -1
- package/dist/ui/icon-button.d.ts.map +1 -1
- package/dist/ui/icon-button.js +1 -1
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/label.d.ts.map +1 -1
- package/dist/ui/label.js +7 -6
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/spinner.d.ts.map +1 -1
- package/dist/ui/spinner.js +50 -44
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/switch.d.ts.map +1 -1
- package/dist/ui/switch.js +24 -24
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/docs/components/composed/bulk-action-bar.md +9 -3
- package/docs/components/composed/error-boundary.md +18 -2
- package/docs/components/composed/master-detail.md +12 -2
- package/docs/components/composed/page-skeletons.md +2 -2
- package/docs/components/composed/rich-chat-input.md +18 -6
- package/docs/components/composed/simple-tooltip.md +1 -1
- package/docs/components/shell/app-command-palette.md +2 -1
- package/docs/components/shell/bottom-navbar.md +4 -4
- package/docs/components/shell/command-registry.md +2 -2
- package/docs/components/shell/link-context.md +2 -2
- package/docs/components/shell/top-bar.md +1 -1
- package/docs/components/ui/search-input.md +2 -2
- package/docs/components/ui/slider.md +2 -2
- package/docs/components/ui/split-button.md +3 -3
- package/llms.txt +2 -2
- package/make-kit/Guidelines.md +1 -1
- package/make-kit/components/overview.md +2 -2
- package/make-kit/foundations/surfaces.md +1 -1
- package/mcp-manifest.json +403 -147
- package/package.json +1 -6
- package/skill/SKILL.md +1 -1
- package/skill/chat-skill/README.md +18 -0
- package/skill/chat-skill/SKILL.md +78 -0
- package/skill/chat-skill/chatgpt-instructions.md +26 -0
- package/skill/chat-skill/gemini-instructions.md +25 -0
- package/skill/references/components.md +2 -2
- package/dist/shell/sidebar.d.ts +0 -113
- package/dist/shell/sidebar.d.ts.map +0 -1
- package/dist/shell/sidebar.js +0 -293
- package/dist/shell/sidebar.js.map +0 -1
- package/docs/components/shell/sidebar.md +0 -103
package/mcp-manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "./mcp-manifest.schema.json",
|
|
3
3
|
"manifestVersion": "1.2.0",
|
|
4
4
|
"package": "@devalok/shilp-sutra",
|
|
5
|
-
"packageVersion": "0.
|
|
5
|
+
"packageVersion": "0.54.0",
|
|
6
6
|
"components": {
|
|
7
7
|
"accordion": {
|
|
8
8
|
"displayName": "Accordion",
|
|
@@ -5217,6 +5217,7 @@
|
|
|
5217
5217
|
"type": {
|
|
5218
5218
|
"name": "enum",
|
|
5219
5219
|
"value": [
|
|
5220
|
+
"xs",
|
|
5220
5221
|
"sm",
|
|
5221
5222
|
"md",
|
|
5222
5223
|
"lg"
|
|
@@ -5258,7 +5259,7 @@
|
|
|
5258
5259
|
"**`onClear` makes the X button appear** only when `value` is non-empty. Pair them so users can reset.",
|
|
5259
5260
|
"**`loading={true}` swaps the clear button for a spinner** with `aria-busy=\"true\"` on the input — useful for debounced/async search.",
|
|
5260
5261
|
"Doesn't auto-consume FormField (no `state` prop) — wrap a regular Input inside FormField for validated search fields.",
|
|
5261
|
-
"Keyboard: Escape
|
|
5262
|
+
"Keyboard: Escape is NOT wired to clear (the input is not `type=\"search\"`). Reset via the X button, or handle Escape yourself and call your `value` setter."
|
|
5262
5263
|
]
|
|
5263
5264
|
},
|
|
5264
5265
|
"docPath": "docs/components/ui/search-input.md",
|
|
@@ -5695,139 +5696,168 @@
|
|
|
5695
5696
|
]
|
|
5696
5697
|
},
|
|
5697
5698
|
"sidebar": {
|
|
5698
|
-
"displayName": "
|
|
5699
|
-
"tier": "
|
|
5700
|
-
"import": "@devalok/shilp-sutra/
|
|
5699
|
+
"displayName": "Sidebar",
|
|
5700
|
+
"tier": "ui",
|
|
5701
|
+
"import": "@devalok/shilp-sutra/ui/sidebar",
|
|
5701
5702
|
"serverSafe": false,
|
|
5702
5703
|
"description": "",
|
|
5703
|
-
"props": {
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5704
|
+
"props": {},
|
|
5705
|
+
"composition": {
|
|
5706
|
+
"notes": [
|
|
5707
|
+
"`Sidebar` — applies collapsed / expanded / off-canvas styles based on `state`",
|
|
5708
|
+
"`SidebarTrigger` — calls `toggleSidebar()` on click; reflects aria-expanded",
|
|
5709
|
+
"`SidebarMenuButton` — uses `state === 'collapsed'` to show its `tooltip` (hidden label appears only when sidebar is icon-width)",
|
|
5710
|
+
"`SidebarInset` — main content area adjusts its left offset based on sidebar width + state",
|
|
5711
|
+
"`SidebarRail` — invisible hit target on the outer edge for click-to-toggle",
|
|
5712
|
+
"Any user component that calls `useSidebar()` — full access to open/isMobile/toggle **Desktop vs mobile:** Context tracks `isMobile` via the `use-mobile` hook and branches behavior: on desktop the sidebar collapses to an icon rail; on mobile it becomes an off-canvas drawer controlled by `openMobile`. **Controlled or uncontrolled:** `SidebarProvider` accepts `open` + `onOpenChange` (controlled) or `defaultOpen` (uncontrolled). State is synced to a cookie for cross-route persistence. **Next.js / router integration:** `SidebarMenuButton` with `asChild` wraps any link element (`next/link`, `react-router Link`, plain `<a>`) — it transfers its styling + isActive state to the child while preserving the link's navigation semantics."
|
|
5713
|
+
],
|
|
5714
|
+
"parts": [
|
|
5715
|
+
{
|
|
5716
|
+
"name": "SidebarProvider",
|
|
5717
|
+
"description": "context provider — must wrap everything"
|
|
5707
5718
|
},
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
"user": {
|
|
5712
|
-
"type": {
|
|
5713
|
-
"name": "union",
|
|
5714
|
-
"raw": "SidebarUser | null — { name, email?, image?, designation?, role? }"
|
|
5719
|
+
{
|
|
5720
|
+
"name": "Sidebar",
|
|
5721
|
+
"description": "root panel"
|
|
5715
5722
|
},
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
"navGroups": {
|
|
5719
|
-
"type": {
|
|
5720
|
-
"name": "object",
|
|
5721
|
-
"raw": "NavGroup[] — { label: string, items: NavItem[], action?: ReactNode }"
|
|
5723
|
+
{
|
|
5724
|
+
"name": "SidebarHeader"
|
|
5722
5725
|
},
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
"logo": {
|
|
5726
|
-
"type": {
|
|
5727
|
-
"name": "ReactNode"
|
|
5726
|
+
{
|
|
5727
|
+
"name": "SidebarContent"
|
|
5728
5728
|
},
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
"footerLinks": {
|
|
5732
|
-
"type": {
|
|
5733
|
-
"name": "object",
|
|
5734
|
-
"raw": "Array<{ label: string, href: string }>"
|
|
5729
|
+
{
|
|
5730
|
+
"name": "SidebarGroup"
|
|
5735
5731
|
},
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
},
|
|
5739
|
-
"footer": {
|
|
5740
|
-
"type": {
|
|
5741
|
-
"name": "object",
|
|
5742
|
-
"raw": "SidebarFooterConfig — structured footer"
|
|
5732
|
+
{
|
|
5733
|
+
"name": "SidebarGroupLabel"
|
|
5743
5734
|
},
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
},
|
|
5747
|
-
"headerSlot": {
|
|
5748
|
-
"type": {
|
|
5749
|
-
"name": "ReactNode"
|
|
5735
|
+
{
|
|
5736
|
+
"name": "SidebarGroupAction"
|
|
5750
5737
|
},
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
"preFooterSlot": {
|
|
5754
|
-
"type": {
|
|
5755
|
-
"name": "ReactNode"
|
|
5738
|
+
{
|
|
5739
|
+
"name": "SidebarGroupContent"
|
|
5756
5740
|
},
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
"preFooterClassName": {
|
|
5760
|
-
"type": {
|
|
5761
|
-
"name": "object",
|
|
5762
|
-
"raw": "string — className on preFooterSlot wrapper div"
|
|
5741
|
+
{
|
|
5742
|
+
"name": "SidebarMenu"
|
|
5763
5743
|
},
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
"renderItem": {
|
|
5767
|
-
"type": {
|
|
5768
|
-
"name": "function",
|
|
5769
|
-
"raw": "(item: NavItem, defaultRender: () => ReactNode) => ReactNode | null — custom item rendering"
|
|
5744
|
+
{
|
|
5745
|
+
"name": "SidebarMenuItem"
|
|
5770
5746
|
},
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
"type": {
|
|
5775
|
-
"name": "string"
|
|
5747
|
+
{
|
|
5748
|
+
"name": "SidebarMenuButton",
|
|
5749
|
+
"description": "tooltip, isActive"
|
|
5776
5750
|
},
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5751
|
+
{
|
|
5752
|
+
"name": "SidebarMenuAction"
|
|
5753
|
+
},
|
|
5754
|
+
{
|
|
5755
|
+
"name": "SidebarMenuBadge"
|
|
5756
|
+
},
|
|
5757
|
+
{
|
|
5758
|
+
"name": "SidebarMenuSub"
|
|
5759
|
+
},
|
|
5760
|
+
{
|
|
5761
|
+
"name": "SidebarMenuSubItem"
|
|
5762
|
+
},
|
|
5763
|
+
{
|
|
5764
|
+
"name": "SidebarMenuSubButton",
|
|
5765
|
+
"description": "isActive"
|
|
5766
|
+
},
|
|
5767
|
+
{
|
|
5768
|
+
"name": "SidebarFooter"
|
|
5769
|
+
},
|
|
5770
|
+
{
|
|
5771
|
+
"name": "SidebarSeparator"
|
|
5772
|
+
},
|
|
5773
|
+
{
|
|
5774
|
+
"name": "SidebarRail"
|
|
5775
|
+
},
|
|
5776
|
+
{
|
|
5777
|
+
"name": "SidebarInset",
|
|
5778
|
+
"description": "main content area"
|
|
5779
|
+
},
|
|
5780
|
+
{
|
|
5781
|
+
"name": "SidebarTrigger",
|
|
5782
|
+
"description": "hamburger button"
|
|
5783
|
+
},
|
|
5784
|
+
{
|
|
5785
|
+
"name": "SidebarInput",
|
|
5786
|
+
"description": "search input in sidebar"
|
|
5787
|
+
},
|
|
5788
|
+
{
|
|
5789
|
+
"name": "SidebarMenuSkeleton",
|
|
5790
|
+
"description": "loading placeholder"
|
|
5791
|
+
}
|
|
5788
5792
|
]
|
|
5789
5793
|
},
|
|
5790
|
-
"docPath": "docs/components/
|
|
5794
|
+
"docPath": "docs/components/ui/sidebar.md",
|
|
5795
|
+
"defaults": {
|
|
5796
|
+
"variant": "default",
|
|
5797
|
+
"size": "md"
|
|
5798
|
+
},
|
|
5799
|
+
"subComponents": {
|
|
5800
|
+
"SidebarMenuButton": {
|
|
5801
|
+
"props": {
|
|
5802
|
+
"variant": {
|
|
5803
|
+
"type": {
|
|
5804
|
+
"name": "enum",
|
|
5805
|
+
"value": [
|
|
5806
|
+
"default",
|
|
5807
|
+
"outline"
|
|
5808
|
+
]
|
|
5809
|
+
},
|
|
5810
|
+
"required": false
|
|
5811
|
+
},
|
|
5812
|
+
"size": {
|
|
5813
|
+
"type": {
|
|
5814
|
+
"name": "enum",
|
|
5815
|
+
"value": [
|
|
5816
|
+
"sm",
|
|
5817
|
+
"md",
|
|
5818
|
+
"lg"
|
|
5819
|
+
]
|
|
5820
|
+
},
|
|
5821
|
+
"required": false
|
|
5822
|
+
},
|
|
5823
|
+
"isActive": {
|
|
5824
|
+
"type": {
|
|
5825
|
+
"name": "boolean"
|
|
5826
|
+
},
|
|
5827
|
+
"required": false,
|
|
5828
|
+
"description": "highlights as current nav item"
|
|
5829
|
+
},
|
|
5830
|
+
"tooltip": {
|
|
5831
|
+
"type": {
|
|
5832
|
+
"name": "ReactNode"
|
|
5833
|
+
},
|
|
5834
|
+
"required": false,
|
|
5835
|
+
"description": "shown when sidebar is collapsed"
|
|
5836
|
+
},
|
|
5837
|
+
"asChild": {
|
|
5838
|
+
"type": {
|
|
5839
|
+
"name": "boolean"
|
|
5840
|
+
},
|
|
5841
|
+
"required": false,
|
|
5842
|
+
"description": "render as Slot — common with next/link"
|
|
5843
|
+
}
|
|
5844
|
+
}
|
|
5845
|
+
}
|
|
5846
|
+
},
|
|
5791
5847
|
"examples": [
|
|
5792
|
-
"<
|
|
5848
|
+
"<SidebarProvider>\n <Sidebar>\n <SidebarHeader>Logo</SidebarHeader>\n <SidebarContent>\n <SidebarGroup>\n <SidebarGroupLabel>Navigation</SidebarGroupLabel>\n <SidebarGroupContent>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton isActive>\n <IconHome /> Dashboard\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </SidebarContent>\n </Sidebar>\n <SidebarInset>\n <SidebarTrigger />\n <main>Page content</main>\n </SidebarInset>\n</SidebarProvider>"
|
|
5793
5849
|
],
|
|
5794
5850
|
"gotchas": [
|
|
5795
|
-
"
|
|
5796
|
-
"
|
|
5797
|
-
"`
|
|
5798
|
-
"
|
|
5799
|
-
"Collapsible nav items auto-open when a child is active (matching `currentPath`)",
|
|
5800
|
-
"Badge numbers > 99 display as \"99+\""
|
|
5851
|
+
"SidebarProvider MUST wrap both Sidebar and SidebarInset",
|
|
5852
|
+
"Use SidebarMenuButton for nav items (supports tooltip in collapsed state)",
|
|
5853
|
+
"`tooltip` is only visible when sidebar is collapsed — providing one doesn't duplicate the visible label",
|
|
5854
|
+
"Cookie-based state persistence means the sidebar defaults to its prior state on page reload — use `defaultOpen` to override if needed"
|
|
5801
5855
|
],
|
|
5802
5856
|
"changes": [
|
|
5803
|
-
{
|
|
5804
|
-
"version": "0.19.0",
|
|
5805
|
-
"summary": "**Changed** Background elevated from `bg-surface-1` to `bg-surface-2` for visual hierarchy above app background"
|
|
5806
|
-
},
|
|
5807
5857
|
{
|
|
5808
5858
|
"version": "0.18.0",
|
|
5809
5859
|
"summary": "**Fixed** `bg-interactive-subtle` changed to `bg-accent-2` (OKLCH migration)"
|
|
5810
5860
|
},
|
|
5811
|
-
{
|
|
5812
|
-
"version": "0.16.0",
|
|
5813
|
-
"summary": "**Added** `preFooterClassName?: string` — custom className on preFooterSlot wrapper"
|
|
5814
|
-
},
|
|
5815
|
-
{
|
|
5816
|
-
"version": "0.14.0",
|
|
5817
|
-
"summary": "**Changed** `footer.version` now accepts `string | { label: string; href: string }` — version can link to changelog"
|
|
5818
|
-
},
|
|
5819
|
-
{
|
|
5820
|
-
"version": "0.13.0",
|
|
5821
|
-
"summary": "**Added** `SidebarPromo` type and `footer.promo` prop — dismissable promo/upsell banner"
|
|
5822
|
-
},
|
|
5823
|
-
{
|
|
5824
|
-
"version": "0.10.0",
|
|
5825
|
-
"summary": "**Added** Collapsible nav items with `children` array and `NavSubItem` type"
|
|
5826
|
-
},
|
|
5827
|
-
{
|
|
5828
|
-
"version": "0.1.1",
|
|
5829
|
-
"summary": "**Changed** Decoupled from Next.js via LinkProvider"
|
|
5830
|
-
},
|
|
5831
5861
|
{
|
|
5832
5862
|
"version": "0.1.0",
|
|
5833
5863
|
"summary": "**Added** Initial release"
|
|
@@ -6149,7 +6179,7 @@
|
|
|
6149
6179
|
"Radix Slider primitive — keyboard navigation (arrow keys, Home/End, PageUp/PageDown) pre-wired.",
|
|
6150
6180
|
"**Value is always an array** — single-thumb: `[50]`; range: `[25, 75]`. Don't pass a plain number.",
|
|
6151
6181
|
"**Multi-thumb range:** Pass `[start, end]` — renders two thumbs that can cross each other by default. Use `minStepsBetweenThumbs` to enforce a gap.",
|
|
6152
|
-
"**FormField:** Slider
|
|
6182
|
+
"**FormField:** Slider consumes FormField for a11y wiring (`aria-invalid` / `aria-describedby` / `aria-required`) but renders no visual validation treatment — values are valid by construction, so there's no error UX to hand-wire.",
|
|
6153
6183
|
"**No label pairing via Label** — use `aria-label` or `aria-labelledby` directly on the Slider. The thumb is the focusable/labeled element.",
|
|
6154
6184
|
"Not portal-rendered — inline; overflow rules of parents apply."
|
|
6155
6185
|
]
|
|
@@ -6165,7 +6195,7 @@
|
|
|
6165
6195
|
"gotchas": [
|
|
6166
6196
|
"value is number[] (array), not a single number",
|
|
6167
6197
|
"Multi-thumb: Pass array `defaultValue={[25, 75]}` for range sliders — renders one thumb per value",
|
|
6168
|
-
"Slider
|
|
6198
|
+
"Slider consumes FormField for a11y wiring (aria-invalid/describedby/required) but shows no validation visuals by design — don't hand-wire what it already does"
|
|
6169
6199
|
],
|
|
6170
6200
|
"changes": [
|
|
6171
6201
|
{
|
|
@@ -6295,9 +6325,9 @@
|
|
|
6295
6325
|
"composition": {
|
|
6296
6326
|
"notes": [
|
|
6297
6327
|
"**Two-in-one button:** visually unified `[Action | ▼]` with the left half being the primary click and the right half opening a dropdown. Use for actions that have a most-common choice plus alternatives (Save vs. Save-As-Draft, Send vs. Schedule).",
|
|
6298
|
-
"**
|
|
6328
|
+
"**Composes the DS Popover internally** and shares the `color` type + a `variant`/`size` subset with Button (currently `solid`/`soft`/`outline` × the Button colors; no `ghost`/`link`/`lg`). Note: the half styling is implemented locally, not inherited from `Button` — a few Button niceties (e.g. `solid`'s `hover:shadow-brand`) don't apply. Popover placement via `top-end` default suits most top-of-page toolbars.",
|
|
6299
6329
|
"**Dropdown content is consumer-provided** — pass any JSX via `dropdownContent` (typically a DropdownMenu, list of actions, a custom panel, or a small form). Don't try to shove a full-featured menu into the chevron; keep it focused on 2–5 alternatives.",
|
|
6300
|
-
"**ButtonGroup
|
|
6330
|
+
"**ButtonGroup:** SplitButton does NOT consume `ButtonGroup` context — set its `variant`/`color`/`size` explicitly to match a surrounding group.",
|
|
6301
6331
|
"**Controlled dropdown:** Pass `open` + `onOpenChange` for controlled state; omit for uncontrolled. Useful when the dropdown must close programmatically after a selection."
|
|
6302
6332
|
]
|
|
6303
6333
|
},
|
|
@@ -6309,7 +6339,7 @@
|
|
|
6309
6339
|
"changes": [
|
|
6310
6340
|
{
|
|
6311
6341
|
"version": "0.44.2",
|
|
6312
|
-
"summary": "**Fixed** The dropdown is now keyboard-accessible. It previously used a hand-rolled floating panel (`role=\"menu\"`) with no focus management, arrow keys, or Escape — keyboard users couldn't reach or dismiss it. It now composes the DS **Popover** primitive: focus moves in on open, Escape and outside-click close, focus returns to the trigger, and on mobile it opens as a bottom sheet.
|
|
6342
|
+
"summary": "**Fixed** The dropdown is now keyboard-accessible. It previously used a hand-rolled floating panel (`role=\"menu\"`) with no focus management, arrow keys, or Escape — keyboard users couldn't reach or dismiss it. It now composes the DS **Popover** primitive: focus moves in on open, Escape and outside-click close, focus returns to the trigger, and on mobile it opens as a bottom sheet."
|
|
6313
6343
|
},
|
|
6314
6344
|
{
|
|
6315
6345
|
"version": "0.33.0",
|
|
@@ -8544,6 +8574,20 @@
|
|
|
8544
8574
|
},
|
|
8545
8575
|
"required": false
|
|
8546
8576
|
},
|
|
8577
|
+
"totalCount": {
|
|
8578
|
+
"type": {
|
|
8579
|
+
"name": "number"
|
|
8580
|
+
},
|
|
8581
|
+
"required": false,
|
|
8582
|
+
"description": "optional — total selectable items; enables \"Select all\""
|
|
8583
|
+
},
|
|
8584
|
+
"onSelectAll": {
|
|
8585
|
+
"type": {
|
|
8586
|
+
"name": "function",
|
|
8587
|
+
"raw": "() => void (optional — called by the \"Select all\" control)"
|
|
8588
|
+
},
|
|
8589
|
+
"required": false
|
|
8590
|
+
},
|
|
8547
8591
|
"className": {
|
|
8548
8592
|
"type": {
|
|
8549
8593
|
"name": "string"
|
|
@@ -8572,10 +8616,10 @@
|
|
|
8572
8616
|
"icon": {
|
|
8573
8617
|
"type": {
|
|
8574
8618
|
"name": "object",
|
|
8575
|
-
"raw": "
|
|
8619
|
+
"raw": "IconInput"
|
|
8576
8620
|
},
|
|
8577
8621
|
"required": false,
|
|
8578
|
-
"description": "optional icon component"
|
|
8622
|
+
"description": "optional — any icon component or element"
|
|
8579
8623
|
},
|
|
8580
8624
|
"onClick": {
|
|
8581
8625
|
"type": {
|
|
@@ -8588,17 +8632,44 @@
|
|
|
8588
8632
|
"type": {
|
|
8589
8633
|
"name": "enum",
|
|
8590
8634
|
"value": [
|
|
8591
|
-
"
|
|
8592
|
-
"error"
|
|
8635
|
+
"accent",
|
|
8636
|
+
"error",
|
|
8637
|
+
"success",
|
|
8638
|
+
"warning",
|
|
8639
|
+
"info",
|
|
8640
|
+
"neutral"
|
|
8593
8641
|
]
|
|
8594
8642
|
},
|
|
8595
|
-
"required": false
|
|
8643
|
+
"required": false,
|
|
8644
|
+
"defaultValue": "accent"
|
|
8596
8645
|
},
|
|
8597
8646
|
"disabled": {
|
|
8598
8647
|
"type": {
|
|
8599
8648
|
"name": "boolean"
|
|
8600
8649
|
},
|
|
8601
|
-
"required": false
|
|
8650
|
+
"required": false,
|
|
8651
|
+
"description": "optional"
|
|
8652
|
+
},
|
|
8653
|
+
"loading": {
|
|
8654
|
+
"type": {
|
|
8655
|
+
"name": "boolean"
|
|
8656
|
+
},
|
|
8657
|
+
"required": false,
|
|
8658
|
+
"description": "optional — pending spinner on the action"
|
|
8659
|
+
},
|
|
8660
|
+
"requiresConfirmation": {
|
|
8661
|
+
"type": {
|
|
8662
|
+
"name": "boolean"
|
|
8663
|
+
},
|
|
8664
|
+
"required": false,
|
|
8665
|
+
"description": "optional — inline confirm before executing"
|
|
8666
|
+
},
|
|
8667
|
+
"confirmMessage": {
|
|
8668
|
+
"type": {
|
|
8669
|
+
"name": "string"
|
|
8670
|
+
},
|
|
8671
|
+
"required": false,
|
|
8672
|
+
"description": "optional — default \"Are you sure?\""
|
|
8602
8673
|
}
|
|
8603
8674
|
}
|
|
8604
8675
|
}
|
|
@@ -9867,9 +9938,30 @@
|
|
|
9867
9938
|
"onReset": {
|
|
9868
9939
|
"type": {
|
|
9869
9940
|
"name": "function",
|
|
9870
|
-
"raw": "() => void (optional
|
|
9941
|
+
"raw": "() => void (optional — renders a \"Try Again\" button)"
|
|
9871
9942
|
},
|
|
9872
9943
|
"required": false
|
|
9944
|
+
},
|
|
9945
|
+
"actions": {
|
|
9946
|
+
"type": {
|
|
9947
|
+
"name": "ReactNode"
|
|
9948
|
+
},
|
|
9949
|
+
"required": false,
|
|
9950
|
+
"description": "optional — custom recovery actions; replaces the default button"
|
|
9951
|
+
},
|
|
9952
|
+
"fullPage": {
|
|
9953
|
+
"type": {
|
|
9954
|
+
"name": "boolean"
|
|
9955
|
+
},
|
|
9956
|
+
"required": false,
|
|
9957
|
+
"defaultValue": "true — center in a min-h-[60vh] region; false = inline"
|
|
9958
|
+
},
|
|
9959
|
+
"autoFocusReset": {
|
|
9960
|
+
"type": {
|
|
9961
|
+
"name": "boolean"
|
|
9962
|
+
},
|
|
9963
|
+
"required": false,
|
|
9964
|
+
"defaultValue": "false — focus the recovery button on mount"
|
|
9873
9965
|
}
|
|
9874
9966
|
},
|
|
9875
9967
|
"composition": {
|
|
@@ -9882,6 +9974,48 @@
|
|
|
9882
9974
|
]
|
|
9883
9975
|
},
|
|
9884
9976
|
"docPath": "docs/components/composed/error-boundary.md",
|
|
9977
|
+
"subComponents": {
|
|
9978
|
+
"ErrorBoundary": {
|
|
9979
|
+
"props": {
|
|
9980
|
+
"children": {
|
|
9981
|
+
"type": {
|
|
9982
|
+
"name": "ReactNode"
|
|
9983
|
+
},
|
|
9984
|
+
"required": true
|
|
9985
|
+
},
|
|
9986
|
+
"onReset": {
|
|
9987
|
+
"type": {
|
|
9988
|
+
"name": "function",
|
|
9989
|
+
"raw": "() => void (optional — called after the boundary resets)"
|
|
9990
|
+
},
|
|
9991
|
+
"required": false
|
|
9992
|
+
},
|
|
9993
|
+
"onError": {
|
|
9994
|
+
"type": {
|
|
9995
|
+
"name": "function",
|
|
9996
|
+
"raw": "(error: unknown, info: React.ErrorInfo) => void (optional — wire Sentry/logging)"
|
|
9997
|
+
},
|
|
9998
|
+
"required": false
|
|
9999
|
+
},
|
|
10000
|
+
"resetKeys": {
|
|
10001
|
+
"type": {
|
|
10002
|
+
"name": "object",
|
|
10003
|
+
"raw": "unknown[]"
|
|
10004
|
+
},
|
|
10005
|
+
"required": false,
|
|
10006
|
+
"description": "optional — auto-reset when any value changes; react-error-boundary parity"
|
|
10007
|
+
},
|
|
10008
|
+
"fallback": {
|
|
10009
|
+
"type": {
|
|
10010
|
+
"name": "function",
|
|
10011
|
+
"raw": "(props: { error: unknown; onReset: () => void }) => ReactNode (optional — defaults to ErrorDisplay)"
|
|
10012
|
+
},
|
|
10013
|
+
"required": false
|
|
10014
|
+
}
|
|
10015
|
+
},
|
|
10016
|
+
"note": "class boundary — wrap a subtree"
|
|
10017
|
+
}
|
|
10018
|
+
},
|
|
9885
10019
|
"examples": [
|
|
9886
10020
|
"<ErrorDisplay error={error} onReset={() => refetch()} />"
|
|
9887
10021
|
],
|
|
@@ -10554,9 +10688,31 @@
|
|
|
10554
10688
|
"raw": "string | null"
|
|
10555
10689
|
},
|
|
10556
10690
|
"required": false,
|
|
10557
|
-
"description": "
|
|
10691
|
+
"description": "CONTROLLED selected item id; omit for uncontrolled",
|
|
10558
10692
|
"defaultValue": "{null}"
|
|
10559
10693
|
},
|
|
10694
|
+
"defaultSelected": {
|
|
10695
|
+
"type": {
|
|
10696
|
+
"name": "union",
|
|
10697
|
+
"raw": "string | null"
|
|
10698
|
+
},
|
|
10699
|
+
"required": false,
|
|
10700
|
+
"description": "uncontrolled initial selection"
|
|
10701
|
+
},
|
|
10702
|
+
"onSelect": {
|
|
10703
|
+
"type": {
|
|
10704
|
+
"name": "function",
|
|
10705
|
+
"raw": "(value: string) => void (called with a row's `value` when chosen)"
|
|
10706
|
+
},
|
|
10707
|
+
"required": false
|
|
10708
|
+
},
|
|
10709
|
+
"label": {
|
|
10710
|
+
"type": {
|
|
10711
|
+
"name": "string"
|
|
10712
|
+
},
|
|
10713
|
+
"required": false,
|
|
10714
|
+
"description": "accessible name for the listbox; default \"Items\""
|
|
10715
|
+
},
|
|
10560
10716
|
"onBack": {
|
|
10561
10717
|
"type": {
|
|
10562
10718
|
"name": "function",
|
|
@@ -10584,6 +10740,20 @@
|
|
|
10584
10740
|
"required": false,
|
|
10585
10741
|
"description": "below this, stacked mobile mode activates",
|
|
10586
10742
|
"defaultValue": "md"
|
|
10743
|
+
},
|
|
10744
|
+
"emptyState": {
|
|
10745
|
+
"type": {
|
|
10746
|
+
"name": "ReactNode"
|
|
10747
|
+
},
|
|
10748
|
+
"required": false,
|
|
10749
|
+
"description": "shown in the detail pane when nothing is selected"
|
|
10750
|
+
},
|
|
10751
|
+
"onNavigate": {
|
|
10752
|
+
"type": {
|
|
10753
|
+
"name": "function",
|
|
10754
|
+
"raw": "(direction: \"up\" | \"down\") => void"
|
|
10755
|
+
},
|
|
10756
|
+
"required": false
|
|
10587
10757
|
}
|
|
10588
10758
|
},
|
|
10589
10759
|
"composition": {
|
|
@@ -10604,12 +10774,19 @@
|
|
|
10604
10774
|
"subComponents": {
|
|
10605
10775
|
"MasterDetail.ListItem": {
|
|
10606
10776
|
"props": {
|
|
10777
|
+
"value": {
|
|
10778
|
+
"type": {
|
|
10779
|
+
"name": "string"
|
|
10780
|
+
},
|
|
10781
|
+
"required": false,
|
|
10782
|
+
"description": "row id — enables derived selection + auto-fires onSelect on activate"
|
|
10783
|
+
},
|
|
10607
10784
|
"active": {
|
|
10608
10785
|
"type": {
|
|
10609
10786
|
"name": "boolean"
|
|
10610
10787
|
},
|
|
10611
10788
|
"required": false,
|
|
10612
|
-
"description": "
|
|
10789
|
+
"description": "explicit highlight; omit to derive from value === selected"
|
|
10613
10790
|
}
|
|
10614
10791
|
}
|
|
10615
10792
|
}
|
|
@@ -10997,9 +11174,9 @@
|
|
|
10997
11174
|
"notes": [
|
|
10998
11175
|
"**Full-page skeleton layouts** for route-level loading states. Each mimics a common page shape (dashboard tiles, project list with filters, task detail with sidebar).",
|
|
10999
11176
|
"**Server-safe** — use in Next.js app router `loading.tsx` files for instant route-transition feedback while data streams.",
|
|
11000
|
-
"**
|
|
11177
|
+
"**Assembled from `ui/Skeleton`** — these compose the base `Skeleton` primitive directly into page-shaped layouts (they do NOT wrap the `LoadingSkeleton` regional exports). Each root is a `role=\"status\"` / `aria-busy` region with an sr-only label.",
|
|
11001
11178
|
"**When to use which skeleton tier:** - `<Skeleton>` (ui) — single shape for a single element - `<CardSkeleton>` / `<TableSkeleton>` (LoadingSkeleton) — individual region shape - `<DashboardSkeleton>` / etc. (PageSkeletons) — full page placeholder",
|
|
11002
|
-
"**Fixed layout structure** — the className prop adjusts the outer container, but internal layout isn't customizable. For custom page skeletons, compose LoadingSkeleton
|
|
11179
|
+
"**Fixed layout structure** — the className prop adjusts the outer container, but internal layout isn't customizable. For custom page skeletons, compose `ui/Skeleton` (or the `LoadingSkeleton` regional exports) yourself."
|
|
11003
11180
|
]
|
|
11004
11181
|
},
|
|
11005
11182
|
"docPath": "docs/components/composed/page-skeletons.md",
|
|
@@ -11268,7 +11445,7 @@
|
|
|
11268
11445
|
"onSubmit": {
|
|
11269
11446
|
"type": {
|
|
11270
11447
|
"name": "function",
|
|
11271
|
-
"raw": "(
|
|
11448
|
+
"raw": "(message: RichChatInputMessage) => void (REQUIRED)"
|
|
11272
11449
|
},
|
|
11273
11450
|
"required": false
|
|
11274
11451
|
},
|
|
@@ -11286,24 +11463,27 @@
|
|
|
11286
11463
|
"required": false,
|
|
11287
11464
|
"defaultValue": false
|
|
11288
11465
|
},
|
|
11466
|
+
"content": {
|
|
11467
|
+
"type": {
|
|
11468
|
+
"name": "object",
|
|
11469
|
+
"raw": "string — initial HTML"
|
|
11470
|
+
},
|
|
11471
|
+
"required": false,
|
|
11472
|
+
"description": "not reactive; use for message editing"
|
|
11473
|
+
},
|
|
11289
11474
|
"variant": {
|
|
11290
11475
|
"type": {
|
|
11291
11476
|
"name": "enum",
|
|
11292
11477
|
"value": [
|
|
11293
11478
|
"compact",
|
|
11294
11479
|
"expanded",
|
|
11295
|
-
"minimal"
|
|
11480
|
+
"minimal",
|
|
11481
|
+
"inline"
|
|
11296
11482
|
]
|
|
11297
11483
|
},
|
|
11298
11484
|
"required": false,
|
|
11299
11485
|
"defaultValue": "compact"
|
|
11300
11486
|
},
|
|
11301
|
-
"maxRows": {
|
|
11302
|
-
"type": {
|
|
11303
|
-
"name": "number"
|
|
11304
|
-
},
|
|
11305
|
-
"required": false
|
|
11306
|
-
},
|
|
11307
11487
|
"enterBehavior": {
|
|
11308
11488
|
"type": {
|
|
11309
11489
|
"name": "enum",
|
|
@@ -11322,6 +11502,19 @@
|
|
|
11322
11502
|
},
|
|
11323
11503
|
"required": false
|
|
11324
11504
|
},
|
|
11505
|
+
"charCountDisplay": {
|
|
11506
|
+
"type": {
|
|
11507
|
+
"name": "enum",
|
|
11508
|
+
"value": [
|
|
11509
|
+
"always",
|
|
11510
|
+
"focus",
|
|
11511
|
+
"near-limit",
|
|
11512
|
+
"hidden"
|
|
11513
|
+
]
|
|
11514
|
+
},
|
|
11515
|
+
"required": false,
|
|
11516
|
+
"defaultValue": "near-limit"
|
|
11517
|
+
},
|
|
11325
11518
|
"mentions": {
|
|
11326
11519
|
"type": {
|
|
11327
11520
|
"name": "object",
|
|
@@ -11364,6 +11557,34 @@
|
|
|
11364
11557
|
},
|
|
11365
11558
|
"required": false
|
|
11366
11559
|
},
|
|
11560
|
+
"onVoiceRecord": {
|
|
11561
|
+
"type": {
|
|
11562
|
+
"name": "function",
|
|
11563
|
+
"raw": "(audio: Blob, duration: number) => void"
|
|
11564
|
+
},
|
|
11565
|
+
"required": false
|
|
11566
|
+
},
|
|
11567
|
+
"onTranscribe": {
|
|
11568
|
+
"type": {
|
|
11569
|
+
"name": "function",
|
|
11570
|
+
"raw": "(blob: Blob, duration: number) => Promise<string | null> — transcribe after recording; return null to attach as a voice note"
|
|
11571
|
+
},
|
|
11572
|
+
"required": false
|
|
11573
|
+
},
|
|
11574
|
+
"maxDuration": {
|
|
11575
|
+
"type": {
|
|
11576
|
+
"name": "object",
|
|
11577
|
+
"raw": "number — max voice-recording seconds"
|
|
11578
|
+
},
|
|
11579
|
+
"required": false
|
|
11580
|
+
},
|
|
11581
|
+
"replyTo": {
|
|
11582
|
+
"type": {
|
|
11583
|
+
"name": "function",
|
|
11584
|
+
"raw": "{ id: string; author: string; preview: string; onDismiss: () => void } — reply banner above the input"
|
|
11585
|
+
},
|
|
11586
|
+
"required": false
|
|
11587
|
+
},
|
|
11367
11588
|
"onTyping": {
|
|
11368
11589
|
"type": {
|
|
11369
11590
|
"name": "function",
|
|
@@ -11414,16 +11635,50 @@
|
|
|
11414
11635
|
"toolbar": {
|
|
11415
11636
|
"type": {
|
|
11416
11637
|
"name": "union",
|
|
11417
|
-
"raw": "boolean | ChatToolbarItem[]"
|
|
11638
|
+
"raw": "boolean | ChatToolbarItem[] | ReactNode (default: true) — true = default toolbar, array = whitelist, ReactNode = custom, false = hidden"
|
|
11639
|
+
},
|
|
11640
|
+
"required": false
|
|
11641
|
+
},
|
|
11642
|
+
"actionButton": {
|
|
11643
|
+
"type": {
|
|
11644
|
+
"name": "ReactNode"
|
|
11418
11645
|
},
|
|
11419
11646
|
"required": false,
|
|
11420
|
-
"
|
|
11647
|
+
"description": "replaces the default attach button; false hides it"
|
|
11648
|
+
},
|
|
11649
|
+
"emojiSet": {
|
|
11650
|
+
"type": {
|
|
11651
|
+
"name": "enum",
|
|
11652
|
+
"value": [
|
|
11653
|
+
"native",
|
|
11654
|
+
"apple",
|
|
11655
|
+
"google",
|
|
11656
|
+
"twitter",
|
|
11657
|
+
"facebook"
|
|
11658
|
+
]
|
|
11659
|
+
},
|
|
11660
|
+
"required": false,
|
|
11661
|
+
"defaultValue": "native"
|
|
11662
|
+
},
|
|
11663
|
+
"onSchedule": {
|
|
11664
|
+
"type": {
|
|
11665
|
+
"name": "function",
|
|
11666
|
+
"raw": "(message: RichChatInputMessage, scheduledAt: Date) => void — if set, a schedule button appears next to send"
|
|
11667
|
+
},
|
|
11668
|
+
"required": false
|
|
11669
|
+
},
|
|
11670
|
+
"sendOptions": {
|
|
11671
|
+
"type": {
|
|
11672
|
+
"name": "function",
|
|
11673
|
+
"raw": "Array<{ label: string; icon?: ComponentType<{ className?: string }>; onSelect: () => void }> — split-send dropdown options"
|
|
11674
|
+
},
|
|
11675
|
+
"required": false
|
|
11421
11676
|
}
|
|
11422
11677
|
}
|
|
11423
11678
|
}
|
|
11424
11679
|
},
|
|
11425
11680
|
"examples": [
|
|
11426
|
-
"<RichChatInput\n onSubmit={(
|
|
11681
|
+
"<RichChatInput\n onSubmit={(message) => sendMessage(message.html)}\n mentions={teamMembers}\n onFileUpload={uploadFile}\n slashCommands={[{ label: 'Actions', commands: [...] }]}\n/>\n\n<RichChatInput\n variant=\"expanded\"\n onSubmit={handleSubmit}\n maxLength={2000}\n disclaimer=\"AI-generated content may be inaccurate.\"\n/>\n\n<RichChatInput\n variant=\"minimal\"\n enterBehavior=\"newline\"\n onSubmit={handleReply}\n/>"
|
|
11427
11682
|
],
|
|
11428
11683
|
"gotchas": [
|
|
11429
11684
|
"Tiptap is bundled — no need to install `@tiptap/*` packages separately",
|
|
@@ -11817,7 +12072,7 @@
|
|
|
11817
12072
|
"notes": [
|
|
11818
12073
|
"**One-liner Tooltip** — wraps TooltipProvider + Tooltip + TooltipTrigger + TooltipContent so consumers don't have to manually compose them for a simple label.",
|
|
11819
12074
|
"**When to use:** 90% of tooltip use cases (icon-only button labels, abbreviated text expansions, secondary info). Use the ui/Tooltip compound for advanced cases (controlled open, nested triggers, custom animations).",
|
|
11820
|
-
"**
|
|
12075
|
+
"**Always mounts its own TooltipProvider** — safe to drop anywhere. Note it does NOT inherit an ancestor `TooltipProvider`'s `delayDuration`; its own `delayDuration` prop (default 300ms) always wins. Set it per-tooltip via the prop.",
|
|
11821
12076
|
"**Content must be inert** — same rule as ui/Tooltip. For interactive popped content, use Popover or HoverCard.",
|
|
11822
12077
|
"**Pairs with IconButton** — the canonical pattern for labeled icon buttons."
|
|
11823
12078
|
]
|
|
@@ -12051,11 +12306,12 @@
|
|
|
12051
12306
|
},
|
|
12052
12307
|
"docPath": "docs/components/shell/app-command-palette.md",
|
|
12053
12308
|
"examples": [
|
|
12054
|
-
"<AppCommandPalette\n user={{ name: 'John', role: '
|
|
12309
|
+
"<AppCommandPalette\n user={{ name: 'John', role: 'Admin' }}\n isAdmin={true}\n onNavigate={(path) => router.push(path)}\n searchResults={results}\n onSearchResultSelect={(r) => router.push(`/${r.entityType}/${r.id}`)}\n/>"
|
|
12055
12310
|
],
|
|
12056
12311
|
"gotchas": [
|
|
12057
12312
|
"Uses CommandRegistry context for page navigation items (see CommandRegistryProvider)",
|
|
12058
12313
|
"`isAdmin` takes precedence over `user.role` for showing admin command groups",
|
|
12314
|
+
"**Role detection is case-sensitive:** `user.role` only auto-enables admin groups when it is exactly `'Admin'` or `'SuperAdmin'`. `'admin'` (lowercase) silently shows nothing — pass `isAdmin` explicitly if your role strings differ.",
|
|
12059
12315
|
"Should be placed at the app root level, typically alongside TopBar"
|
|
12060
12316
|
],
|
|
12061
12317
|
"changes": [
|
|
@@ -12139,8 +12395,8 @@
|
|
|
12139
12395
|
},
|
|
12140
12396
|
"composition": {
|
|
12141
12397
|
"notes": [
|
|
12142
|
-
"**Mobile-only bottom nav** — fixed to bottom of viewport. Desktop should use
|
|
12143
|
-
"**Responsive switch pattern:** Use `useIsMobile()` hook to conditionally render
|
|
12398
|
+
"**Mobile-only bottom nav** — fixed to bottom of viewport. Desktop should use Sidebar instead.",
|
|
12399
|
+
"**Responsive switch pattern:** Use `useIsMobile()` hook to conditionally render Sidebar (desktop) or BottomNavbar (mobile). Example: ```jsx const isMobile = useIsMobile() return isMobile ? <BottomNavbar ... /> : <Sidebar ... /> ```",
|
|
12144
12400
|
"**Primary vs overflow:** `primaryItems` (max 4) for the always-visible slots; `moreItems` go into a \"More\" sheet that opens on tap. Don't exceed 4 primary — the bar becomes cramped.",
|
|
12145
12401
|
"**Router integration via LinkProvider:** Each nav item is rendered using the framework-specific Link component registered in LinkProvider. Without LinkProvider, you get full-page reloads on tap.",
|
|
12146
12402
|
"**Badge numbers** cap at 99+ (composes the `Badge` primitive).",
|
|
@@ -12158,7 +12414,7 @@
|
|
|
12158
12414
|
"gotchas": [
|
|
12159
12415
|
"Designed for mobile viewports — fixed to bottom of screen",
|
|
12160
12416
|
"Max 4 `primaryItems` recommended; overflow goes in `moreItems` shown in a \"More\" sheet",
|
|
12161
|
-
"Use with `useIsMobile()` hook to conditionally render instead of
|
|
12417
|
+
"Use with `useIsMobile()` hook to conditionally render instead of Sidebar",
|
|
12162
12418
|
"Requires LinkProvider for framework-specific link components (e.g., Next.js Link)"
|
|
12163
12419
|
],
|
|
12164
12420
|
"changes": [
|
|
@@ -12199,7 +12455,7 @@
|
|
|
12199
12455
|
"notes": [
|
|
12200
12456
|
"**Context provider for AppCommandPalette.** Registers page-level navigation items that the command palette surfaces as commands.",
|
|
12201
12457
|
"**Place at app root** — wrap both AppCommandPalette and the rest of the app inside `<CommandRegistryProvider>`. Positioning matters: any AppCommandPalette outside the provider gets `useCommandRegistry() === null` and falls back to minimal functionality.",
|
|
12202
|
-
"**Separation of pages vs adminPages** —
|
|
12458
|
+
"**Separation of pages vs adminPages** — this is an ORGANIZATIONAL split, not access control. The component does NOT enforce anything: YOU populate `adminPages` conditionally (e.g. only when the signed-in user is an admin). Anything you put in `adminPages` is still shipped to the client — do real authorization on the server, not here.",
|
|
12203
12459
|
"**useCommandRegistry()** is the consumer hook — returns the full registry or null. Use in your own command-aware components (e.g. a Spotlight-style keyboard-search embed elsewhere in the app).",
|
|
12204
12460
|
"**Works with LinkProvider** — CommandPaletteItems navigate via `onNavigate` prop on AppCommandPalette, which routes to your framework's Link component."
|
|
12205
12461
|
]
|
|
@@ -12274,7 +12530,7 @@
|
|
|
12274
12530
|
},
|
|
12275
12531
|
"composition": {
|
|
12276
12532
|
"notes": [
|
|
12277
|
-
"**The framework router bridge for all shell components.** Without LinkProvider,
|
|
12533
|
+
"**The framework router bridge for all shell components.** Without LinkProvider, Sidebar / BottomNavbar / TopBar.UserMenu / AppCommandPalette render plain `<a>` tags — that means full page reloads instead of client-side navigation.",
|
|
12278
12534
|
"**Required setup:** ```tsx // Next.js import Link from 'next/link' <LinkProvider component={Link}> <App /> </LinkProvider> ```",
|
|
12279
12535
|
"**Place at app root** — above every shell component that renders nav links.",
|
|
12280
12536
|
"**component must be forwardRef** (Next.js Link, Remix Link, react-router Link all qualify). Custom components need to forward ref + forward className + forward all anchor props.",
|
|
@@ -12297,7 +12553,7 @@
|
|
|
12297
12553
|
}
|
|
12298
12554
|
},
|
|
12299
12555
|
"examples": [
|
|
12300
|
-
"import Link from 'next/link'\n\n<LinkProvider component={Link}>\n <
|
|
12556
|
+
"import Link from 'next/link'\n\n<LinkProvider component={Link}>\n <Sidebar ... />\n <BottomNavbar ... />\n</LinkProvider>"
|
|
12301
12557
|
],
|
|
12302
12558
|
"gotchas": [
|
|
12303
12559
|
"Without LinkProvider, shell components render plain `<a>` tags (full page reloads)",
|
|
@@ -12582,7 +12838,7 @@
|
|
|
12582
12838
|
"**NotificationCenter lives inside TopBar.Right** — it's a complete bell+popover component. Drop it in a TopBar.Section next to other icon buttons.",
|
|
12583
12839
|
"**UserMenu is composable:** `userMenuItems` inserts custom items between the built-in Profile and the color-mode toggle. Each item can navigate (href), run an action (onClick), or show a separator/badge/color decoration.",
|
|
12584
12840
|
"**Responsive hiding:** Actions that shouldn't appear on mobile use `className=\"hidden md:flex\"` on the IconButton — the component doesn't enforce mobile hiding; that's layout responsibility.",
|
|
12585
|
-
"**Pairs with
|
|
12841
|
+
"**Pairs with Sidebar** — desktop app shell is typically `<TopBar>` + `<Sidebar>` + main content region."
|
|
12586
12842
|
]
|
|
12587
12843
|
},
|
|
12588
12844
|
"docPath": "docs/components/shell/top-bar.md",
|