@beydesign/storybook 0.2.29 → 0.3.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/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/stories/Form/Dropdown.js +38 -31
- package/dist/stories/Form/FileUpload/FileUpload.js +26 -16
- package/dist/stories/Form/FileUpload/FileUploading.js +35 -25
- package/dist/stories/Form/FileUpload/UploadedFile.js +15 -4
- package/dist/stories/Form/FileUpload/UploadedFile.stories.js +21 -26
- package/dist/stories/Form/types.d.ts +5 -9
- package/dist/stories/{Drawer → Navigation/Drawer}/Drawer.d.ts +4 -0
- package/dist/stories/Navigation/Drawer/Drawer.js +81 -0
- package/dist/stories/{Drawer → Navigation/Drawer}/Drawer.stories.js +1 -1
- package/dist/stories/Navigation/Drawer/DrawerBody.d.ts +9 -0
- package/dist/stories/Navigation/Drawer/DrawerBody.js +73 -0
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCard.js +3 -3
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCard.stories.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCardSkeleton.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCardSkeleton.stories.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerNavItem.d.ts +1 -1
- package/dist/stories/Navigation/Drawer/DrawerNavItem.js +22 -0
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerNavItem.stories.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfile.js +3 -3
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfile.stories.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfileSkeleton.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfileSkeleton.stories.js +1 -1
- package/dist/stories/{Drawer → Navigation/Drawer}/index.d.ts +1 -0
- package/dist/stories/{Drawer → Navigation/Drawer}/index.js +1 -0
- package/dist/stories/{Drawer → Navigation/Drawer}/types.d.ts +44 -34
- package/dist/stories/Navigation/Drawer/types.js +7 -0
- package/dist/stories/Navigation/MobileNav.d.ts +15 -0
- package/dist/stories/Navigation/MobileNav.js +97 -0
- package/dist/stories/Navigation/MobileNav.stories.d.ts +25 -0
- package/dist/stories/Navigation/MobileNav.stories.js +65 -0
- package/dist/stories/Navigation/MobileNavBar.js +3 -13
- package/dist/stories/Navigation/MobileNavBar.stories.js +5 -18
- package/dist/stories/Navigation/SettingsPage.stories.d.ts +19 -0
- package/dist/stories/Navigation/SettingsPage.stories.js +75 -0
- package/dist/stories/Navigation/SubNav/SubNav.d.ts +14 -0
- package/dist/stories/Navigation/SubNav/SubNav.js +16 -0
- package/dist/stories/{Settings/SettingsNav.stories.d.ts → Navigation/SubNav/SubNav.stories.d.ts} +3 -3
- package/dist/stories/{Settings/SettingsNav.stories.js → Navigation/SubNav/SubNav.stories.js} +3 -3
- package/dist/stories/Navigation/SubNav/SubNavBody.d.ts +10 -0
- package/dist/stories/Navigation/SubNav/SubNavBody.js +91 -0
- package/dist/stories/Navigation/SubNav/SubNavItem.d.ts +10 -0
- package/dist/stories/Navigation/SubNav/SubNavItem.js +12 -0
- package/dist/stories/Navigation/SubNav/index.d.ts +4 -0
- package/dist/stories/Navigation/SubNav/index.js +4 -0
- package/dist/stories/Navigation/SubNav/types.d.ts +54 -0
- package/dist/stories/Navigation/index.d.ts +3 -0
- package/dist/stories/Navigation/index.js +3 -0
- package/dist/stories/Navigation/internal/NavPanel.d.ts +21 -0
- package/dist/stories/Navigation/internal/NavPanel.js +45 -0
- package/dist/stories/Navigation/internal/NavRow.d.ts +45 -0
- package/dist/stories/Navigation/internal/NavRow.js +79 -0
- package/dist/stories/Navigation/internal/index.d.ts +11 -0
- package/dist/stories/Navigation/internal/index.js +11 -0
- package/dist/stories/Navigation/internal/types.d.ts +71 -0
- package/dist/stories/Navigation/internal/types.js +30 -0
- package/dist/stories/Navigation/navigation.fixtures.d.ts +22 -0
- package/dist/stories/Navigation/navigation.fixtures.js +64 -0
- package/dist/stories/Navigation/types.d.ts +24 -1
- package/dist/stories/UI/Menu.js +3 -1
- package/dist/stories/UI/types.d.ts +2 -0
- package/package.json +1 -1
- package/dist/stories/Drawer/Drawer.js +0 -163
- package/dist/stories/Drawer/DrawerNavItem.js +0 -87
- package/dist/stories/Drawer/types.js +0 -29
- package/dist/stories/Settings/SettingsNav.d.ts +0 -10
- package/dist/stories/Settings/SettingsNav.js +0 -97
- package/dist/stories/Settings/SettingsNavItem.d.ts +0 -9
- package/dist/stories/Settings/SettingsNavItem.js +0 -75
- package/dist/stories/Settings/SettingsPage.stories.d.ts +0 -11
- package/dist/stories/Settings/SettingsPage.stories.js +0 -93
- package/dist/stories/Settings/index.d.ts +0 -3
- package/dist/stories/Settings/index.js +0 -3
- package/dist/stories/Settings/types.d.ts +0 -68
- /package/dist/stories/{Drawer → Navigation/Drawer}/Drawer.stories.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCard.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCard.stories.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCardSkeleton.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerCreditsCardSkeleton.stories.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerIcons.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerIcons.js +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerNavItem.stories.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfile.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfile.stories.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfileSkeleton.d.ts +0 -0
- /package/dist/stories/{Drawer → Navigation/Drawer}/DrawerProfileSkeleton.stories.d.ts +0 -0
- /package/dist/stories/{Settings → Navigation/SubNav}/types.js +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
3
|
import { DrawerSize } from './types';
|
|
4
|
-
import { Typography, TypographySize, TypographyWeight } from '
|
|
5
|
-
import { Popover, ProgressIndicator, ProgressIndicatorMode } from '
|
|
6
|
-
import { getIconComponent } from '
|
|
4
|
+
import { Typography, TypographySize, TypographyWeight } from '../../Typography';
|
|
5
|
+
import { Popover, ProgressIndicator, ProgressIndicatorMode } from '../../UI';
|
|
6
|
+
import { getIconComponent } from '../../../utils';
|
|
7
7
|
import { GemIcon } from './DrawerIcons';
|
|
8
8
|
const DEFAULT_INFO_LINES = [
|
|
9
9
|
'Managed Agents 1 Min = 100 Credits',
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { DrawerCreditsCard } from './DrawerCreditsCard';
|
|
3
3
|
import { DrawerSize } from './types';
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Components/
|
|
5
|
+
title: 'Design System/Components/Navigation/DrawerCreditsCard',
|
|
6
6
|
component: DrawerCreditsCard,
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'centered',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
|
-
import { SkeletonLoader } from '
|
|
3
|
+
import { SkeletonLoader } from '../../UI';
|
|
4
4
|
import { DrawerSize } from './types';
|
|
5
5
|
/** Mirrors {@link DrawerCreditsCard}'s Card so the skeleton snaps in place. */
|
|
6
6
|
const Card = styled.div `
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { DrawerCreditsCardSkeleton } from './DrawerCreditsCardSkeleton';
|
|
3
3
|
import { DrawerSize } from './types';
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Components/
|
|
5
|
+
title: 'Design System/Components/Navigation/DrawerCreditsCardSkeleton',
|
|
6
6
|
component: DrawerCreditsCardSkeleton,
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'centered',
|
|
@@ -3,6 +3,6 @@ import { DrawerNavItemProps } from './types';
|
|
|
3
3
|
/**
|
|
4
4
|
* A single navigation row for the {@link Drawer}. Supports active / inactive /
|
|
5
5
|
* hover / disabled states, first / secondary hierarchy and expanded / collapsed
|
|
6
|
-
* sizes
|
|
6
|
+
* sizes — a top-level configuration of the shared {@link NavRow}.
|
|
7
7
|
*/
|
|
8
8
|
export declare const DrawerNavItem: React.FC<DrawerNavItemProps>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { DrawerNavItemState, DrawerNavItemHierarchy, DrawerSize, } from './types';
|
|
4
|
+
import { NavRow } from '../internal';
|
|
5
|
+
import { TypographySize, TypographyWeight } from '../../Typography';
|
|
6
|
+
import { getIconComponent } from '../../../utils';
|
|
7
|
+
const FIRST_PADDING = 'var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px)';
|
|
8
|
+
const SECONDARY_PADDING = 'var(--spacing-tokens-size-in-px-spacing-spacing-xs, 4px) var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px)';
|
|
9
|
+
const Caret = styled.span `
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
color: inherit;
|
|
13
|
+
`;
|
|
14
|
+
/**
|
|
15
|
+
* A single navigation row for the {@link Drawer}. Supports active / inactive /
|
|
16
|
+
* hover / disabled states, first / secondary hierarchy and expanded / collapsed
|
|
17
|
+
* sizes — a top-level configuration of the shared {@link NavRow}.
|
|
18
|
+
*/
|
|
19
|
+
export const DrawerNavItem = ({ text, icon, state = DrawerNavItemState.Inactive, size = DrawerSize.Expanded, hierarchy = DrawerNavItemHierarchy.First, showBadge = false, badgeText = 'Coming Soon', showSubNavCaret = false, onClick, className, style, testId, }) => {
|
|
20
|
+
const isSecondary = hierarchy === DrawerNavItemHierarchy.Secondary;
|
|
21
|
+
return (_jsx(NavRow, { text: text, icon: icon, state: state, collapsed: size === DrawerSize.Collapsed, iconSize: 20, typographySize: isSecondary ? TypographySize.TextXS : TypographySize.TextS, typographyWeight: isSecondary ? TypographyWeight.Medium : TypographyWeight.SemiBold, padding: isSecondary ? SECONDARY_PADDING : FIRST_PADDING, showBadge: showBadge, badgeText: badgeText, trailing: showSubNavCaret ? (_jsx(Caret, { children: getIconComponent('CaretRight', { size: 16 }) })) : undefined, onClick: onClick, className: className, style: style, testId: testId }));
|
|
22
|
+
};
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { DrawerNavItem } from './DrawerNavItem';
|
|
3
3
|
import { DrawerNavItemState, DrawerNavItemHierarchy, DrawerSize, } from './types';
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Components/
|
|
5
|
+
title: 'Design System/Components/Navigation/DrawerNavItem',
|
|
6
6
|
component: DrawerNavItem,
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'centered',
|
|
@@ -2,9 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import styled from '@emotion/styled';
|
|
4
4
|
import { DrawerSize } from './types';
|
|
5
|
-
import { Avatar, AvatarSize, AvatarStyle } from '
|
|
6
|
-
import { Typography, TypographySize, TypographyWeight } from '
|
|
7
|
-
import { getIconComponent } from '
|
|
5
|
+
import { Avatar, AvatarSize, AvatarStyle } from '../../UI';
|
|
6
|
+
import { Typography, TypographySize, TypographyWeight } from '../../Typography';
|
|
7
|
+
import { getIconComponent } from '../../../utils';
|
|
8
8
|
const Container = styled.div `
|
|
9
9
|
display: flex;
|
|
10
10
|
flex-direction: column;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { DrawerProfile } from './DrawerProfile';
|
|
3
3
|
import { DrawerSize } from './types';
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Components/
|
|
5
|
+
title: 'Design System/Components/Navigation/DrawerProfile',
|
|
6
6
|
component: DrawerProfile,
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'centered',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
|
-
import { SkeletonLoader } from '
|
|
3
|
+
import { SkeletonLoader } from '../../UI';
|
|
4
4
|
import { DrawerSize } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Mirrors {@link DrawerProfile}'s clickable Row so the skeleton snaps in place:
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { DrawerProfileSkeleton } from './DrawerProfileSkeleton';
|
|
3
3
|
import { DrawerSize } from './types';
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'Design System/Components/
|
|
5
|
+
title: 'Design System/Components/Navigation/DrawerProfileSkeleton',
|
|
6
6
|
component: DrawerProfileSkeleton,
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'centered',
|
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
|
-
import { IconName } from '
|
|
2
|
+
import { IconName } from '../../../utils';
|
|
3
|
+
import type { NavItemHierarchy, NavItemState, NavPanelSize, SubNavConfig } from '../internal/types';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
+
* The canonical declarations live in `../internal/types` so that the shared
|
|
6
|
+
* `NavRow` and `NavPanel` primitives can consume them without depending on the
|
|
7
|
+
* Drawer. They are re-exported here under their established public names.
|
|
8
|
+
* (`SubNavConfig` and friends are re-exported from `../SubNav`, their own home.)
|
|
5
9
|
*/
|
|
6
|
-
export
|
|
7
|
-
Expanded = "Expanded",
|
|
8
|
-
Collapsed = "Collapsed"
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Visual state of a single navigation item.
|
|
12
|
-
* `Hover` is mostly useful for documentation/Storybook — at runtime an
|
|
13
|
-
* `Inactive` item also picks up the hover styling on real pointer hover.
|
|
14
|
-
*/
|
|
15
|
-
export declare enum DrawerNavItemState {
|
|
16
|
-
Active = "Active",
|
|
17
|
-
Inactive = "Inactive",
|
|
18
|
-
Hover = "Hover",
|
|
19
|
-
Disabled = "Disabled"
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Hierarchy of a navigation item. `First` is a top-level entry (36px row),
|
|
23
|
-
* `Secondary` is a nested sub-item (28px row, lighter weight).
|
|
24
|
-
*/
|
|
25
|
-
export declare enum DrawerNavItemHierarchy {
|
|
26
|
-
First = "First",
|
|
27
|
-
Secondary = "Secondary"
|
|
28
|
-
}
|
|
10
|
+
export { NavItemState as DrawerNavItemState, NavPanelSize as DrawerSize, NavItemHierarchy as DrawerNavItemHierarchy, } from '../internal/types';
|
|
29
11
|
/**
|
|
30
12
|
* Props for the standalone {@link DrawerNavItem} component.
|
|
31
13
|
*/
|
|
@@ -35,15 +17,20 @@ export interface DrawerNavItemProps {
|
|
|
35
17
|
/** Phosphor icon name rendered to the left of the label. */
|
|
36
18
|
icon: IconName;
|
|
37
19
|
/** Visual state of the item. */
|
|
38
|
-
state?:
|
|
20
|
+
state?: NavItemState;
|
|
39
21
|
/** Expanded (icon + label) or Collapsed (icon only). */
|
|
40
|
-
size?:
|
|
22
|
+
size?: NavPanelSize;
|
|
41
23
|
/** Top-level (`First`) or nested (`Secondary`) item. */
|
|
42
|
-
hierarchy?:
|
|
24
|
+
hierarchy?: NavItemHierarchy;
|
|
43
25
|
/** Show a trailing badge (e.g. "Coming Soon"). Hidden when collapsed. */
|
|
44
26
|
showBadge?: boolean;
|
|
45
27
|
/** Text for the trailing badge. */
|
|
46
28
|
badgeText?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Render a trailing caret marking this item as opening a sub-navigation.
|
|
31
|
+
* Hidden when collapsed.
|
|
32
|
+
*/
|
|
33
|
+
showSubNavCaret?: boolean;
|
|
47
34
|
/** Click handler. Not fired when the item is disabled. */
|
|
48
35
|
onClick?: () => void;
|
|
49
36
|
className?: string;
|
|
@@ -56,7 +43,7 @@ export interface DrawerNavItemProps {
|
|
|
56
43
|
*/
|
|
57
44
|
export interface DrawerCreditsCardProps {
|
|
58
45
|
/** Expanded (full card) or Collapsed (icon only, details in a popover). */
|
|
59
|
-
size?:
|
|
46
|
+
size?: NavPanelSize;
|
|
60
47
|
/** Credits consumed so far. */
|
|
61
48
|
usedCredits?: number;
|
|
62
49
|
/** Total credits available in the plan. */
|
|
@@ -82,7 +69,7 @@ export interface DrawerCreditsCardProps {
|
|
|
82
69
|
*/
|
|
83
70
|
export interface DrawerCreditsCardSkeletonProps {
|
|
84
71
|
/** Expanded (full card) or Collapsed (icon-only box). */
|
|
85
|
-
size?:
|
|
72
|
+
size?: NavPanelSize;
|
|
86
73
|
className?: string;
|
|
87
74
|
style?: CSSProperties;
|
|
88
75
|
testId?: string;
|
|
@@ -103,7 +90,7 @@ export interface DrawerProfileMenuItem {
|
|
|
103
90
|
*/
|
|
104
91
|
export interface DrawerProfileProps {
|
|
105
92
|
/** Expanded (avatar + text) or Collapsed (avatar only). */
|
|
106
|
-
size?:
|
|
93
|
+
size?: NavPanelSize;
|
|
107
94
|
/** Display name. */
|
|
108
95
|
name: string;
|
|
109
96
|
/** Secondary line, usually the email. */
|
|
@@ -129,7 +116,7 @@ export interface DrawerProfileProps {
|
|
|
129
116
|
*/
|
|
130
117
|
export interface DrawerProfileSkeletonProps {
|
|
131
118
|
/** Expanded (avatar + text lines) or Collapsed (avatar circle only). */
|
|
132
|
-
size?:
|
|
119
|
+
size?: NavPanelSize;
|
|
133
120
|
className?: string;
|
|
134
121
|
style?: CSSProperties;
|
|
135
122
|
testId?: string;
|
|
@@ -142,15 +129,24 @@ export interface DrawerNavItemConfig {
|
|
|
142
129
|
key?: string;
|
|
143
130
|
text: string;
|
|
144
131
|
icon: IconName;
|
|
145
|
-
hierarchy?:
|
|
132
|
+
hierarchy?: NavItemHierarchy;
|
|
146
133
|
/** Force a state. When omitted it is derived from `activeKey` / `disabled`. */
|
|
147
|
-
state?:
|
|
134
|
+
state?: NavItemState;
|
|
148
135
|
disabled?: boolean;
|
|
149
136
|
showBadge?: boolean;
|
|
150
137
|
badgeText?: string;
|
|
151
138
|
/** When set, clicking navigates to this URL. */
|
|
152
139
|
link?: string;
|
|
153
140
|
onClick?: () => void;
|
|
141
|
+
/**
|
|
142
|
+
* A secondary navigation this item drills into (e.g. the Settings sub-nav).
|
|
143
|
+
*
|
|
144
|
+
* On desktop the item navigates as usual and the sub-nav is rendered as its
|
|
145
|
+
* own panel beside the Drawer (`SubNav`). Where there is only room for
|
|
146
|
+
* one panel — `MobileNav` — the item instead grows a trailing caret and
|
|
147
|
+
* pushes this config as a second pane.
|
|
148
|
+
*/
|
|
149
|
+
subNav?: SubNavConfig;
|
|
154
150
|
}
|
|
155
151
|
/**
|
|
156
152
|
* Props for the composed {@link Drawer} component.
|
|
@@ -186,3 +182,17 @@ export interface DrawerProps {
|
|
|
186
182
|
style?: CSSProperties;
|
|
187
183
|
testId?: string;
|
|
188
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Props for the {@link DrawerBody} — the Drawer's content without any panel
|
|
187
|
+
* chrome, so it can be dropped into the `MobileNav` overlay as its root pane.
|
|
188
|
+
*/
|
|
189
|
+
export interface DrawerBodyProps extends Pick<DrawerProps, 'navItems' | 'activeKey' | 'credits' | 'creditsLoading' | 'profile' | 'profileLoading' | 'logo'> {
|
|
190
|
+
/** Expanded (icon + label) or Collapsed (icon only). */
|
|
191
|
+
size?: NavPanelSize;
|
|
192
|
+
/**
|
|
193
|
+
* When provided, items carrying a `subNav` render a trailing caret and call
|
|
194
|
+
* this instead of navigating. The desktop `Drawer` omits it, so those items
|
|
195
|
+
* behave like any other nav entry.
|
|
196
|
+
*/
|
|
197
|
+
onSubNavOpen?: (item: DrawerNavItemConfig) => void;
|
|
198
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical declarations live in `../internal/types` so that the shared
|
|
3
|
+
* `NavRow` and `NavPanel` primitives can consume them without depending on the
|
|
4
|
+
* Drawer. They are re-exported here under their established public names.
|
|
5
|
+
* (`SubNavConfig` and friends are re-exported from `../SubNav`, their own home.)
|
|
6
|
+
*/
|
|
7
|
+
export { NavItemState as DrawerNavItemState, NavPanelSize as DrawerSize, NavItemHierarchy as DrawerNavItemHierarchy, } from '../internal/types';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MobileNavProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* The single navigation panel for mobile, where there is no room for the
|
|
5
|
+
* `Drawer` and a settings sub-nav side by side. It slides in over the page and
|
|
6
|
+
* holds both as pushable panes: the root pane is the very same {@link DrawerBody}
|
|
7
|
+
* the desktop `Drawer` renders, and any nav item carrying a `subNav` grows a
|
|
8
|
+
* trailing caret that pushes that config as a {@link SubNavBody} pane with
|
|
9
|
+
* a back button. Nothing is duplicated — only the chrome around the bodies
|
|
10
|
+
* changes between desktop and mobile.
|
|
11
|
+
*
|
|
12
|
+
* `MobileNavBar` renders this behind its hamburger; use it directly if the app
|
|
13
|
+
* already has its own mobile header.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MobileNav: React.FC<MobileNavProps>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { Drawer as MuiDrawer } from '@mui/material';
|
|
4
|
+
import styled from '@emotion/styled';
|
|
5
|
+
import { keyframes } from '@emotion/react';
|
|
6
|
+
import { DrawerBody } from './Drawer';
|
|
7
|
+
import { SubNavBody } from './SubNav';
|
|
8
|
+
import { NavPanel } from './internal';
|
|
9
|
+
const DEFAULT_WIDTH = '315px';
|
|
10
|
+
const slideForward = keyframes `
|
|
11
|
+
from { transform: translateX(16px); opacity: 0; }
|
|
12
|
+
to { transform: translateX(0); opacity: 1; }
|
|
13
|
+
`;
|
|
14
|
+
const slideBack = keyframes `
|
|
15
|
+
from { transform: translateX(-16px); opacity: 0; }
|
|
16
|
+
to { transform: translateX(0); opacity: 1; }
|
|
17
|
+
`;
|
|
18
|
+
/**
|
|
19
|
+
* Hosts one pane at a time, growing to fill the panel so the body's own flex
|
|
20
|
+
* chain (logo header, then a nav that pushes the footer down) still works.
|
|
21
|
+
*
|
|
22
|
+
* Keep the default `min-height: auto`: on a short viewport the pane must refuse
|
|
23
|
+
* to shrink below its content, otherwise the panel scrolls to a height that
|
|
24
|
+
* excludes the profile footer and clips it.
|
|
25
|
+
*/
|
|
26
|
+
const Pane = styled.div `
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
flex: 1 0 auto;
|
|
30
|
+
animation: ${({ $forward }) => ($forward ? slideForward : slideBack)} 0.25s
|
|
31
|
+
ease-out;
|
|
32
|
+
|
|
33
|
+
@media (prefers-reduced-motion: reduce) {
|
|
34
|
+
animation: none;
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
/**
|
|
38
|
+
* The single navigation panel for mobile, where there is no room for the
|
|
39
|
+
* `Drawer` and a settings sub-nav side by side. It slides in over the page and
|
|
40
|
+
* holds both as pushable panes: the root pane is the very same {@link DrawerBody}
|
|
41
|
+
* the desktop `Drawer` renders, and any nav item carrying a `subNav` grows a
|
|
42
|
+
* trailing caret that pushes that config as a {@link SubNavBody} pane with
|
|
43
|
+
* a back button. Nothing is duplicated — only the chrome around the bodies
|
|
44
|
+
* changes between desktop and mobile.
|
|
45
|
+
*
|
|
46
|
+
* `MobileNavBar` renders this behind its hamburger; use it directly if the app
|
|
47
|
+
* already has its own mobile header.
|
|
48
|
+
*/
|
|
49
|
+
export const MobileNav = ({ open, onOpenChange, navItems, activeKey, credits, creditsLoading, profile, profileLoading, logo, width = DEFAULT_WIDTH, className, style, testId, }) => {
|
|
50
|
+
const [subNav, setSubNav] = useState(null);
|
|
51
|
+
const close = useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
52
|
+
/** Navigating away should dismiss the overlay, whichever pane it happened in. */
|
|
53
|
+
const closingNavItems = useMemo(() => navItems.map((item) => ({
|
|
54
|
+
...item,
|
|
55
|
+
onClick: () => {
|
|
56
|
+
item.onClick?.();
|
|
57
|
+
close();
|
|
58
|
+
},
|
|
59
|
+
})), [navItems, close]);
|
|
60
|
+
const closingSubNav = useMemo(() => {
|
|
61
|
+
if (!subNav)
|
|
62
|
+
return null;
|
|
63
|
+
return {
|
|
64
|
+
...subNav,
|
|
65
|
+
sections: subNav.sections.map((section) => ({
|
|
66
|
+
...section,
|
|
67
|
+
items: section.items.map((item) => ({
|
|
68
|
+
...item,
|
|
69
|
+
onClick: () => {
|
|
70
|
+
item.onClick?.();
|
|
71
|
+
close();
|
|
72
|
+
},
|
|
73
|
+
})),
|
|
74
|
+
})),
|
|
75
|
+
};
|
|
76
|
+
}, [subNav, close]);
|
|
77
|
+
const handleSubNavOpen = (item) => {
|
|
78
|
+
if (item.subNav)
|
|
79
|
+
setSubNav(item.subNav);
|
|
80
|
+
};
|
|
81
|
+
return (_jsx(MuiDrawer, { anchor: "left", open: open, onClose: close, className: className,
|
|
82
|
+
/* Reset to the root pane only once the panel is fully out of sight. */
|
|
83
|
+
SlideProps: { onExited: () => setSubNav(null) }, PaperProps: {
|
|
84
|
+
sx: {
|
|
85
|
+
width,
|
|
86
|
+
backgroundColor: 'transparent',
|
|
87
|
+
boxShadow: 'none',
|
|
88
|
+
border: 'none',
|
|
89
|
+
overflow: 'hidden',
|
|
90
|
+
},
|
|
91
|
+
style,
|
|
92
|
+
}, sx: {
|
|
93
|
+
'& .MuiBackdrop-root': {
|
|
94
|
+
backgroundColor: 'var(--color-background-bg-overlay-2)',
|
|
95
|
+
},
|
|
96
|
+
}, "data-testid": testId, children: _jsx(NavPanel, { "$borderColor": "var(--color-border-border-divider)", children: closingSubNav ? (_jsx(Pane, { "$forward": true, children: _jsx(SubNavBody, { title: closingSubNav.title, sections: closingSubNav.sections, activeKey: closingSubNav.activeKey, onBack: () => setSubNav(null) }) }, "sub-nav")) : (_jsx(Pane, { "$forward": false, children: _jsx(DrawerBody, { navItems: closingNavItems, activeKey: activeKey, credits: credits, creditsLoading: creditsLoading, profile: profile, profileLoading: profileLoading, logo: logo, onSubNavOpen: handleSubNavOpen }) }, "root")) }) }));
|
|
97
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { MobileNav } from './MobileNav';
|
|
3
|
+
/**
|
|
4
|
+
* Drives the overlay the way an app does: a trigger button, and `open` state
|
|
5
|
+
* the component reports back through `onOpenChange`.
|
|
6
|
+
*/
|
|
7
|
+
declare const MobileNavExample: ({ navItems, activeKey, ...rest }: Partial<React.ComponentProps<typeof MobileNav>>) => import("react").JSX.Element;
|
|
8
|
+
declare const meta: Meta<typeof MobileNavExample>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof MobileNavExample>;
|
|
11
|
+
/**
|
|
12
|
+
* The root pane. "Settings" carries a `subNav`, so it renders a trailing caret
|
|
13
|
+
* and pushes instead of navigating.
|
|
14
|
+
*/
|
|
15
|
+
export declare const Default: Story;
|
|
16
|
+
/**
|
|
17
|
+
* Without a `subNav` anywhere in `navItems` there is nothing to drill into, so
|
|
18
|
+
* no item shows a caret and the overlay is a plain single-pane nav.
|
|
19
|
+
*/
|
|
20
|
+
export declare const WithoutSubNav: Story;
|
|
21
|
+
/**
|
|
22
|
+
* A sub-nav is not a settings-only idea — any item can declare one. Here the
|
|
23
|
+
* developer entry drills into a subset of the same sections.
|
|
24
|
+
*/
|
|
25
|
+
export declare const CustomSubNav: Story;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { MobileNav } from './MobileNav';
|
|
4
|
+
import { credits, drawerNavItems, profile, settingsSections, } from './navigation.fixtures';
|
|
5
|
+
import { MainButton, ButtonHierarchy, ButtonSize, ButtonDisplayMode, } from '../Buttons';
|
|
6
|
+
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
7
|
+
/**
|
|
8
|
+
* Drives the overlay the way an app does: a trigger button, and `open` state
|
|
9
|
+
* the component reports back through `onOpenChange`.
|
|
10
|
+
*/
|
|
11
|
+
const MobileNavExample = ({ navItems = drawerNavItems, activeKey = 'settings', ...rest }) => {
|
|
12
|
+
const [open, setOpen] = useState(true);
|
|
13
|
+
return (_jsxs("div", { style: {
|
|
14
|
+
height: '100vh',
|
|
15
|
+
padding: 16,
|
|
16
|
+
backgroundColor: 'var(--color-background-bg-page)',
|
|
17
|
+
}, children: [_jsx(MainButton, { text: "Open menu", displayIcon: "List", displayIconMode: ButtonDisplayMode.Default, hierarchy: ButtonHierarchy.Secondary, size: ButtonSize.sm, onClick: () => setOpen(true) }), _jsx("div", { style: { marginTop: 16 }, children: _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Regular, color: "var(--color-text-text-paragraph)", children: "Tap \"Settings\" in the panel to push the settings sub-nav, then use the back arrow to return." }) }), _jsx(MobileNav, { open: open, onOpenChange: setOpen, navItems: navItems, activeKey: activeKey, credits: credits, profile: profile, ...rest })] }));
|
|
18
|
+
};
|
|
19
|
+
const meta = {
|
|
20
|
+
title: 'Design System/Components/Navigation/MobileNav',
|
|
21
|
+
component: MobileNavExample,
|
|
22
|
+
parameters: {
|
|
23
|
+
layout: 'fullscreen',
|
|
24
|
+
viewport: { defaultViewport: 'mobile1' },
|
|
25
|
+
design: {
|
|
26
|
+
type: 'figspec',
|
|
27
|
+
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=7317-23750',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
tags: ['autodocs'],
|
|
31
|
+
};
|
|
32
|
+
export default meta;
|
|
33
|
+
/**
|
|
34
|
+
* The root pane. "Settings" carries a `subNav`, so it renders a trailing caret
|
|
35
|
+
* and pushes instead of navigating.
|
|
36
|
+
*/
|
|
37
|
+
export const Default = {};
|
|
38
|
+
/**
|
|
39
|
+
* Without a `subNav` anywhere in `navItems` there is nothing to drill into, so
|
|
40
|
+
* no item shows a caret and the overlay is a plain single-pane nav.
|
|
41
|
+
*/
|
|
42
|
+
export const WithoutSubNav = {
|
|
43
|
+
args: {
|
|
44
|
+
navItems: drawerNavItems.filter((item) => item.key !== 'settings'),
|
|
45
|
+
activeKey: 'kb',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A sub-nav is not a settings-only idea — any item can declare one. Here the
|
|
50
|
+
* developer entry drills into a subset of the same sections.
|
|
51
|
+
*/
|
|
52
|
+
export const CustomSubNav = {
|
|
53
|
+
args: {
|
|
54
|
+
activeKey: 'developers',
|
|
55
|
+
navItems: drawerNavItems.map((item) => item.key === 'developers'
|
|
56
|
+
? {
|
|
57
|
+
...item,
|
|
58
|
+
subNav: {
|
|
59
|
+
title: 'Developers',
|
|
60
|
+
sections: settingsSections.filter((section) => section.key === 'developers'),
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
: item),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import { Box
|
|
3
|
+
import { Box } from '@mui/material';
|
|
4
4
|
import { Logo } from '../UI';
|
|
5
|
-
import {
|
|
5
|
+
import { MobileNav } from './MobileNav';
|
|
6
6
|
import { getIconComponent } from '../../utils';
|
|
7
7
|
const shadowXs = 'var(--global-shadows-shadow-xs-offset-x) ' +
|
|
8
8
|
'var(--global-shadows-shadow-xs-offset-y) ' +
|
|
@@ -29,15 +29,5 @@ export const MobileNavBar = ({ onSearchClick, drawerProps, showSearch = true, lo
|
|
|
29
29
|
if (drawerProps)
|
|
30
30
|
setOpen(true);
|
|
31
31
|
};
|
|
32
|
-
|
|
33
|
-
const navItems = drawerProps?.navItems.map((item) => ({
|
|
34
|
-
...item,
|
|
35
|
-
onClick: () => {
|
|
36
|
-
item.onClick?.();
|
|
37
|
-
closeDrawer();
|
|
38
|
-
},
|
|
39
|
-
}));
|
|
40
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Box, { className: className, sx: style, boxSizing: 'border-box', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', width: '100%', height: '60px', paddingX: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', borderBottom: '1px solid var(--color-border-border-component)', bgcolor: 'var(--color-background-bg-page)', children: [_jsx(Box, { display: 'flex', alignItems: 'center', sx: { '& svg': { display: 'block', height: '20px', width: 'auto' } }, children: _jsx(Logo, { color: 'var(--color-foreground-fg-brand-logo)', ...logoProps }) }), _jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [showSearch && (_jsx(NavIconButton, { icon: 'MagnifyingGlass', ariaLabel: 'Search', onClick: onSearchClick })), _jsx(NavIconButton, { icon: 'List', ariaLabel: 'Open menu', onClick: handleMenuClick })] })] }), drawerProps && navItems && (_jsx(MuiDrawer, { anchor: 'left', open: open, onClose: closeDrawer, PaperProps: {
|
|
41
|
-
sx: { backgroundColor: 'transparent', boxShadow: 'none' },
|
|
42
|
-
}, children: _jsx(Drawer, { ...drawerProps, navItems: navItems, showToggle: false }) }))] }));
|
|
32
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { className: className, sx: style, boxSizing: 'border-box', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', width: '100%', height: '60px', paddingX: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', borderBottom: '1px solid var(--color-border-border-component)', bgcolor: 'var(--color-background-bg-page)', children: [_jsx(Box, { display: 'flex', alignItems: 'center', sx: { '& svg': { display: 'block', height: '20px', width: 'auto' } }, children: _jsx(Logo, { color: 'var(--color-foreground-fg-brand-logo)', ...logoProps }) }), _jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [showSearch && (_jsx(NavIconButton, { icon: 'MagnifyingGlass', ariaLabel: 'Search', onClick: onSearchClick })), _jsx(NavIconButton, { icon: 'List', ariaLabel: 'Open menu', onClick: handleMenuClick })] })] }), drawerProps && (_jsx(MobileNav, { open: open, onOpenChange: setOpen, navItems: drawerProps.navItems, activeKey: drawerProps.activeKey, credits: drawerProps.credits, creditsLoading: drawerProps.creditsLoading, profile: drawerProps.profile, profileLoading: drawerProps.profileLoading, logo: drawerProps.logo }))] }));
|
|
43
33
|
};
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
import { MobileNavBar } from './MobileNavBar';
|
|
2
|
-
|
|
3
|
-
{ key: 'home', text: 'Home', icon: 'House' },
|
|
4
|
-
{ key: 'avatars', text: 'Avatars', icon: 'UserFocus' },
|
|
5
|
-
{ key: 'agents', text: 'My Agents', icon: 'Headset' },
|
|
6
|
-
{ key: 'ttv', text: 'Text-to-Video', icon: 'VideoCamera' },
|
|
7
|
-
{ key: 'kb', text: 'Knowledge Base', icon: 'Book' },
|
|
8
|
-
{ key: 'conversations', text: 'Conversations', icon: 'ChatTeardropDots' },
|
|
9
|
-
{ key: 'analytics', text: 'Analytics', icon: 'ChartBar' },
|
|
10
|
-
{ key: 'api', text: 'API keys', icon: 'Key' },
|
|
11
|
-
{ key: 'developers', text: 'Developers', icon: 'BracketsCurly' },
|
|
12
|
-
];
|
|
2
|
+
import { credits, drawerNavItems, profile } from './navigation.fixtures';
|
|
13
3
|
const drawerProps = {
|
|
14
|
-
navItems,
|
|
4
|
+
navItems: drawerNavItems,
|
|
15
5
|
activeKey: 'kb',
|
|
16
|
-
credits
|
|
17
|
-
profile
|
|
18
|
-
name: 'Emma Novak',
|
|
19
|
-
email: 'emma@example.com',
|
|
20
|
-
},
|
|
6
|
+
credits,
|
|
7
|
+
profile,
|
|
21
8
|
};
|
|
22
9
|
const meta = {
|
|
23
10
|
title: 'Design System/Components/Navigation/MobileNavBar',
|
|
@@ -37,7 +24,7 @@ const meta = {
|
|
|
37
24
|
},
|
|
38
25
|
drawerProps: {
|
|
39
26
|
control: false,
|
|
40
|
-
description: 'Drawer config. When provided, the menu button opens the navigation
|
|
27
|
+
description: 'Drawer config. When provided, the menu button opens the navigation as a `MobileNav` overlay. Any nav item carrying a `subNav` (here: Settings) becomes a pushable pane inside it.',
|
|
41
28
|
table: { type: { summary: 'DrawerProps' } },
|
|
42
29
|
},
|
|
43
30
|
showSearch: {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
/**
|
|
3
|
+
* The settings page at both sizes, driven by a single navigation config.
|
|
4
|
+
*
|
|
5
|
+
* Above 640px the primary {@link Drawer} and the {@link SubNav} sit side
|
|
6
|
+
* by side. Below it there is no room for two panels, so `MobileNavBar` slides in
|
|
7
|
+
* one `MobileNav` overlay where the Settings item — carrying that same
|
|
8
|
+
* `sections` array as its `subNav` — pushes the settings pane instead.
|
|
9
|
+
*
|
|
10
|
+
* Resize the preview across 640px to see them swap.
|
|
11
|
+
*/
|
|
12
|
+
declare const SettingsPageExample: () => import("react").JSX.Element;
|
|
13
|
+
declare const meta: Meta<typeof SettingsPageExample>;
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof SettingsPageExample>;
|
|
16
|
+
/** Two panels side by side. Widen the preview past 640px. */
|
|
17
|
+
export declare const DrawerWithSubNav: Story;
|
|
18
|
+
/** The same config, merged into one overlay. Open the menu, then tap Settings. */
|
|
19
|
+
export declare const Mobile: Story;
|