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.
- package/LICENSE +1 -1
- package/README.md +11 -3
- package/components/AppLayout/AppLayout.css +13 -3
- package/components/AppLayout/AppLayout.d.ts +5 -1
- package/components/AppLayout/AppLayout.js +4 -0
- package/components/AppSidebar/AppSidebar.css +237 -0
- package/components/AppSidebar/AppSidebar.d.ts +32 -3
- package/components/AppSidebar/AppSidebar.js +187 -16
- package/components/BottomNav/BottomNav.css +417 -0
- package/components/BottomNav/BottomNav.d.ts +73 -0
- package/components/BottomNav/BottomNav.js +100 -0
- package/components/Chart/AreaChart.js +67 -56
- package/components/Chart/BarChart.js +67 -56
- package/components/Chart/ComboChart.js +93 -82
- package/components/Chart/LineChart.js +59 -48
- package/components/Chart/PieChart.js +56 -45
- package/components/Chart/RadarChart.js +60 -49
- package/components/Chart/RadialChart.js +70 -59
- package/components/Chart/ScatterChart.js +61 -50
- package/components/Chart/StackedBarChart.js +64 -53
- package/components/Chart/Treemap.js +34 -23
- package/components/Nav/Nav.d.ts +11 -3
- package/components/Nav/Nav.js +3 -2
- package/components/SidebarPanel/SidebarPanel.css +291 -0
- package/components/SidebarPanel/SidebarPanel.d.ts +45 -0
- package/components/SidebarPanel/SidebarPanel.js +166 -0
- package/components/Stepper/Stepper.d.ts +3 -1
- package/components/Stepper/Stepper.js +1 -1
- package/components/TopAppBar/TopAppBar.css +464 -0
- package/components/TopAppBar/TopAppBar.d.ts +80 -0
- package/components/TopAppBar/TopAppBar.js +138 -0
- package/components/registry.json +25 -1
- package/components/registry.json.d.ts +25 -1
- package/components/registry.json.js +1 -1
- package/index.d.ts +3 -0
- package/index.js +6 -0
- package/package.json +5 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
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 -->
|
|
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
|
-
|
|
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
|
|
26
|
-
|
|
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
|
|
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;
|