@beydesign/storybook 0.2.30 → 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/{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/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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { NavItemState } from './types';
|
|
4
|
+
import { Typography, TypographySize, TypographyWeight } from '../../Typography';
|
|
5
|
+
import { Badge, BadgeColor, BadgeSize } from '../../UI';
|
|
6
|
+
import { getIconComponent } from '../../../utils';
|
|
7
|
+
const ACTIVE_FG = 'var(--color-text-text-clicable)';
|
|
8
|
+
const INACTIVE_FG = 'var(--color-text-text-subtle)';
|
|
9
|
+
const ACTIVE_BG = 'var(--color-background-bg-brand-transparent)';
|
|
10
|
+
const HOVER_BG = 'var(--color-background-bg-brand-transparent-hover)';
|
|
11
|
+
const foreground = (state) => state === NavItemState.Active || state === NavItemState.Hover
|
|
12
|
+
? ACTIVE_FG
|
|
13
|
+
: INACTIVE_FG;
|
|
14
|
+
const background = (state) => {
|
|
15
|
+
if (state === NavItemState.Active)
|
|
16
|
+
return ACTIVE_BG;
|
|
17
|
+
if (state === NavItemState.Hover)
|
|
18
|
+
return HOVER_BG;
|
|
19
|
+
return 'transparent';
|
|
20
|
+
};
|
|
21
|
+
const StyledNavRow = styled.button `
|
|
22
|
+
appearance: none;
|
|
23
|
+
font: inherit;
|
|
24
|
+
text-align: left;
|
|
25
|
+
border: none;
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: ${({ $collapsed }) => $collapsed ? 'center' : 'flex-start'};
|
|
30
|
+
gap: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
31
|
+
width: ${({ $collapsed }) => ($collapsed ? '36px' : '100%')};
|
|
32
|
+
height: ${({ $collapsed }) => ($collapsed ? '36px' : 'auto')};
|
|
33
|
+
align-self: ${({ $collapsed }) => ($collapsed ? 'center' : 'stretch')};
|
|
34
|
+
padding: ${({ $collapsed, $padding }) => ($collapsed ? '0' : $padding)};
|
|
35
|
+
border-radius: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
36
|
+
color: ${({ $state }) => foreground($state)};
|
|
37
|
+
background-color: ${({ $state }) => background($state)};
|
|
38
|
+
opacity: ${({ $state }) => ($state === NavItemState.Disabled ? 0.5 : 1)};
|
|
39
|
+
cursor: ${({ $state }) => $state === NavItemState.Disabled ? 'not-allowed' : 'pointer'};
|
|
40
|
+
transition:
|
|
41
|
+
background-color 0.2s ease-in-out,
|
|
42
|
+
color 0.2s ease-in-out,
|
|
43
|
+
padding 0.3s ease-in-out;
|
|
44
|
+
|
|
45
|
+
&:hover {
|
|
46
|
+
${({ $state }) => $state === NavItemState.Inactive
|
|
47
|
+
? `background-color: ${HOVER_BG}; color: ${ACTIVE_FG};`
|
|
48
|
+
: ''}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
const IconSlot = styled.span `
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
flex-shrink: 0;
|
|
54
|
+
color: inherit;
|
|
55
|
+
`;
|
|
56
|
+
const Label = styled.span `
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
flex: 1 1 0;
|
|
59
|
+
min-width: 0;
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
text-overflow: ellipsis;
|
|
63
|
+
color: inherit;
|
|
64
|
+
`;
|
|
65
|
+
/**
|
|
66
|
+
* The single navigation row used by every nav in the system. `DrawerNavItem`
|
|
67
|
+
* and `SubNavItem` are thin configurations of this component — they differ
|
|
68
|
+
* only in padding, icon size and type scale — so the states, colours, hover
|
|
69
|
+
* behaviour and badge handling live here exactly once. All colours resolve to
|
|
70
|
+
* theme tokens, so it adapts to light and dark.
|
|
71
|
+
*/
|
|
72
|
+
export const NavRow = ({ text, icon, state = NavItemState.Inactive, collapsed = false, iconSize = 20, typographySize = TypographySize.TextS, typographyWeight = TypographyWeight.SemiBold, padding = 'var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px)', showBadge = false, badgeText = 'Coming Soon', trailing, onClick, className, style, testId, }) => {
|
|
73
|
+
const isDisabled = state === NavItemState.Disabled;
|
|
74
|
+
const handleClick = () => {
|
|
75
|
+
if (!isDisabled)
|
|
76
|
+
onClick?.();
|
|
77
|
+
};
|
|
78
|
+
return (_jsxs(StyledNavRow, { type: "button", "$state": state, "$collapsed": collapsed, "$padding": padding, className: className, style: style, onClick: handleClick, disabled: isDisabled, title: collapsed ? text : undefined, "aria-current": state === NavItemState.Active ? 'page' : undefined, "data-testid": testId, children: [_jsx(IconSlot, { children: getIconComponent(icon, { size: iconSize }) }), !collapsed && (_jsxs(_Fragment, { children: [_jsx(Label, { children: _jsx(Typography, { size: typographySize, weight: typographyWeight, color: "inherit", children: text }) }), showBadge && (_jsx(Badge, { size: BadgeSize.xs, icon: "ClockCountdown", showIcon: true, text: badgeText, color: BadgeColor.Default })), trailing] }))] }));
|
|
79
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal shared navigation primitives.
|
|
3
|
+
*
|
|
4
|
+
* This folder is deliberately NOT re-exported from `Navigation/index.ts` — it is
|
|
5
|
+
* the private foundation `Drawer`, `SubNav` and `MobileNav` are built on.
|
|
6
|
+
* Anything consumers need reaches them through those barrels under its public
|
|
7
|
+
* name (e.g. `NavItemState` ships as `DrawerNavItemState`).
|
|
8
|
+
*/
|
|
9
|
+
export * from './NavPanel';
|
|
10
|
+
export * from './NavRow';
|
|
11
|
+
export * from './types';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal shared navigation primitives.
|
|
3
|
+
*
|
|
4
|
+
* This folder is deliberately NOT re-exported from `Navigation/index.ts` — it is
|
|
5
|
+
* the private foundation `Drawer`, `SubNav` and `MobileNav` are built on.
|
|
6
|
+
* Anything consumers need reaches them through those barrels under its public
|
|
7
|
+
* name (e.g. `NavItemState` ships as `DrawerNavItemState`).
|
|
8
|
+
*/
|
|
9
|
+
export * from './NavPanel';
|
|
10
|
+
export * from './NavRow';
|
|
11
|
+
export * from './types';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { IconName } from '../../../utils';
|
|
2
|
+
/**
|
|
3
|
+
* Expanded / collapsed size shared across every navigation panel and its
|
|
4
|
+
* sub-components.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum NavPanelSize {
|
|
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 NavItemState {
|
|
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 NavItemHierarchy {
|
|
26
|
+
First = "First",
|
|
27
|
+
Secondary = "Secondary"
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A single navigation entry inside a {@link SubNavSection}.
|
|
31
|
+
*/
|
|
32
|
+
export interface SubNavItemConfig {
|
|
33
|
+
/** Stable identifier used to resolve the active item (falls back to `text`). */
|
|
34
|
+
key?: string;
|
|
35
|
+
text: string;
|
|
36
|
+
icon: IconName;
|
|
37
|
+
/** Force a state. When omitted it is derived from `activeKey` / `disabled`. */
|
|
38
|
+
state?: NavItemState;
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
showBadge?: boolean;
|
|
41
|
+
badgeText?: string;
|
|
42
|
+
/** When set, clicking navigates to this URL. */
|
|
43
|
+
link?: string;
|
|
44
|
+
onClick?: () => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A titled group of {@link SubNavItemConfig} rows
|
|
48
|
+
* (e.g. "Your business", "Billing & plans").
|
|
49
|
+
*/
|
|
50
|
+
export interface SubNavSection {
|
|
51
|
+
/** Stable key for the section (falls back to `title`). */
|
|
52
|
+
key?: string;
|
|
53
|
+
/** Uppercase caption rendered above the section's items. */
|
|
54
|
+
title?: string;
|
|
55
|
+
items: SubNavItemConfig[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A secondary navigation that a top-level nav item can drill into.
|
|
59
|
+
*
|
|
60
|
+
* On desktop this is rendered as its own panel beside the primary nav (see
|
|
61
|
+
* `SubNav`). On mobile there is no room for two panels, so the same
|
|
62
|
+
* config is pushed as a second pane inside the single overlay — see `MobileNav`.
|
|
63
|
+
*/
|
|
64
|
+
export interface SubNavConfig {
|
|
65
|
+
/** Heading rendered at the top of the pane. */
|
|
66
|
+
title?: string;
|
|
67
|
+
/** Grouped navigation entries. */
|
|
68
|
+
sections: SubNavSection[];
|
|
69
|
+
/** Key (or text) of the currently active item. */
|
|
70
|
+
activeKey?: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expanded / collapsed size shared across every navigation panel and its
|
|
3
|
+
* sub-components.
|
|
4
|
+
*/
|
|
5
|
+
export var NavPanelSize;
|
|
6
|
+
(function (NavPanelSize) {
|
|
7
|
+
NavPanelSize["Expanded"] = "Expanded";
|
|
8
|
+
NavPanelSize["Collapsed"] = "Collapsed";
|
|
9
|
+
})(NavPanelSize || (NavPanelSize = {}));
|
|
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 var NavItemState;
|
|
16
|
+
(function (NavItemState) {
|
|
17
|
+
NavItemState["Active"] = "Active";
|
|
18
|
+
NavItemState["Inactive"] = "Inactive";
|
|
19
|
+
NavItemState["Hover"] = "Hover";
|
|
20
|
+
NavItemState["Disabled"] = "Disabled";
|
|
21
|
+
})(NavItemState || (NavItemState = {}));
|
|
22
|
+
/**
|
|
23
|
+
* Hierarchy of a navigation item. `First` is a top-level entry (36px row),
|
|
24
|
+
* `Secondary` is a nested sub-item (28px row, lighter weight).
|
|
25
|
+
*/
|
|
26
|
+
export var NavItemHierarchy;
|
|
27
|
+
(function (NavItemHierarchy) {
|
|
28
|
+
NavItemHierarchy["First"] = "First";
|
|
29
|
+
NavItemHierarchy["Secondary"] = "Secondary";
|
|
30
|
+
})(NavItemHierarchy || (NavItemHierarchy = {}));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DrawerNavItemConfig } from './Drawer';
|
|
2
|
+
import type { SubNavSection } from './SubNav';
|
|
3
|
+
/**
|
|
4
|
+
* Sample navigation config shared by the navigation stories.
|
|
5
|
+
*
|
|
6
|
+
* The point of this file is the point of the whole design: ONE config drives
|
|
7
|
+
* both layouts. On desktop `settingsSections` renders as a `SubNav` panel
|
|
8
|
+
* beside the `Drawer`; on mobile the very same array rides along on the
|
|
9
|
+
* Settings item's `subNav` and becomes the second pane of `MobileNav`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const settingsSections: SubNavSection[];
|
|
12
|
+
export declare const drawerNavItems: DrawerNavItemConfig[];
|
|
13
|
+
export declare const credits: {
|
|
14
|
+
usedCredits: number;
|
|
15
|
+
maxCredits: number;
|
|
16
|
+
};
|
|
17
|
+
export declare const profile: {
|
|
18
|
+
name: string;
|
|
19
|
+
email: string;
|
|
20
|
+
};
|
|
21
|
+
/** Display names for the settings keys, for the example page's content area. */
|
|
22
|
+
export declare const settingsLabels: Record<string, string>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample navigation config shared by the navigation stories.
|
|
3
|
+
*
|
|
4
|
+
* The point of this file is the point of the whole design: ONE config drives
|
|
5
|
+
* both layouts. On desktop `settingsSections` renders as a `SubNav` panel
|
|
6
|
+
* beside the `Drawer`; on mobile the very same array rides along on the
|
|
7
|
+
* Settings item's `subNav` and becomes the second pane of `MobileNav`.
|
|
8
|
+
*/
|
|
9
|
+
export const settingsSections = [
|
|
10
|
+
{
|
|
11
|
+
key: 'business',
|
|
12
|
+
title: 'Your business',
|
|
13
|
+
items: [{ key: 'branding', text: 'Branding', icon: 'StarFour' }],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
key: 'team',
|
|
17
|
+
title: 'Team',
|
|
18
|
+
items: [{ key: 'members', text: 'Members', icon: 'UsersThree' }],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: 'billing',
|
|
22
|
+
title: 'Billing & plans',
|
|
23
|
+
items: [
|
|
24
|
+
{ key: 'subscription', text: 'Subscription', icon: 'CreditCard' },
|
|
25
|
+
{ key: 'invoices', text: 'Invoices', icon: 'FileText' },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: 'developers',
|
|
30
|
+
title: 'Developers',
|
|
31
|
+
items: [
|
|
32
|
+
{ key: 'api-keys', text: 'API keys', icon: 'Key' },
|
|
33
|
+
{ key: 'webhooks', text: 'Webhooks', icon: 'Graph' },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
export const drawerNavItems = [
|
|
38
|
+
{ key: 'home', text: 'Home', icon: 'House' },
|
|
39
|
+
{ key: 'avatars', text: 'Avatars', icon: 'UserFocus' },
|
|
40
|
+
{ key: 'agents', text: 'My Agents', icon: 'Headset' },
|
|
41
|
+
{ key: 'ttv', text: 'Text-to-Video', icon: 'VideoCamera' },
|
|
42
|
+
{ key: 'kb', text: 'Knowledge Base', icon: 'Book' },
|
|
43
|
+
{ key: 'conversations', text: 'Conversations', icon: 'ChatTeardropDots' },
|
|
44
|
+
{ key: 'analytics', text: 'Analytics', icon: 'ChartBar' },
|
|
45
|
+
{ key: 'api', text: 'API keys', icon: 'Key' },
|
|
46
|
+
{ key: 'developers', text: 'Developers', icon: 'BracketsCurly' },
|
|
47
|
+
{
|
|
48
|
+
key: 'settings',
|
|
49
|
+
text: 'Settings',
|
|
50
|
+
icon: 'GearSix',
|
|
51
|
+
subNav: { title: 'Settings', sections: settingsSections },
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
export const credits = { usedCredits: 500, maxCredits: 2000 };
|
|
55
|
+
export const profile = { name: 'Emma Novak', email: 'emma@example.com' };
|
|
56
|
+
/** Display names for the settings keys, for the example page's content area. */
|
|
57
|
+
export const settingsLabels = {
|
|
58
|
+
branding: 'Branding',
|
|
59
|
+
members: 'Members',
|
|
60
|
+
subscription: 'Subscription',
|
|
61
|
+
invoices: 'Invoices',
|
|
62
|
+
'api-keys': 'API keys',
|
|
63
|
+
webhooks: 'Webhooks',
|
|
64
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
1
2
|
import { SxProps, Theme } from '@mui/material';
|
|
2
3
|
import { IconName } from '../../utils';
|
|
3
4
|
import { AvatarProps } from '../UI';
|
|
4
5
|
import { CreditsCardProps } from '../Credits';
|
|
5
|
-
import { DrawerProps } from '
|
|
6
|
+
import { DrawerBodyProps, DrawerProps } from './Drawer';
|
|
6
7
|
/**
|
|
7
8
|
* Header component props
|
|
8
9
|
*/
|
|
@@ -185,6 +186,28 @@ export interface ProcessHeaderProps {
|
|
|
185
186
|
/** The class name to apply to the component */
|
|
186
187
|
className?: string;
|
|
187
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Props for the {@link MobileNav} overlay — the single navigation panel used
|
|
191
|
+
* below the mobile breakpoint, which holds the `Drawer` and any `subNav` as
|
|
192
|
+
* pushable panes.
|
|
193
|
+
*/
|
|
194
|
+
export interface MobileNavProps extends Omit<DrawerBodyProps, 'size' | 'onSubNavOpen'> {
|
|
195
|
+
/** Whether the overlay is open. */
|
|
196
|
+
open: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Fired with the next open value — when the scrim is clicked, Esc is pressed,
|
|
199
|
+
* or the user navigates from a nav item.
|
|
200
|
+
*/
|
|
201
|
+
onOpenChange: (open: boolean) => void;
|
|
202
|
+
/** Panel width. Defaults to `315px`, matching the mobile design. */
|
|
203
|
+
width?: string;
|
|
204
|
+
/** The class name to apply to the component */
|
|
205
|
+
className?: string;
|
|
206
|
+
/** The style object to apply to the sliding panel */
|
|
207
|
+
style?: CSSProperties;
|
|
208
|
+
/** Renders as `data-testid` for testing. */
|
|
209
|
+
testId?: string;
|
|
210
|
+
}
|
|
188
211
|
/**
|
|
189
212
|
* Mobile navigation bar props
|
|
190
213
|
*/
|
package/package.json
CHANGED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import styled from '@emotion/styled';
|
|
4
|
-
import { DrawerSize, DrawerNavItemState, DrawerNavItemHierarchy, } from './types';
|
|
5
|
-
import { DrawerNavItem } from './DrawerNavItem';
|
|
6
|
-
import { DrawerCreditsCard } from './DrawerCreditsCard';
|
|
7
|
-
import { DrawerCreditsCardSkeleton } from './DrawerCreditsCardSkeleton';
|
|
8
|
-
import { DrawerProfile } from './DrawerProfile';
|
|
9
|
-
import { DrawerProfileSkeleton } from './DrawerProfileSkeleton';
|
|
10
|
-
import { Logo, LogoVariant } from '../UI';
|
|
11
|
-
import { getIconComponent } from '../../utils';
|
|
12
|
-
const EXPANDED_WIDTH = '238px';
|
|
13
|
-
const COLLAPSED_WIDTH = '68px';
|
|
14
|
-
/** Composed from the semantic `shadow-sm` design token. */
|
|
15
|
-
const SHADOW_SM = 'var(--global-shadows-shadow-sm-offset-x) var(--global-shadows-shadow-sm-offset-y) var(--global-shadows-shadow-sm-blur) var(--global-shadows-shadow-sm-spread) var(--global-shadows-shadow-sm-color)';
|
|
16
|
-
/**
|
|
17
|
-
* Non-clipping outer shell. The toggle lives here (a sibling of the scroll
|
|
18
|
-
* area) so it can overhang the right edge without being clipped by the panel's
|
|
19
|
-
* `overflow`.
|
|
20
|
-
*/
|
|
21
|
-
const Shell = styled.aside `
|
|
22
|
-
position: relative;
|
|
23
|
-
flex-shrink: 0;
|
|
24
|
-
height: 100vh;
|
|
25
|
-
width: ${({ $collapsed }) => ($collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH)};
|
|
26
|
-
transition: width 0.3s ease-in-out;
|
|
27
|
-
`;
|
|
28
|
-
const Scroll = styled.div `
|
|
29
|
-
box-sizing: border-box;
|
|
30
|
-
display: flex;
|
|
31
|
-
flex-direction: column;
|
|
32
|
-
height: 100%;
|
|
33
|
-
width: 100%;
|
|
34
|
-
padding: var(--spacing-tokens-size-in-px-spacing-spacing-xl, 16px)
|
|
35
|
-
var(--spacing-tokens-size-in-px-spacing-spacing-xl, 16px)
|
|
36
|
-
var(--spacing-tokens-size-in-px-spacing-spacing-2xl, 24px);
|
|
37
|
-
background-color: var(--color-background-bg-page-contrast);
|
|
38
|
-
border-right: 1px solid var(--color-border-border-subtle);
|
|
39
|
-
overflow-x: hidden;
|
|
40
|
-
overflow-y: auto;
|
|
41
|
-
|
|
42
|
-
/* Theme-aware thin scrollbar */
|
|
43
|
-
scrollbar-width: thin;
|
|
44
|
-
scrollbar-color: var(--color-border-border-component) transparent;
|
|
45
|
-
|
|
46
|
-
&::-webkit-scrollbar {
|
|
47
|
-
width: 6px;
|
|
48
|
-
}
|
|
49
|
-
&::-webkit-scrollbar-track {
|
|
50
|
-
background: transparent;
|
|
51
|
-
}
|
|
52
|
-
&::-webkit-scrollbar-thumb {
|
|
53
|
-
background-color: var(--color-border-border-component);
|
|
54
|
-
border-radius: var(--spacing-tokens-size-in-px-radius-radius-full);
|
|
55
|
-
}
|
|
56
|
-
&::-webkit-scrollbar-thumb:hover {
|
|
57
|
-
background-color: var(--color-text-text-subtle);
|
|
58
|
-
}
|
|
59
|
-
`;
|
|
60
|
-
const LogoHeader = styled.div `
|
|
61
|
-
display: flex;
|
|
62
|
-
align-items: center;
|
|
63
|
-
justify-content: ${({ $collapsed }) => $collapsed ? 'center' : 'flex-start'};
|
|
64
|
-
height: 38px;
|
|
65
|
-
min-height: 38px;
|
|
66
|
-
margin-bottom: 40px;
|
|
67
|
-
`;
|
|
68
|
-
const Nav = styled.nav `
|
|
69
|
-
display: flex;
|
|
70
|
-
flex-direction: column;
|
|
71
|
-
flex: 1;
|
|
72
|
-
justify-content: space-between;
|
|
73
|
-
gap: var(--spacing-tokens-size-in-px-spacing-spacing-2xl, 24px);
|
|
74
|
-
`;
|
|
75
|
-
const NavTop = styled.div `
|
|
76
|
-
display: flex;
|
|
77
|
-
flex-direction: column;
|
|
78
|
-
gap: var(--spacing-tokens-size-in-px-spacing-spacing-lg, 12px);
|
|
79
|
-
`;
|
|
80
|
-
const Footer = styled.div `
|
|
81
|
-
display: flex;
|
|
82
|
-
flex-direction: column;
|
|
83
|
-
gap: var(--spacing-tokens-size-in-px-spacing-spacing-2xl, 24px);
|
|
84
|
-
`;
|
|
85
|
-
const FooterSlot = styled.div `
|
|
86
|
-
display: flex;
|
|
87
|
-
justify-content: center;
|
|
88
|
-
`;
|
|
89
|
-
const ToggleButton = styled.button `
|
|
90
|
-
appearance: none;
|
|
91
|
-
position: absolute;
|
|
92
|
-
top: 52px;
|
|
93
|
-
right: -16px;
|
|
94
|
-
z-index: 2;
|
|
95
|
-
display: inline-flex;
|
|
96
|
-
align-items: center;
|
|
97
|
-
justify-content: center;
|
|
98
|
-
width: 32px;
|
|
99
|
-
height: 32px;
|
|
100
|
-
padding: 0;
|
|
101
|
-
border: 1px solid var(--color-border-border-subtle);
|
|
102
|
-
border-radius: var(--spacing-tokens-size-in-px-radius-radius-full);
|
|
103
|
-
background-color: var(--color-background-bg-element);
|
|
104
|
-
color: var(--color-text-text-paragraph);
|
|
105
|
-
cursor: pointer;
|
|
106
|
-
box-shadow: ${SHADOW_SM};
|
|
107
|
-
transition: color 0.2s ease-in-out;
|
|
108
|
-
|
|
109
|
-
&:hover {
|
|
110
|
-
color: var(--color-text-text-clicable);
|
|
111
|
-
}
|
|
112
|
-
`;
|
|
113
|
-
/** Rotates the chevron smoothly between expanded (◀) and collapsed (▶). */
|
|
114
|
-
const ToggleIcon = styled.span `
|
|
115
|
-
display: inline-flex;
|
|
116
|
-
transform: rotate(${({ $collapsed }) => ($collapsed ? '180deg' : '0deg')});
|
|
117
|
-
transition: transform 0.3s ease-in-out;
|
|
118
|
-
|
|
119
|
-
@media (prefers-reduced-motion: reduce) {
|
|
120
|
-
transition: none;
|
|
121
|
-
}
|
|
122
|
-
`;
|
|
123
|
-
const resolveState = (item, activeKey) => {
|
|
124
|
-
if (item.state)
|
|
125
|
-
return item.state;
|
|
126
|
-
if (item.disabled)
|
|
127
|
-
return DrawerNavItemState.Disabled;
|
|
128
|
-
const key = item.key ?? item.text;
|
|
129
|
-
if (activeKey !== undefined && key === activeKey) {
|
|
130
|
-
return DrawerNavItemState.Active;
|
|
131
|
-
}
|
|
132
|
-
return DrawerNavItemState.Inactive;
|
|
133
|
-
};
|
|
134
|
-
/**
|
|
135
|
-
* Composed application sidebar ("Drawer"): logo header, navigation list,
|
|
136
|
-
* credits card and user-profile footer, with a floating collapse/expand
|
|
137
|
-
* toggle. Collapse state can be controlled (`collapsed` + `onToggle`) or left
|
|
138
|
-
* uncontrolled (`defaultCollapsed`). Every colour, space and radius resolves to
|
|
139
|
-
* `@beydesign/tokens` CSS variables, so it renders correctly in light and dark.
|
|
140
|
-
*/
|
|
141
|
-
export const Drawer = ({ navItems, activeKey, collapsed, defaultCollapsed = false, onToggle, showToggle = true, credits, creditsLoading = false, profile, profileLoading = false, logo, className, style, testId, }) => {
|
|
142
|
-
const isControlled = collapsed !== undefined;
|
|
143
|
-
const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);
|
|
144
|
-
const isCollapsed = isControlled ? collapsed : internalCollapsed;
|
|
145
|
-
const drawerSize = isCollapsed ? DrawerSize.Collapsed : DrawerSize.Expanded;
|
|
146
|
-
const handleToggle = () => {
|
|
147
|
-
const next = !isCollapsed;
|
|
148
|
-
if (!isControlled)
|
|
149
|
-
setInternalCollapsed(next);
|
|
150
|
-
onToggle?.(next);
|
|
151
|
-
};
|
|
152
|
-
const handleItemClick = (item) => {
|
|
153
|
-
if (item.disabled)
|
|
154
|
-
return;
|
|
155
|
-
if (item.link) {
|
|
156
|
-
window.location.href = item.link;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
item.onClick?.();
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
return (_jsxs(Shell, { "$collapsed": isCollapsed, className: className, style: style, "data-testid": testId, children: [_jsxs(Scroll, { children: [_jsx(LogoHeader, { "$collapsed": isCollapsed, children: _jsx(Logo, { variant: isCollapsed ? LogoVariant.Icon : LogoVariant.Horizontal, color: logo?.color ?? 'var(--color-foreground-fg-brand-logo)', gradient: logo?.gradient, svgUrl: logo?.svgUrl }) }), _jsxs(Nav, { children: [_jsx(NavTop, { children: navItems.map((item) => (_jsx(DrawerNavItem, { text: item.text, icon: item.icon, state: resolveState(item, activeKey), size: drawerSize, hierarchy: item.hierarchy ?? DrawerNavItemHierarchy.First, showBadge: item.showBadge, badgeText: item.badgeText, onClick: () => handleItemClick(item) }, item.key ?? item.text))) }), (credits || creditsLoading || profile || profileLoading) && (_jsxs(Footer, { children: [(credits || creditsLoading) && (_jsx(FooterSlot, { "$collapsed": isCollapsed, children: creditsLoading ? (_jsx(DrawerCreditsCardSkeleton, { size: drawerSize })) : (_jsx(DrawerCreditsCard, { ...credits, size: drawerSize })) })), (profile || profileLoading) && (_jsx(FooterSlot, { "$collapsed": isCollapsed, children: profileLoading ? (_jsx(DrawerProfileSkeleton, { size: drawerSize })) : (profile && _jsx(DrawerProfile, { ...profile, size: drawerSize })) }))] }))] })] }), showToggle && (_jsx(ToggleButton, { type: "button", onClick: handleToggle, "aria-label": isCollapsed ? 'Expand sidebar' : 'Collapse sidebar', children: _jsx(ToggleIcon, { "$collapsed": isCollapsed, children: getIconComponent('CaretLeft', { size: 16, weight: 'bold' }) }) }))] }));
|
|
163
|
-
};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import styled from '@emotion/styled';
|
|
3
|
-
import { DrawerNavItemState, DrawerNavItemHierarchy, DrawerSize, } from './types';
|
|
4
|
-
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
5
|
-
import { Badge, BadgeColor, BadgeSize } from '../UI';
|
|
6
|
-
import { getIconComponent } from '../../utils';
|
|
7
|
-
const ACTIVE_FG = 'var(--color-text-text-clicable)';
|
|
8
|
-
const INACTIVE_FG = 'var(--color-text-text-subtle)';
|
|
9
|
-
const ACTIVE_BG = 'var(--color-background-bg-brand-transparent)';
|
|
10
|
-
const HOVER_BG = 'var(--color-background-bg-brand-transparent-hover)';
|
|
11
|
-
const foreground = (state) => state === DrawerNavItemState.Active || state === DrawerNavItemState.Hover
|
|
12
|
-
? ACTIVE_FG
|
|
13
|
-
: INACTIVE_FG;
|
|
14
|
-
const background = (state) => {
|
|
15
|
-
if (state === DrawerNavItemState.Active)
|
|
16
|
-
return ACTIVE_BG;
|
|
17
|
-
if (state === DrawerNavItemState.Hover)
|
|
18
|
-
return HOVER_BG;
|
|
19
|
-
return 'transparent';
|
|
20
|
-
};
|
|
21
|
-
const StyledNavItem = styled.button `
|
|
22
|
-
appearance: none;
|
|
23
|
-
font: inherit;
|
|
24
|
-
text-align: left;
|
|
25
|
-
border: none;
|
|
26
|
-
box-sizing: border-box;
|
|
27
|
-
display: flex;
|
|
28
|
-
align-items: center;
|
|
29
|
-
justify-content: ${({ $collapsed }) => $collapsed ? 'center' : 'flex-start'};
|
|
30
|
-
gap: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
31
|
-
width: ${({ $collapsed }) => ($collapsed ? '36px' : '100%')};
|
|
32
|
-
height: ${({ $collapsed }) => ($collapsed ? '36px' : 'auto')};
|
|
33
|
-
align-self: ${({ $collapsed }) => ($collapsed ? 'center' : 'stretch')};
|
|
34
|
-
padding: ${({ $collapsed, $hierarchy }) => {
|
|
35
|
-
if ($collapsed)
|
|
36
|
-
return '0';
|
|
37
|
-
return $hierarchy === DrawerNavItemHierarchy.Secondary
|
|
38
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-xs, 4px) var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px)'
|
|
39
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px)';
|
|
40
|
-
}};
|
|
41
|
-
border-radius: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
42
|
-
color: ${({ $state }) => foreground($state)};
|
|
43
|
-
background-color: ${({ $state }) => background($state)};
|
|
44
|
-
opacity: ${({ $state }) => $state === DrawerNavItemState.Disabled ? 0.5 : 1};
|
|
45
|
-
cursor: ${({ $state }) => $state === DrawerNavItemState.Disabled ? 'not-allowed' : 'pointer'};
|
|
46
|
-
transition:
|
|
47
|
-
background-color 0.2s ease-in-out,
|
|
48
|
-
color 0.2s ease-in-out,
|
|
49
|
-
padding 0.3s ease-in-out;
|
|
50
|
-
|
|
51
|
-
&:hover {
|
|
52
|
-
${({ $state }) => $state === DrawerNavItemState.Inactive
|
|
53
|
-
? `background-color: ${HOVER_BG}; color: ${ACTIVE_FG};`
|
|
54
|
-
: ''}
|
|
55
|
-
}
|
|
56
|
-
`;
|
|
57
|
-
const IconSlot = styled.span `
|
|
58
|
-
display: inline-flex;
|
|
59
|
-
flex-shrink: 0;
|
|
60
|
-
color: inherit;
|
|
61
|
-
`;
|
|
62
|
-
const Label = styled.span `
|
|
63
|
-
display: inline-flex;
|
|
64
|
-
flex: 1 1 0;
|
|
65
|
-
min-width: 0;
|
|
66
|
-
white-space: nowrap;
|
|
67
|
-
overflow: hidden;
|
|
68
|
-
text-overflow: ellipsis;
|
|
69
|
-
color: inherit;
|
|
70
|
-
`;
|
|
71
|
-
/**
|
|
72
|
-
* A single navigation row for the {@link Drawer}. Supports active / inactive /
|
|
73
|
-
* hover / disabled states, first / secondary hierarchy and expanded / collapsed
|
|
74
|
-
* sizes. All colours resolve to theme tokens, so it adapts to light and dark.
|
|
75
|
-
*/
|
|
76
|
-
export const DrawerNavItem = ({ text, icon, state = DrawerNavItemState.Inactive, size = DrawerSize.Expanded, hierarchy = DrawerNavItemHierarchy.First, showBadge = false, badgeText = 'Coming Soon', onClick, className, style, testId, }) => {
|
|
77
|
-
const isCollapsed = size === DrawerSize.Collapsed;
|
|
78
|
-
const isDisabled = state === DrawerNavItemState.Disabled;
|
|
79
|
-
const isSecondary = hierarchy === DrawerNavItemHierarchy.Secondary;
|
|
80
|
-
const handleClick = () => {
|
|
81
|
-
if (!isDisabled)
|
|
82
|
-
onClick?.();
|
|
83
|
-
};
|
|
84
|
-
return (_jsxs(StyledNavItem, { type: "button", "$state": state, "$collapsed": isCollapsed, "$hierarchy": hierarchy, className: className, style: style, onClick: handleClick, disabled: isDisabled, title: isCollapsed ? text : undefined, "data-testid": testId, children: [_jsx(IconSlot, { children: getIconComponent(icon, { size: 20 }) }), !isCollapsed && (_jsxs(_Fragment, { children: [_jsx(Label, { children: _jsx(Typography, { size: isSecondary ? TypographySize.TextXS : TypographySize.TextS, weight: isSecondary
|
|
85
|
-
? TypographyWeight.Medium
|
|
86
|
-
: TypographyWeight.SemiBold, color: "inherit", children: text }) }), showBadge && (_jsx(Badge, { size: BadgeSize.xs, icon: "ClockCountdown", showIcon: true, text: badgeText, color: BadgeColor.Default }))] }))] }));
|
|
87
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Expanded / collapsed size shared across the Drawer and its sub-components.
|
|
3
|
-
*/
|
|
4
|
-
export var DrawerSize;
|
|
5
|
-
(function (DrawerSize) {
|
|
6
|
-
DrawerSize["Expanded"] = "Expanded";
|
|
7
|
-
DrawerSize["Collapsed"] = "Collapsed";
|
|
8
|
-
})(DrawerSize || (DrawerSize = {}));
|
|
9
|
-
/**
|
|
10
|
-
* Visual state of a single navigation item.
|
|
11
|
-
* `Hover` is mostly useful for documentation/Storybook — at runtime an
|
|
12
|
-
* `Inactive` item also picks up the hover styling on real pointer hover.
|
|
13
|
-
*/
|
|
14
|
-
export var DrawerNavItemState;
|
|
15
|
-
(function (DrawerNavItemState) {
|
|
16
|
-
DrawerNavItemState["Active"] = "Active";
|
|
17
|
-
DrawerNavItemState["Inactive"] = "Inactive";
|
|
18
|
-
DrawerNavItemState["Hover"] = "Hover";
|
|
19
|
-
DrawerNavItemState["Disabled"] = "Disabled";
|
|
20
|
-
})(DrawerNavItemState || (DrawerNavItemState = {}));
|
|
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 var DrawerNavItemHierarchy;
|
|
26
|
-
(function (DrawerNavItemHierarchy) {
|
|
27
|
-
DrawerNavItemHierarchy["First"] = "First";
|
|
28
|
-
DrawerNavItemHierarchy["Secondary"] = "Secondary";
|
|
29
|
-
})(DrawerNavItemHierarchy || (DrawerNavItemHierarchy = {}));
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { SettingsNavProps } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Secondary navigation for the Settings area: a "Settings" heading followed by
|
|
5
|
-
* titled sections of {@link SettingsNavItem} rows. Sits beside the primary
|
|
6
|
-
* {@link Drawer} and only appears on settings pages. Every colour, space and
|
|
7
|
-
* radius resolves to `@beydesign/tokens` CSS variables, so it renders correctly
|
|
8
|
-
* in light and dark.
|
|
9
|
-
*/
|
|
10
|
-
export declare const SettingsNav: React.FC<SettingsNavProps>;
|