rift-ds 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +11 -3
  3. package/components/AppLayout/AppLayout.css +13 -3
  4. package/components/AppLayout/AppLayout.d.ts +5 -1
  5. package/components/AppLayout/AppLayout.js +4 -0
  6. package/components/AppSidebar/AppSidebar.css +237 -0
  7. package/components/AppSidebar/AppSidebar.d.ts +32 -3
  8. package/components/AppSidebar/AppSidebar.js +187 -16
  9. package/components/BottomNav/BottomNav.css +417 -0
  10. package/components/BottomNav/BottomNav.d.ts +73 -0
  11. package/components/BottomNav/BottomNav.js +100 -0
  12. package/components/Chart/AreaChart.js +67 -56
  13. package/components/Chart/BarChart.js +67 -56
  14. package/components/Chart/ComboChart.js +93 -82
  15. package/components/Chart/LineChart.js +59 -48
  16. package/components/Chart/PieChart.js +56 -45
  17. package/components/Chart/RadarChart.js +60 -49
  18. package/components/Chart/RadialChart.js +70 -59
  19. package/components/Chart/ScatterChart.js +61 -50
  20. package/components/Chart/StackedBarChart.js +64 -53
  21. package/components/Chart/Treemap.js +34 -23
  22. package/components/Nav/Nav.d.ts +11 -3
  23. package/components/Nav/Nav.js +3 -2
  24. package/components/SidebarPanel/SidebarPanel.css +291 -0
  25. package/components/SidebarPanel/SidebarPanel.d.ts +45 -0
  26. package/components/SidebarPanel/SidebarPanel.js +166 -0
  27. package/components/Stepper/Stepper.d.ts +3 -1
  28. package/components/Stepper/Stepper.js +1 -1
  29. package/components/TopAppBar/TopAppBar.css +464 -0
  30. package/components/TopAppBar/TopAppBar.d.ts +80 -0
  31. package/components/TopAppBar/TopAppBar.js +138 -0
  32. package/components/registry.json +25 -1
  33. package/components/registry.json.d.ts +25 -1
  34. package/components/registry.json.js +1 -1
  35. package/index.d.ts +3 -0
  36. package/index.js +6 -0
  37. package/package.json +5 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Rob Ritacca
3
+ Copyright (c) 2026 Robert Ritacca
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,4 +1,6 @@
1
- <a href="https://rift-ds.com"><img src=".github/readme-banner.jpg" alt="Rift DS, the AI-ready React design system" width="100%"></a>
1
+ <!-- banner:start -->
2
+ <a href="https://rift-ds.com"><img src="https://raw.githubusercontent.com/robritacca-dotcom/rift-ds/main/.github/readme-banner.jpg" alt="Rift DS, the AI-ready React design system" width="100%"></a>
3
+ <!-- banner:end -->
2
4
 
3
5
  # Rift DS
4
6
 
@@ -71,13 +73,13 @@ import 'rift-ds/tokens/presets/presets.css';
71
73
 
72
74
  ## Components
73
75
 
74
- <!-- component-count -->133<!-- /component-count --> components, including a chat set for AI products (Chat thread, Composer, Tool call, Reasoning, Thread panel) and Shader field, a WebGL2 ambient background whose light sources read your colour tokens at runtime, so it re-themes with everything else. Details and live examples are on the [docs site](https://rift-ds.com/components).
76
+ <!-- component-count -->136<!-- /component-count --> components, including a chat set for AI products (Chat thread, Composer, Tool call, Reasoning, Thread panel) and Shader field, a WebGL2 ambient background whose light sources read your colour tokens at runtime, so it re-themes with everything else. Details and live examples are on the [docs site](https://rift-ds.com/components).
75
77
 
76
78
  <details>
77
79
  <summary>The full list</summary>
78
80
 
79
81
  <!-- component-list:start -->
80
- Accordion · Agent plan · Agent rail · Agent status · AI button · Alert · Alert dialog · Anchor nav · Animated number · App layout · App sidebar · Area chart · Avatar · Avatar group · Badge · Banner · Bar chart · Breadcrumb · Button · Button group · Card · Card stack · Carousel · Chat header · Chat marker · Chat message · Chat thread · Checkbox · Chip · Circular button · Code block · Code diff · Colour picker · Combo chart · Combobox · Command palette · Composer · Contact card · Context menu · Contribution graph · Data table · Date input · Date picker · Dialog · Divider · Document chip · Drawer · Dropdown · Dropdown menu · Empty state · Entity card · Event calendar · Field · Figure · File input · Filter bar · Funnel chart · Gantt chart · Gauge · Globe · Hover card · Image compare · Input · Instructions · Interrupt card · Kbd · Legend tile · Lightbox · Line chart · Link list · Map callout · Map legend · Message actions · Message card · Meter · Model picker · Nav · Nav list · Notification centre · Number input · Pagination · Panel · Pie chart · Pin input · Popover · Progress bar · Prompt suggestions · Prose · Quote · Radar chart · Radial chart · Radio button · Rating · Reasoning · Rich dropdown · Scatter chart · Section title · Segmented control · Selection card · Shader field · Skeleton · Slider · Source chip · Source trail · Sparkline · Spinner · Split button · Split pane · Stacked bar chart · Stat · Status dot · Stepper · Streaming text · Swatch · Table · Tabs · Tag input · Textarea · Thread panel · Thread tabs · Time picker · Timeline · Toast · Toggle group · Toggle switch · Tool call · Toolbar · Tooltip · Tree view · Treemap · Usage card · Waveform · World map
82
+ Accordion · Agent plan · Agent rail · Agent status · AI button · Alert · Alert dialog · Anchor nav · Animated number · App layout · App sidebar · Area chart · Avatar · Avatar group · Badge · Banner · Bar chart · Bottom nav · Breadcrumb · Button · Button group · Card · Card stack · Carousel · Chat header · Chat marker · Chat message · Chat thread · Checkbox · Chip · Circular button · Code block · Code diff · Colour picker · Combo chart · Combobox · Command palette · Composer · Contact card · Context menu · Contribution graph · Data table · Date input · Date picker · Dialog · Divider · Document chip · Drawer · Dropdown · Dropdown menu · Empty state · Entity card · Event calendar · Field · Figure · File input · Filter bar · Funnel chart · Gantt chart · Gauge · Globe · Hover card · Image compare · Input · Instructions · Interrupt card · Kbd · Legend tile · Lightbox · Line chart · Link list · Map callout · Map legend · Message actions · Message card · Meter · Model picker · Nav · Nav list · Notification centre · Number input · Pagination · Panel · Pie chart · Pin input · Popover · Progress bar · Prompt suggestions · Prose · Quote · Radar chart · Radial chart · Radio button · Rating · Reasoning · Rich dropdown · Scatter chart · Section title · Segmented control · Selection card · Shader field · Sidebar panel · Skeleton · Slider · Source chip · Source trail · Sparkline · Spinner · Split button · Split pane · Stacked bar chart · Stat · Status dot · Stepper · Streaming text · Swatch · Table · Tabs · Tag input · Textarea · Thread panel · Thread tabs · Time picker · Timeline · Toast · Toggle group · Toggle switch · Tool call · Toolbar · Tooltip · Top app bar · Tree view · Treemap · Usage card · Waveform · World map
81
83
  <!-- component-list:end -->
82
84
 
83
85
  </details>
@@ -102,6 +104,12 @@ npm run dev --workspace website # docs site at http://localhost:3000
102
104
  npm run verify # the full local quality gate, mirroring CI
103
105
  ```
104
106
 
107
+ ## Author
108
+
109
+ <!-- author:start -->
110
+ Designed and built by [Robert Ritacca](https://robertritacca.com).
111
+ <!-- author:end -->
112
+
105
113
  ## License
106
114
 
107
115
  MIT, the whole repository: components, tokens, scripts, the website, and the docs. Use it in anything. See [`LICENSE`](LICENSE) for the full terms.
@@ -16,14 +16,24 @@
16
16
  flex: 1;
17
17
  display: flex;
18
18
  justify-content: center;
19
- margin-left: 64px;
19
+ /* The rail's width plus, while it shows, the side panel's. */
20
+ margin-left: calc(var(--ds-app-layout-rail, 64px) + var(--ds-app-layout-panel, 0px));
20
21
  padding: var(--padding-1000) var(--padding-500);
21
22
  transition: margin-left var(--motion-duration-slow) var(--motion-ease-emphasized);
22
23
  min-width: 0;
23
24
  }
24
25
 
25
- .ds-app-layout--expanded .ds-app-layout__main {
26
- margin-left: 280px;
26
+ .ds-app-layout--expanded {
27
+ --ds-app-layout-rail: 280px;
28
+ }
29
+
30
+ /* Panel mode's collapsed rail is the wider, labelled one. */
31
+ .ds-app-layout:not(.ds-app-layout--expanded):has(.ds-app-sidebar--panel-mode) {
32
+ --ds-app-layout-rail: 80px;
33
+ }
34
+
35
+ .ds-app-layout:has(.ds-app-sidebar__panel--visible) {
36
+ --ds-app-layout-panel: 240px;
27
37
  }
28
38
 
29
39
  /* ============================================
@@ -9,6 +9,10 @@ export interface AppLayoutProps {
9
9
  activeKey?: string;
10
10
  /** Active sub-item key */
11
11
  activeSubKey?: string;
12
+ /** Active third-level item key, listed in the sidebar's side panel */
13
+ activeTertiaryKey?: string;
14
+ /** Where sub-items show: the sidebar's accordion, or straight into its side panel (see AppSidebar) */
15
+ subNav?: 'accordion' | 'panel';
12
16
  /** Whether sidebar starts expanded */
13
17
  defaultExpanded?: boolean;
14
18
  /** Logo text next to icon */
@@ -30,4 +34,4 @@ export interface AppLayoutProps {
30
34
  * AppLayout — full-page template with a collapsible sidebar
31
35
  * and a centred content area.
32
36
  */
33
- export declare const AppLayout: ({ sections, profile, activeKey, activeSubKey, defaultExpanded, logoText, logo, children, theme, className, }: AppLayoutProps) => React.JSX.Element;
37
+ export declare const AppLayout: ({ sections, profile, activeKey, activeSubKey, activeTertiaryKey, subNav, defaultExpanded, logoText, logo, children, theme, className, }: AppLayoutProps) => React.JSX.Element;
@@ -8,6 +8,8 @@ const AppLayout = ({
8
8
  profile,
9
9
  activeKey,
10
10
  activeSubKey,
11
+ activeTertiaryKey,
12
+ subNav,
11
13
  defaultExpanded = true,
12
14
  logoText,
13
15
  logo,
@@ -33,6 +35,8 @@ const AppLayout = ({
33
35
  profile,
34
36
  activeKey,
35
37
  activeSubKey,
38
+ activeTertiaryKey,
39
+ subNav,
36
40
  expanded,
37
41
  onExpandedChange: handleExpandedChange,
38
42
  logoText,
@@ -18,7 +18,13 @@
18
18
  height: 100vh;
19
19
  width: 64px;
20
20
  padding: var(--padding-500) 0;
21
+ /* The vertical padding sits inside the viewport height; content-box
22
+ sizing ran the rail 40px past the bottom and clipped the profile. */
23
+ box-sizing: border-box;
21
24
  background-color: var(--color-bg-page-primary);
25
+ /* The logo mark draws in currentColor; without a colour of its own the
26
+ rail inherited the host's, and the mark vanished on a dark host. */
27
+ color: var(--color-text-primary);
22
28
  overflow: hidden;
23
29
  transition: width var(--motion-duration-slow) var(--motion-ease-emphasized);
24
30
  }
@@ -358,6 +364,46 @@
358
364
  white-space: nowrap;
359
365
  }
360
366
 
367
+ /* A sub-item with children opens the side panel, and says so with a
368
+ trailing chevron; a badge sits before it on the same right edge. */
369
+ .ds-app-sidebar__sub-label {
370
+ flex: 1;
371
+ min-width: 0;
372
+ overflow: hidden;
373
+ text-overflow: ellipsis;
374
+ }
375
+
376
+ .ds-app-sidebar__sub-btn .ds-app-sidebar__btn-badge {
377
+ opacity: 1;
378
+ flex-shrink: 0;
379
+ }
380
+
381
+ /* On a filled row the pill steps back to the page ground, or it would
382
+ share the row's fill and dissolve into it. */
383
+ .ds-app-sidebar__btn--active .ds-app-sidebar__btn-badge,
384
+ .ds-app-sidebar__btn:hover .ds-app-sidebar__btn-badge,
385
+ .ds-app-sidebar__sub-btn--active .ds-app-sidebar__btn-badge,
386
+ .ds-app-sidebar__sub-btn:hover .ds-app-sidebar__btn-badge {
387
+ background-color: var(--color-bg-page-primary);
388
+ }
389
+
390
+ .ds-app-sidebar__sub-chevron {
391
+ --icon-size: var(--icon-size-500);
392
+ flex-shrink: 0;
393
+ }
394
+
395
+ .ds-app-sidebar .ds-app-sidebar__sub-chevron {
396
+ color: var(--color-icon-secondary);
397
+ }
398
+
399
+ /* The nav sections share one wrapper so the drawer's drill-in can swap
400
+ them for the panel's level as a unit. */
401
+ .ds-app-sidebar__sections {
402
+ display: flex;
403
+ flex-direction: column;
404
+ gap: var(--gap-1000);
405
+ }
406
+
361
407
  /* ============================================
362
408
  CONSUMER SLOTS + BOTTOM WRAPPER
363
409
  Slots keep their height in both states so the
@@ -484,6 +530,193 @@
484
530
  --icon-size: var(--icon-size-600);
485
531
  }
486
532
 
533
+ /* ============================================
534
+ SIDE PANEL — the SidebarPanel fixed beside the
535
+ rail. It tracks the rail's width through the
536
+ same slow emphasized glide, and slides a step
537
+ out from under it on open. Hidden, it stays
538
+ mounted (inert) so the slide can run both ways.
539
+ ============================================ */
540
+ .ds-app-sidebar__panel {
541
+ position: fixed;
542
+ top: 0;
543
+ left: 64px;
544
+ /* One step under the rail, so the slide starts from beneath it. */
545
+ z-index: 99;
546
+ height: 100vh;
547
+ border-left: var(--border-025) solid var(--color-bg-container-border);
548
+ border-right: var(--border-025) solid var(--color-bg-container-border);
549
+ opacity: 0;
550
+ transform: translateX(calc(var(--padding-300) * -1));
551
+ visibility: hidden;
552
+ pointer-events: none;
553
+ /* Visibility waits out the fade on the way out, then flips; on the way
554
+ in it flips first (the --visible rule resets the delay). */
555
+ transition:
556
+ left var(--motion-duration-slow) var(--motion-ease-emphasized),
557
+ opacity var(--motion-duration-base) var(--motion-ease-standard),
558
+ transform var(--motion-duration-slow) var(--motion-ease-emphasized),
559
+ visibility 0s linear var(--motion-duration-base);
560
+ }
561
+
562
+ .ds-app-sidebar__panel--visible {
563
+ opacity: 1;
564
+ transform: none;
565
+ visibility: visible;
566
+ pointer-events: auto;
567
+ transition:
568
+ left var(--motion-duration-slow) var(--motion-ease-emphasized),
569
+ opacity var(--motion-duration-base) var(--motion-ease-standard),
570
+ transform var(--motion-duration-slow) var(--motion-ease-emphasized),
571
+ visibility 0s linear 0s;
572
+ }
573
+
574
+ .ds-app-sidebar__panel--panel-mode {
575
+ left: 80px;
576
+ }
577
+
578
+ .ds-app-sidebar__panel--beside-expanded {
579
+ left: 280px;
580
+ }
581
+
582
+ /* Floating: a second glass card beside the first, one gap along. */
583
+ .ds-app-sidebar__panel--floating {
584
+ top: var(--ds-sidebar-float-inset, 20px);
585
+ left: calc(var(--ds-sidebar-float-inset, 20px) + 64px + var(--gap-300));
586
+ height: calc(100dvh - var(--ds-sidebar-float-inset, 20px) * 2);
587
+ background-color: var(--color-bg-glass);
588
+ border: var(--border-025) solid var(--color-bg-container-border);
589
+ border-radius: var(--radius-600);
590
+ box-shadow: var(--shadow-floating);
591
+ backdrop-filter: blur(24px);
592
+ }
593
+
594
+ .ds-app-sidebar__panel--floating.ds-app-sidebar__panel--panel-mode {
595
+ left: calc(var(--ds-sidebar-float-inset, 20px) + 80px + var(--gap-300));
596
+ }
597
+
598
+ .ds-app-sidebar__panel--floating.ds-app-sidebar__panel--beside-expanded {
599
+ left: calc(var(--ds-sidebar-float-inset, 20px) + 280px + var(--gap-300));
600
+ }
601
+
602
+ /* ============================================
603
+ PANEL MODE RAIL — labels under icons
604
+ With the second level in the panel, the
605
+ collapsed rail is the whole of level 1, so it
606
+ widens to 80px and names every destination:
607
+ a pill indicator behind the icon, the label
608
+ beneath (the navigation-rail pattern).
609
+ ============================================ */
610
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) {
611
+ width: 80px;
612
+ }
613
+
614
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__logo {
615
+ /* Centres the 24px mark in the 80px rail: (80 - 24) / 2. */
616
+ padding: 0 calc(var(--padding-500) + var(--padding-200));
617
+ }
618
+
619
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__nav {
620
+ gap: 0;
621
+ }
622
+
623
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn {
624
+ height: auto;
625
+ margin: 0 var(--padding-100);
626
+ /* Room between the content and the focus ring; the rows' spacing lives
627
+ here rather than in the nav gap, so the rhythm is unchanged. */
628
+ padding: var(--padding-100) 0;
629
+ justify-content: center;
630
+ border-radius: var(--radius-300);
631
+ overflow: visible;
632
+ }
633
+
634
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn:hover,
635
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn--active {
636
+ background-color: transparent;
637
+ }
638
+
639
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn-left {
640
+ flex-direction: column;
641
+ gap: var(--gap-100);
642
+ width: 100%;
643
+ }
644
+
645
+ /* The trailing chevron and count pill are faded out on any collapsed
646
+ rail, but faded still takes width: on this centred column it pushed
647
+ the icon and label off centre. Here they leave the layout outright. */
648
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn-chevron,
649
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn-badge {
650
+ display: none;
651
+ }
652
+
653
+ /* The indicator: a 56 x 32 pill behind the icon carries hover and the
654
+ selection, so the label stays legible on the page ground. */
655
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn-icon {
656
+ display: flex;
657
+ align-items: center;
658
+ justify-content: center;
659
+ width: 56px;
660
+ height: 32px;
661
+ border-radius: var(--radius-pill);
662
+ transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
663
+ }
664
+
665
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn:hover .ds-app-sidebar__btn-icon,
666
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn--active .ds-app-sidebar__btn-icon {
667
+ background-color: var(--color-action-passive-bg-hover);
668
+ }
669
+
670
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn-label {
671
+ opacity: 1;
672
+ max-width: 100%;
673
+ font-family: var(--font-caption-family);
674
+ font-size: var(--font-caption-size);
675
+ font-weight: var(--font-caption-weight);
676
+ line-height: var(--font-caption-line-height);
677
+ letter-spacing: var(--font-caption-letter-spacing);
678
+ text-align: center;
679
+ text-overflow: ellipsis;
680
+ }
681
+
682
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__btn--active .ds-app-sidebar__btn-label {
683
+ font-weight: var(--font-paragraph-sm-emphasis-weight);
684
+ }
685
+
686
+ .ds-app-sidebar--panel-mode:not(.ds-app-sidebar--expanded) .ds-app-sidebar__profile {
687
+ /* Centres the 40px avatar in the 80px rail. */
688
+ padding: 0 var(--padding-500);
689
+ }
690
+
691
+ .ds-app-sidebar__btn:focus-visible,
692
+ .ds-app-sidebar__sub-btn:focus-visible {
693
+ outline: 2px solid var(--color-action-primary-bg);
694
+ outline-offset: -2px;
695
+ }
696
+
697
+ /* ============================================
698
+ DRAWER DRILL-IN — the panel's level as a
699
+ second screen inside the mobile drawer
700
+ ============================================ */
701
+ .ds-app-sidebar__drill {
702
+ width: auto;
703
+ height: auto;
704
+ padding: 0;
705
+ background: transparent;
706
+ animation: ds-app-sidebar-drill-in var(--motion-duration-slow) var(--motion-ease-emphasized);
707
+ }
708
+
709
+ @keyframes ds-app-sidebar-drill-in {
710
+ from {
711
+ opacity: 0;
712
+ transform: translateX(var(--padding-1000));
713
+ }
714
+ to {
715
+ opacity: 1;
716
+ transform: none;
717
+ }
718
+ }
719
+
487
720
  /* ============================================
488
721
  RESPONSIVE — the mobile drawer
489
722
  Below the mobile breakpoint (768px — design.md's Breakpoints section
@@ -512,6 +745,10 @@
512
745
  visibility: hidden;
513
746
  }
514
747
 
748
+ .ds-app-sidebar__panel {
749
+ display: none;
750
+ }
751
+
515
752
  .ds-app-sidebar__mobile-trigger {
516
753
  position: fixed;
517
754
  /* One padding step in from the corner, so hosts whose mobile
@@ -6,8 +6,19 @@ export interface AppSidebarSubItem {
6
6
  label: string;
7
7
  /** Click handler — also fires on a link sub-item, so a consumer can route client-side */
8
8
  onClick?: () => void;
9
- /** Renders the sub-item as a real link to this URL instead of a button */
9
+ /** Renders the sub-item as a real link to this URL instead of a button. Ignored when the sub-item has children, whose row opens them */
10
10
  href?: string;
11
+ /** Trailing count pill, e.g. unread items */
12
+ badge?: string | number;
13
+ /** Group heading this entry sits under when it is listed in the panel (see `subNav`); ignored in the accordion */
14
+ group?: string;
15
+ /**
16
+ * The next level down. With `subNav="accordion"` a sub-item's children are
17
+ * level 3 and open in the side panel; with `subNav="panel"` they are the
18
+ * panel's own accordion. Navigation stops at three levels, so deeper
19
+ * children are not rendered.
20
+ */
21
+ children?: AppSidebarSubItem[];
11
22
  }
12
23
  export interface AppSidebarItem {
13
24
  /** Unique key for this item */
@@ -22,7 +33,7 @@ export interface AppSidebarItem {
22
33
  href?: string;
23
34
  /** Trailing count pill, e.g. unread items; hidden while the rail is collapsed */
24
35
  badge?: string | number;
25
- /** Sub-items — turns this into an accordion */
36
+ /** Sub-items: an accordion under the row, or the side panel's contents when `subNav="panel"` */
26
37
  children?: AppSidebarSubItem[];
27
38
  }
28
39
  export interface AppSidebarSection {
@@ -48,6 +59,23 @@ export interface AppSidebarProps {
48
59
  activeKey?: string;
49
60
  /** Key of the currently active sub-item */
50
61
  activeSubKey?: string;
62
+ /** Key of the currently active third-level item, listed in the side panel */
63
+ activeTertiaryKey?: string;
64
+ /**
65
+ * Where an item's sub-items show. `accordion` (the default) opens them under
66
+ * the row, and a sub-item's own children open in a side panel as level 3.
67
+ * `panel` skips the accordion: a top-level item opens its sub-items straight
68
+ * into the side panel, with their children as the panel's accordion, and the
69
+ * collapsed rail shows each label under its icon. On small screens both
70
+ * modes drill in inside the drawer instead.
71
+ */
72
+ subNav?: 'accordion' | 'panel';
73
+ /** Whether the side panel starts open when there is one to show */
74
+ defaultPanelOpen?: boolean;
75
+ /** Controlled open state of the side panel */
76
+ panelOpen?: boolean;
77
+ /** Called when the side panel opens or collapses */
78
+ onPanelOpenChange?: (open: boolean) => void;
51
79
  /** Whether sidebar starts expanded */
52
80
  defaultExpanded?: boolean;
53
81
  /** Controlled expanded state */
@@ -86,5 +114,6 @@ export interface AppSidebarProps {
86
114
  * **Collapsed** (64 px): icon-only buttons, logo mark, avatar.
87
115
  * **Expanded** (280 px): labels, category headings, accordion
88
116
  * sub-items with tree-line connectors, and a profile section.
117
+ * A third level opens in a `SidebarPanel` beside the rail (see `subNav`).
89
118
  */
90
- export declare const AppSidebar: ({ sections, profile, activeKey, activeSubKey, defaultExpanded, expanded: controlledExpanded, onExpandedChange, onProfileMore, floating, topSlot, footerSlot, className, logo, logoText, showMobileTrigger, }: AppSidebarProps) => React.JSX.Element;
119
+ export declare const AppSidebar: ({ sections, profile, activeKey, activeSubKey, activeTertiaryKey, subNav, defaultPanelOpen, panelOpen: controlledPanelOpen, onPanelOpenChange, defaultExpanded, expanded: controlledExpanded, onExpandedChange, onProfileMore, floating, topSlot, footerSlot, className, logo, logoText, showMobileTrigger, }: AppSidebarProps) => React.JSX.Element;