@beydesign/storybook 0.2.24 → 0.2.25
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/stories/Drawer/Drawer.js +3 -2
- package/dist/stories/Drawer/Drawer.stories.d.ts +3 -0
- package/dist/stories/Drawer/Drawer.stories.js +14 -0
- package/dist/stories/Drawer/DrawerProfileSkeleton.d.ts +9 -0
- package/dist/stories/Drawer/DrawerProfileSkeleton.js +37 -0
- package/dist/stories/Drawer/DrawerProfileSkeleton.stories.d.ts +7 -0
- package/dist/stories/Drawer/DrawerProfileSkeleton.stories.js +37 -0
- package/dist/stories/Drawer/index.d.ts +1 -0
- package/dist/stories/Drawer/index.js +1 -0
- package/dist/stories/Drawer/types.d.ts +12 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { DrawerNavItem } from './DrawerNavItem';
|
|
|
6
6
|
import { DrawerCreditsCard } from './DrawerCreditsCard';
|
|
7
7
|
import { DrawerCreditsCardSkeleton } from './DrawerCreditsCardSkeleton';
|
|
8
8
|
import { DrawerProfile } from './DrawerProfile';
|
|
9
|
+
import { DrawerProfileSkeleton } from './DrawerProfileSkeleton';
|
|
9
10
|
import { Logo, LogoVariant } from '../UI';
|
|
10
11
|
import { getIconComponent } from '../../utils';
|
|
11
12
|
const EXPANDED_WIDTH = '238px';
|
|
@@ -137,7 +138,7 @@ const resolveState = (item, activeKey) => {
|
|
|
137
138
|
* uncontrolled (`defaultCollapsed`). Every colour, space and radius resolves to
|
|
138
139
|
* `@beydesign/tokens` CSS variables, so it renders correctly in light and dark.
|
|
139
140
|
*/
|
|
140
|
-
export const Drawer = ({ navItems, activeKey, collapsed, defaultCollapsed = false, onToggle, showToggle = true, credits, creditsLoading = false, profile, logo, className, style, testId, }) => {
|
|
141
|
+
export const Drawer = ({ navItems, activeKey, collapsed, defaultCollapsed = false, onToggle, showToggle = true, credits, creditsLoading = false, profile, profileLoading = false, logo, className, style, testId, }) => {
|
|
141
142
|
const isControlled = collapsed !== undefined;
|
|
142
143
|
const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);
|
|
143
144
|
const isCollapsed = isControlled ? collapsed : internalCollapsed;
|
|
@@ -158,5 +159,5 @@ export const Drawer = ({ navItems, activeKey, collapsed, defaultCollapsed = fals
|
|
|
158
159
|
item.onClick?.();
|
|
159
160
|
}
|
|
160
161
|
};
|
|
161
|
-
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) && (_jsxs(Footer, { children: [(credits || creditsLoading) && (_jsx(FooterSlot, { "$collapsed": isCollapsed, children: creditsLoading ? (_jsx(DrawerCreditsCardSkeleton, { size: drawerSize })) : (_jsx(DrawerCreditsCard, { ...credits, size: drawerSize })) })), profile && (_jsx(FooterSlot, { "$collapsed": isCollapsed, children: _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' }) }) }))] }));
|
|
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' }) }) }))] }));
|
|
162
163
|
};
|
|
@@ -8,4 +8,7 @@ export declare const Collapsed: Story;
|
|
|
8
8
|
export declare const WithSubItems: Story;
|
|
9
9
|
export declare const CreditsLoading: Story;
|
|
10
10
|
export declare const CreditsLoadingCollapsed: Story;
|
|
11
|
+
export declare const ProfileLoading: Story;
|
|
12
|
+
export declare const ProfileLoadingCollapsed: Story;
|
|
13
|
+
export declare const FooterLoading: Story;
|
|
11
14
|
export declare const NoFooter: Story;
|
|
@@ -47,6 +47,11 @@ const meta = {
|
|
|
47
47
|
description: 'Render the credits card as a loading skeleton',
|
|
48
48
|
table: { defaultValue: { summary: 'false' } },
|
|
49
49
|
},
|
|
50
|
+
profileLoading: {
|
|
51
|
+
control: 'boolean',
|
|
52
|
+
description: 'Render the profile footer as a loading skeleton',
|
|
53
|
+
table: { defaultValue: { summary: 'false' } },
|
|
54
|
+
},
|
|
50
55
|
navItems: { control: false },
|
|
51
56
|
credits: { control: false },
|
|
52
57
|
profile: { control: false },
|
|
@@ -113,6 +118,15 @@ export const CreditsLoading = {
|
|
|
113
118
|
export const CreditsLoadingCollapsed = {
|
|
114
119
|
args: { creditsLoading: true, defaultCollapsed: true },
|
|
115
120
|
};
|
|
121
|
+
export const ProfileLoading = {
|
|
122
|
+
args: { profileLoading: true },
|
|
123
|
+
};
|
|
124
|
+
export const ProfileLoadingCollapsed = {
|
|
125
|
+
args: { profileLoading: true, defaultCollapsed: true },
|
|
126
|
+
};
|
|
127
|
+
export const FooterLoading = {
|
|
128
|
+
args: { creditsLoading: true, profileLoading: true },
|
|
129
|
+
};
|
|
116
130
|
export const NoFooter = {
|
|
117
131
|
args: { credits: undefined, profile: undefined },
|
|
118
132
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DrawerProfileSkeletonProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Loading placeholder for {@link DrawerProfile}. Reproduces the footer's avatar
|
|
5
|
+
* plus name and email lines (Expanded), or just the avatar circle (Collapsed),
|
|
6
|
+
* so it occupies the same footprint while the user data is being fetched. Fully
|
|
7
|
+
* theme-aware.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DrawerProfileSkeleton: React.FC<DrawerProfileSkeletonProps>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { SkeletonLoader } from '../UI';
|
|
4
|
+
import { DrawerSize } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors {@link DrawerProfile}'s clickable Row so the skeleton snaps in place:
|
|
7
|
+
* same 8px padding, gap and alignment as the profile footer's default (menu)
|
|
8
|
+
* usage.
|
|
9
|
+
*/
|
|
10
|
+
const Row = styled.div `
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
15
|
+
width: 100%;
|
|
16
|
+
padding: var(--spacing-tokens-size-in-px-spacing-spacing-md, 8px);
|
|
17
|
+
`;
|
|
18
|
+
const TextColumn = styled.div `
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: var(--spacing-tokens-size-in-px-spacing-spacing-xs, 4px);
|
|
22
|
+
min-width: 0;
|
|
23
|
+
`;
|
|
24
|
+
const RADIUS_XS = 'var(--spacing-tokens-size-in-px-radius-radius-xs, 4px)';
|
|
25
|
+
const RADIUS_FULL = 'var(--spacing-tokens-size-in-px-radius-radius-full, 999px)';
|
|
26
|
+
/**
|
|
27
|
+
* Loading placeholder for {@link DrawerProfile}. Reproduces the footer's avatar
|
|
28
|
+
* plus name and email lines (Expanded), or just the avatar circle (Collapsed),
|
|
29
|
+
* so it occupies the same footprint while the user data is being fetched. Fully
|
|
30
|
+
* theme-aware.
|
|
31
|
+
*/
|
|
32
|
+
export const DrawerProfileSkeleton = ({ size = DrawerSize.Expanded, className, style, testId, }) => {
|
|
33
|
+
if (size === DrawerSize.Collapsed) {
|
|
34
|
+
return (_jsx(SkeletonLoader, { width: "32px", height: "32px", borderRadius: RADIUS_FULL, style: style }));
|
|
35
|
+
}
|
|
36
|
+
return (_jsxs(Row, { className: className, style: style, "data-testid": testId, children: [_jsx(SkeletonLoader, { width: "32px", height: "32px", borderRadius: RADIUS_FULL }), _jsxs(TextColumn, { children: [_jsx(SkeletonLoader, { width: "96px", height: "14px", borderRadius: RADIUS_XS }), _jsx(SkeletonLoader, { width: "128px", height: "12px", borderRadius: RADIUS_XS })] })] }));
|
|
37
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DrawerProfileSkeleton } from './DrawerProfileSkeleton';
|
|
3
|
+
declare const meta: Meta<typeof DrawerProfileSkeleton>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof DrawerProfileSkeleton>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Collapsed: Story;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { DrawerProfileSkeleton } from './DrawerProfileSkeleton';
|
|
3
|
+
import { DrawerSize } from './types';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Components/Drawer/DrawerProfileSkeleton',
|
|
6
|
+
component: DrawerProfileSkeleton,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
design: {
|
|
10
|
+
type: 'figspec',
|
|
11
|
+
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=6940-28398',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
tags: ['autodocs'],
|
|
15
|
+
argTypes: {
|
|
16
|
+
size: {
|
|
17
|
+
control: 'inline-radio',
|
|
18
|
+
options: Object.values(DrawerSize),
|
|
19
|
+
table: { defaultValue: { summary: 'Expanded' } },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
args: {
|
|
23
|
+
size: DrawerSize.Expanded,
|
|
24
|
+
},
|
|
25
|
+
decorators: [
|
|
26
|
+
(Story) => (_jsx("div", { style: {
|
|
27
|
+
width: 230,
|
|
28
|
+
padding: 16,
|
|
29
|
+
backgroundColor: 'var(--color-background-bg-page-contrast)',
|
|
30
|
+
}, children: _jsx(Story, {}) })),
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
export default meta;
|
|
34
|
+
export const Default = {};
|
|
35
|
+
export const Collapsed = {
|
|
36
|
+
args: { size: DrawerSize.Collapsed },
|
|
37
|
+
};
|
|
@@ -124,6 +124,16 @@ export interface DrawerProfileProps {
|
|
|
124
124
|
style?: CSSProperties;
|
|
125
125
|
testId?: string;
|
|
126
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Props for the {@link DrawerProfileSkeleton} loading placeholder.
|
|
129
|
+
*/
|
|
130
|
+
export interface DrawerProfileSkeletonProps {
|
|
131
|
+
/** Expanded (avatar + text lines) or Collapsed (avatar circle only). */
|
|
132
|
+
size?: DrawerSize;
|
|
133
|
+
className?: string;
|
|
134
|
+
style?: CSSProperties;
|
|
135
|
+
testId?: string;
|
|
136
|
+
}
|
|
127
137
|
/**
|
|
128
138
|
* A single entry in the {@link Drawer}'s `navItems` list.
|
|
129
139
|
*/
|
|
@@ -164,6 +174,8 @@ export interface DrawerProps {
|
|
|
164
174
|
creditsLoading?: boolean;
|
|
165
175
|
/** User profile footer configuration. Omit to hide the footer. */
|
|
166
176
|
profile?: Omit<DrawerProfileProps, 'size' | 'className' | 'style'>;
|
|
177
|
+
/** Render the profile footer as a loading skeleton instead of its content. */
|
|
178
|
+
profileLoading?: boolean;
|
|
167
179
|
/** Logo appearance overrides. */
|
|
168
180
|
logo?: {
|
|
169
181
|
color?: string;
|