@beydesign/storybook 0.1.19 → 0.1.20

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/App.js CHANGED
@@ -1,10 +1,109 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import reactLogo from './assets/react.svg';
4
- import viteLogo from '/vite.svg';
3
+ import { EntityCard, EntityCardSkeleton } from './stories/EntityCard';
5
4
  import './App.css';
5
+ const avatars = [
6
+ {
7
+ id: 'nelly',
8
+ name: 'Nelly',
9
+ image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?fm=jpg&q=60&w=600&ixlib=rb-4.0.3',
10
+ },
11
+ {
12
+ id: 'ava',
13
+ name: 'Ava',
14
+ image: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?fm=jpg&q=60&w=600&ixlib=rb-4.0.3',
15
+ },
16
+ {
17
+ id: 'leo',
18
+ name: 'Leo',
19
+ image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?fm=jpg&q=60&w=600&ixlib=rb-4.0.3',
20
+ },
21
+ {
22
+ id: 'maya',
23
+ name: 'Maya Customer Support',
24
+ image: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?fm=jpg&q=60&w=600&ixlib=rb-4.0.3',
25
+ },
26
+ {
27
+ id: 'no-image',
28
+ name: 'No Image',
29
+ image: undefined,
30
+ },
31
+ ];
32
+ const agentMenuItems = [
33
+ {
34
+ label: 'Conversation Link',
35
+ icon: 'ShareNetwork',
36
+ onClick: () => { },
37
+ },
38
+ { label: 'Copy Agent ID', icon: 'CopySimple', onClick: () => { } },
39
+ { label: 'Embed', icon: 'Code', onClick: () => { } },
40
+ {
41
+ label: 'Agent Details',
42
+ icon: 'IdentificationCard',
43
+ onClick: () => { },
44
+ },
45
+ { label: 'Duplicate', icon: 'Copy', onClick: () => { } },
46
+ {
47
+ label: 'Delete',
48
+ icon: 'Trash',
49
+ onClick: () => { },
50
+ destructive: true,
51
+ },
52
+ ];
6
53
  function App() {
7
- const [count, setCount] = useState(0);
8
- return (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("a", { href: "https://vite.dev", target: "_blank", children: _jsx("img", { src: viteLogo, className: "logo", alt: "Vite logo" }) }), _jsx("a", { href: "https://react.dev", target: "_blank", children: _jsx("img", { src: reactLogo, className: "logo react", alt: "React logo" }) })] }), _jsx("h1", { children: "Vite + React" }), _jsxs("div", { className: "card", children: [_jsxs("button", { onClick: () => setCount((count) => count + 1), children: ["count is ", count] }), _jsxs("p", { children: ["Edit ", _jsx("code", { children: "src/App.tsx" }), " and save to test HMR"] })] }), _jsx("p", { className: "read-the-docs", children: "Click on the Vite and React logos to learn more" })] }));
54
+ const [loading, setLoading] = useState(false);
55
+ return (_jsxs("div", { style: { padding: '32px' }, children: [_jsx("button", { type: "button", onClick: () => setLoading((prev) => !prev), style: {
56
+ fontFamily: 'Figtree, sans-serif',
57
+ marginBottom: '24px',
58
+ padding: '8px 16px',
59
+ borderRadius: '6px',
60
+ border: '1px solid var(--colors-light-border-border-component)',
61
+ background: 'var(--colors-light-background-bg-white)',
62
+ color: 'var(--colors-light-text-text-title)',
63
+ cursor: 'pointer',
64
+ }, children: loading ? 'Show loaded cards' : 'Show loading skeletons' }), _jsx("h2", { style: {
65
+ fontFamily: 'Figtree, sans-serif',
66
+ color: 'var(--colors-light-text-text-title)',
67
+ marginBottom: '4px',
68
+ }, children: "Explore our Avatar Library" }), _jsx("p", { style: {
69
+ fontFamily: 'Figtree, sans-serif',
70
+ color: 'var(--colors-light-text-text-subtle)',
71
+ marginBottom: '24px',
72
+ }, children: "Select the perfect studio-quality digital human to make your interactions feel personal." }), _jsx("div", { style: {
73
+ display: 'flex',
74
+ flexWrap: 'wrap',
75
+ gap: '16px',
76
+ }, children: avatars.map((avatar) => loading ? (_jsx(EntityCardSkeleton, { view: "avatar", showDescription: true }, avatar.id)) : (_jsx(EntityCard, { name: avatar.name, image: avatar.image, onPreview: () => console.log('Preview', avatar.name), showMenu: true, menuItems: [
77
+ {
78
+ label: 'Copy Avatar ID',
79
+ icon: 'Copy',
80
+ onClick: () => console.log('Copy', avatar.id),
81
+ },
82
+ {
83
+ label: 'Create Agent',
84
+ icon: 'UserCirclePlus',
85
+ onClick: () => console.log('Create Agent', avatar.name),
86
+ },
87
+ {
88
+ label: 'Delete',
89
+ icon: 'Trash',
90
+ onClick: () => console.log('Delete', avatar.name),
91
+ destructive: true,
92
+ },
93
+ ], description: "daijdaij pa oapopao ao opaop op", showDescription: true }, avatar.id))) }), _jsx("h2", { style: {
94
+ fontFamily: 'Figtree, sans-serif',
95
+ color: 'var(--colors-light-text-text-title)',
96
+ margin: '40px 0 4px',
97
+ }, children: "Explore our Agent library" }), _jsx("p", { style: {
98
+ fontFamily: 'Figtree, sans-serif',
99
+ color: 'var(--colors-light-text-text-subtle)',
100
+ marginBottom: '24px',
101
+ }, children: "Your active agents \u2014 hover a card to join a live conversation." }), _jsx("div", { style: {
102
+ display: 'flex',
103
+ flexWrap: 'wrap',
104
+ gap: '16px',
105
+ }, children: avatars
106
+ .slice(0, 4)
107
+ .map((avatar) => loading ? (_jsx(EntityCardSkeleton, { view: "agent" }, `agent-${avatar.id}`)) : (_jsx(EntityCard, { view: "agent", name: `${avatar.name} Customer Support`, image: avatar.image, showStatusBadge: true, statusBadgeText: "Active", onPreview: () => console.log('Join', avatar.name), previewButtonText: "Join", previewIcon: "VideoCamera", showMenu: true, menuItems: agentMenuItems }, `agent-${avatar.id}`))) })] }));
9
108
  }
10
109
  export default App;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './stories/UI';
2
2
  export * from './stories/Agent';
3
+ export * from './stories/EntityCard';
3
4
  export * from './stories/Form';
4
5
  export * from './stories/Buttons';
5
6
  export * from './stories/Typography';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './stories/UI';
2
2
  export * from './stories/Agent';
3
+ export * from './stories/EntityCard';
3
4
  export * from './stories/Form';
4
5
  export * from './stories/Buttons';
5
6
  export * from './stories/Typography';
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { EntityCardProps } from './types';
3
+ export declare const EntityCard: React.FC<EntityCardProps>;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box } from '@mui/material';
4
+ import { Typography, TypographySize, TypographyWeight } from '../Typography';
5
+ import { Menu, Badge, BadgeColor, BadgeSize } from '../UI';
6
+ import { MainButton, ButtonHierarchy, ButtonSize, ButtonDisplayMode, } from '../Buttons';
7
+ import { UserCircle } from '@phosphor-icons/react';
8
+ export const EntityCard = ({ view = 'avatar', name, image, description = '', showDescription = false, onPreview, previewButtonText, previewIcon = 'Play', showStatusBadge = false, statusBadgeText = '', statusBadgeColor = BadgeColor.Green, menuItems = [], showMenu = false, width, }) => {
9
+ const [hovered, setHovered] = useState(false);
10
+ const [imageError, setImageError] = useState(false);
11
+ const isAgent = view === 'agent';
12
+ const cardWidth = width ?? (isAgent ? '280px' : '218px');
13
+ const imageAspectRatio = isAgent ? '1 / 1' : '203 / 264';
14
+ const entityKey = name?.toLowerCase()?.replace(/\s+/g, '-');
15
+ const hasMenu = showMenu && menuItems.length > 0;
16
+ const showActions = hovered && (!!onPreview || hasMenu);
17
+ const showBadge = showStatusBadge && !!statusBadgeText;
18
+ return (_jsxs(Box, { width: cardWidth, display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', bgcolor: 'var(--colors-light-background-bg-card-highlight)', border: '1px solid var(--colors-light-border-border-subtle)', boxSizing: 'border-box', overflow: 'hidden', "data-testid": `${entityKey}-entity-card`, children: [_jsxs(Box, { position: 'relative', width: '100%', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', overflow: 'hidden', sx: { aspectRatio: imageAspectRatio }, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [image && !imageError ? (_jsx("img", { src: image, alt: name, width: '100%', height: '100%', style: { objectFit: 'cover', height: '100%', width: '100%' }, onError: () => setImageError(true) })) : (_jsx(Box, { width: '100%', height: '100%', bgcolor: 'var(--colors-light-background-bg-element)', display: 'flex', justifyContent: 'center', alignItems: 'center', children: _jsx(UserCircle, { size: 74, weight: 'thin', color: 'var(--colors-light-text-text-subtle)' }) })), _jsx(Box, { position: 'absolute', left: 0, right: 0, bottom: 0, display: 'flex', alignItems: 'center', padding: '24px 12px 12px', sx: {
19
+ backgroundImage: 'linear-gradient(rgba(45, 38, 55, 0) 0%, rgba(45, 38, 55, 0.16) 34%, rgba(45, 38, 55, 0.64) 100%)',
20
+ }, children: _jsx(Typography, { size: TypographySize.HeadingXS, weight: TypographyWeight.SemiBold, color: 'var(--colors-light-text-text-white)', textStyle: { wordBreak: 'break-word' }, children: name }) }), showBadge && (_jsx(Box, { position: 'absolute', top: '8px', left: '8px', sx: { zIndex: 2 }, children: _jsx(Badge, { text: statusBadgeText, color: statusBadgeColor, size: BadgeSize.md, showIcon: true, icon: 'Circle', iconWeight: 'fill', iconSize: '8px', iconColor: 'var(--colors-light-background-bg-success)' }) })), showActions && (_jsxs(Box, { position: 'absolute', top: '8px', right: '8px', display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', sx: { zIndex: 2 }, children: [onPreview &&
21
+ (previewButtonText ? (_jsx(MainButton, { text: previewButtonText, showLeadingIcon: true, leadingIcon: previewIcon, hierarchy: ButtonHierarchy.Primary, size: ButtonSize.sm, onClick: onPreview, testId: `${entityKey}-preview-button` })) : (_jsx(MainButton, { displayIcon: previewIcon, displayIconMode: ButtonDisplayMode.Only, hierarchy: ButtonHierarchy.Primary, size: ButtonSize.sm, onClick: onPreview, testId: `${entityKey}-preview-button` }))), hasMenu && (_jsx(Menu, { items: menuItems, testKey: entityKey, size: ButtonSize.sm }))] }))] }), showDescription && description && (_jsx(Box, { display: 'flex', alignItems: 'center', padding: '0 12px', width: '100%', boxSizing: 'border-box', children: _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Regular, color: 'var(--colors-light-text-text-label)', textStyle: { wordBreak: 'break-word' }, children: description }) }))] }));
22
+ };
@@ -0,0 +1,10 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { EntityCard } from './EntityCard';
3
+ declare const meta: Meta<typeof EntityCard>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof EntityCard>;
6
+ export declare const Default: Story;
7
+ export declare const AgentView: Story;
8
+ export declare const WithDescription: Story;
9
+ export declare const NoActions: Story;
10
+ export declare const NoImage: Story;
@@ -0,0 +1,187 @@
1
+ import { EntityCard } from './EntityCard';
2
+ import { BadgeColor } from '../UI';
3
+ const meta = {
4
+ title: 'Design System/Components/EntityCard/EntityCard',
5
+ component: EntityCard,
6
+ parameters: {
7
+ layout: 'centered',
8
+ design: {
9
+ type: 'figspec',
10
+ url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=6916-20176',
11
+ },
12
+ },
13
+ tags: ['autodocs'],
14
+ argTypes: {
15
+ view: {
16
+ control: 'select',
17
+ options: ['avatar', 'agent'],
18
+ description: 'View variant — drives default width and image aspect ratio',
19
+ table: {
20
+ type: { summary: "'avatar' | 'agent'" },
21
+ defaultValue: { summary: 'avatar' },
22
+ },
23
+ },
24
+ name: {
25
+ control: 'text',
26
+ description: 'Display name shown over the image',
27
+ table: { type: { summary: 'string' } },
28
+ },
29
+ image: {
30
+ control: 'text',
31
+ description: 'Image url',
32
+ table: { type: { summary: 'string' } },
33
+ },
34
+ description: {
35
+ control: 'text',
36
+ description: 'Optional description shown below the image',
37
+ table: { type: { summary: 'string' } },
38
+ },
39
+ showDescription: {
40
+ control: 'boolean',
41
+ description: 'Whether to show the description',
42
+ table: { type: { summary: 'boolean' } },
43
+ },
44
+ showMenu: {
45
+ control: 'boolean',
46
+ description: 'Whether to show the menu on hover',
47
+ table: { type: { summary: 'boolean' } },
48
+ },
49
+ onPreview: {
50
+ description: 'Preview handler — renders the action button on hover',
51
+ table: { type: { summary: 'function' } },
52
+ },
53
+ previewButtonText: {
54
+ control: 'text',
55
+ description: 'Label for the action button; when set it renders text + icon, otherwise icon-only',
56
+ table: { type: { summary: 'string' } },
57
+ },
58
+ previewIcon: {
59
+ control: 'text',
60
+ description: 'Icon for the action button',
61
+ table: {
62
+ type: { summary: 'IconName' },
63
+ defaultValue: { summary: 'Play' },
64
+ },
65
+ },
66
+ showStatusBadge: {
67
+ control: 'boolean',
68
+ description: 'Whether to show the status badge (top-left)',
69
+ table: { type: { summary: 'boolean' } },
70
+ },
71
+ statusBadgeText: {
72
+ control: 'text',
73
+ description: 'Status badge text (e.g. "Active")',
74
+ table: { type: { summary: 'string' } },
75
+ },
76
+ statusBadgeColor: {
77
+ control: 'select',
78
+ options: Object.values(BadgeColor),
79
+ description: 'Status badge color',
80
+ table: {
81
+ type: { summary: 'BadgeColor' },
82
+ defaultValue: { summary: BadgeColor.Green },
83
+ },
84
+ },
85
+ menuItems: {
86
+ description: 'Menu items for the dropdown',
87
+ table: { type: { summary: 'array' } },
88
+ },
89
+ width: {
90
+ control: 'text',
91
+ description: 'Width of the card',
92
+ table: {
93
+ type: { summary: 'string | number' },
94
+ defaultValue: { summary: '218px' },
95
+ },
96
+ },
97
+ },
98
+ };
99
+ export default meta;
100
+ const avatarImage = 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?fm=jpg&q=60&w=600&ixlib=rb-4.0.3';
101
+ export const Default = {
102
+ args: {
103
+ name: 'Nelly',
104
+ image: avatarImage,
105
+ onPreview: () => { },
106
+ showMenu: true,
107
+ menuItems: [
108
+ { label: 'Copy Avatar ID', icon: 'Copy', onClick: () => { } },
109
+ { label: 'Create Agent', icon: 'UserCirclePlus', onClick: () => { } },
110
+ { label: 'Delete', icon: 'Trash', onClick: () => { }, destructive: true },
111
+ ],
112
+ },
113
+ };
114
+ export const AgentView = {
115
+ args: {
116
+ view: 'agent',
117
+ name: 'Nelly Customer Support',
118
+ image: avatarImage,
119
+ onPreview: () => { },
120
+ previewButtonText: 'Join',
121
+ previewIcon: 'VideoCamera',
122
+ showStatusBadge: true,
123
+ statusBadgeText: 'Active',
124
+ showMenu: true,
125
+ menuItems: [
126
+ { label: 'Conversation Link', icon: 'ShareNetwork', onClick: () => { } },
127
+ { label: 'Copy Agent ID', icon: 'CopySimple', onClick: () => { } },
128
+ { label: 'Embed', icon: 'Code', onClick: () => { } },
129
+ { label: 'Agent Details', icon: 'IdentificationCard', onClick: () => { } },
130
+ { label: 'Duplicate', icon: 'Copy', onClick: () => { } },
131
+ { label: 'Delete', icon: 'Trash', onClick: () => { }, destructive: true },
132
+ ],
133
+ },
134
+ parameters: {
135
+ design: {
136
+ type: 'figspec',
137
+ url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=6919-20599',
138
+ },
139
+ docs: {
140
+ description: {
141
+ story: 'The agent view — wider, square image, a persistent status badge, and a labelled "Join" action. Hover to reveal the action row.',
142
+ },
143
+ },
144
+ },
145
+ };
146
+ export const WithDescription = {
147
+ args: {
148
+ ...Default.args,
149
+ name: 'Nelly Customer Support',
150
+ showDescription: true,
151
+ description: 'Support description',
152
+ },
153
+ parameters: {
154
+ docs: {
155
+ description: {
156
+ story: 'Avatar card with an optional description below the image.',
157
+ },
158
+ },
159
+ },
160
+ };
161
+ export const NoActions = {
162
+ args: {
163
+ name: 'Nelly',
164
+ image: avatarImage,
165
+ },
166
+ parameters: {
167
+ docs: {
168
+ description: {
169
+ story: 'A read-only avatar card without preview or menu actions on hover.',
170
+ },
171
+ },
172
+ },
173
+ };
174
+ export const NoImage = {
175
+ args: {
176
+ ...Default.args,
177
+ name: 'No Image',
178
+ image: undefined,
179
+ },
180
+ parameters: {
181
+ docs: {
182
+ description: {
183
+ story: 'Fallback placeholder shown when no image is provided or it fails to load.',
184
+ },
185
+ },
186
+ },
187
+ };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { EntityCardSkeletonProps } from './types';
3
+ export declare const EntityCardSkeleton: React.FC<EntityCardSkeletonProps>;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from '@mui/material';
3
+ import { SkeletonLoader } from '../UI';
4
+ export const EntityCardSkeleton = ({ view = 'avatar', width, showDescription = false, style, }) => {
5
+ const isAgent = view === 'agent';
6
+ const cardWidth = width ?? (isAgent ? '280px' : '218px');
7
+ const imageAspectRatio = isAgent ? '1 / 1' : '203 / 264';
8
+ return (_jsxs(Box, { width: cardWidth, display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', bgcolor: 'var(--colors-light-background-bg-card-highlight)', border: '1px solid var(--colors-light-border-border-subtle)', boxSizing: 'border-box', overflow: 'hidden', style: style, children: [_jsx(Box, { width: '100%', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', overflow: 'hidden', sx: { aspectRatio: imageAspectRatio }, children: _jsx(SkeletonLoader, {}) }), showDescription && (_jsxs(Box, { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', padding: '0 12px', width: '100%', boxSizing: 'border-box', children: [_jsx(SkeletonLoader, { width: '100%', height: '16px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' }), _jsx(SkeletonLoader, { width: '70%', height: '16px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' })] }))] }));
9
+ };
@@ -0,0 +1,10 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { EntityCardSkeleton } from './EntityCardSkeleton';
3
+ declare const meta: Meta<typeof EntityCardSkeleton>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof EntityCardSkeleton>;
6
+ export declare const Avatar: Story;
7
+ export declare const AvatarWithDescription: Story;
8
+ export declare const Agent: Story;
9
+ export declare const Grid: Story;
10
+ export declare const LoadingState: Story;
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from '@mui/material';
3
+ import { EntityCardSkeleton } from './EntityCardSkeleton';
4
+ const meta = {
5
+ title: 'Design System/Components/EntityCard/EntityCardSkeleton',
6
+ component: EntityCardSkeleton,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ view: {
13
+ control: 'select',
14
+ options: ['avatar', 'agent'],
15
+ description: 'View variant — drives default width and image aspect ratio',
16
+ table: {
17
+ type: { summary: "'avatar' | 'agent'" },
18
+ defaultValue: { summary: 'avatar' },
19
+ },
20
+ },
21
+ width: {
22
+ control: 'text',
23
+ description: 'Width of the card (overrides the view default)',
24
+ table: {
25
+ type: { summary: 'string | number' },
26
+ defaultValue: { summary: '218px (avatar) / 280px (agent)' },
27
+ },
28
+ },
29
+ showDescription: {
30
+ control: 'boolean',
31
+ description: 'Show the description placeholder',
32
+ table: {
33
+ type: { summary: 'boolean' },
34
+ defaultValue: { summary: 'false' },
35
+ },
36
+ },
37
+ style: {
38
+ control: 'object',
39
+ description: 'Custom style for the skeleton',
40
+ table: {
41
+ type: { summary: 'React.CSSProperties' },
42
+ defaultValue: { summary: 'undefined' },
43
+ },
44
+ },
45
+ },
46
+ };
47
+ export default meta;
48
+ export const Avatar = {
49
+ args: {
50
+ view: 'avatar',
51
+ },
52
+ };
53
+ export const AvatarWithDescription = {
54
+ args: {
55
+ view: 'avatar',
56
+ showDescription: true,
57
+ },
58
+ };
59
+ export const Agent = {
60
+ args: {
61
+ view: 'agent',
62
+ },
63
+ };
64
+ export const Grid = {
65
+ render: () => (_jsxs(Box, { display: "flex", flexWrap: "wrap", gap: 2, children: [_jsx(EntityCardSkeleton, { view: "avatar" }), _jsx(EntityCardSkeleton, { view: "avatar", showDescription: true }), _jsx(EntityCardSkeleton, { view: "agent" })] })),
66
+ };
67
+ export const LoadingState = {
68
+ render: () => (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 3, children: [_jsxs(Box, { children: [_jsx("h3", { children: "Loading state example" }), _jsx("p", { children: "How a row of entity cards appears while data is loading." })] }), _jsx(Box, { display: "flex", flexWrap: "wrap", gap: 2, children: Array(5)
69
+ .fill(0)
70
+ .map((_, index) => (_jsx(EntityCardSkeleton, { view: "avatar" }, index))) }), _jsx(Box, { display: "flex", flexWrap: "wrap", gap: 2, children: Array(4)
71
+ .fill(0)
72
+ .map((_, index) => (_jsx(EntityCardSkeleton, { view: "agent" }, index))) })] })),
73
+ };
@@ -0,0 +1,3 @@
1
+ export * from './EntityCard';
2
+ export * from './EntityCardSkeleton';
3
+ export * from './types';
@@ -0,0 +1,3 @@
1
+ export * from './EntityCard';
2
+ export * from './EntityCardSkeleton';
3
+ export * from './types';
@@ -0,0 +1,54 @@
1
+ import { MenuItemProps, BadgeColor } from '../UI';
2
+ import { IconName } from '../../utils';
3
+ /**
4
+ * Entity card view variants.
5
+ * - `avatar`: portrait avatar tile (icon-only preview action)
6
+ * - `agent`: wider, square agent tile (labelled action + status badge)
7
+ */
8
+ export type EntityCardView = 'avatar' | 'agent';
9
+ /**
10
+ * Entity card component props
11
+ */
12
+ export interface EntityCardProps {
13
+ /** View variant — drives default width and image aspect ratio */
14
+ view?: EntityCardView;
15
+ /** Display name shown over the image */
16
+ name: string;
17
+ /** Image url */
18
+ image?: string;
19
+ /** Optional description shown below the image */
20
+ description?: string;
21
+ /** Whether to show the description */
22
+ showDescription?: boolean;
23
+ /** Preview handler — renders the action button on hover */
24
+ onPreview?: () => void;
25
+ /** Label for the action button; when set it renders text + icon, otherwise icon-only */
26
+ previewButtonText?: string;
27
+ /** Icon for the action button (defaults to `Play`) */
28
+ previewIcon?: IconName;
29
+ /** Whether to show the status badge (top-left) */
30
+ showStatusBadge?: boolean;
31
+ /** Status badge text (e.g. "Active") */
32
+ statusBadgeText?: string;
33
+ /** Status badge color (defaults to Green) */
34
+ statusBadgeColor?: BadgeColor;
35
+ /** Menu items for the dropdown — renders the menu button on hover */
36
+ menuItems?: MenuItemProps[];
37
+ /** Whether to show the menu */
38
+ showMenu?: boolean;
39
+ /** Width of the card (overrides the view default) */
40
+ width?: string | number;
41
+ }
42
+ /**
43
+ * Entity card skeleton props
44
+ */
45
+ export interface EntityCardSkeletonProps {
46
+ /** View variant — drives default width and image aspect ratio */
47
+ view?: EntityCardView;
48
+ /** Width of the card (overrides the view default) */
49
+ width?: string | number;
50
+ /** Show the description placeholder */
51
+ showDescription?: boolean;
52
+ /** Custom style for the skeleton */
53
+ style?: React.CSSProperties;
54
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { MenuItem as MuiMenuItem, Menu as MuiMenu, } from '@mui/material';
3
3
  import { Fragment, useState } from 'react';
4
- import { MainButton, ButtonDisplayMode, ButtonHierarchy, ButtonType, } from '../Buttons';
4
+ import { MainButton, ButtonDisplayMode, ButtonHierarchy, ButtonType, ButtonSize, } from '../Buttons';
5
5
  import { Typography, TypographySize, TypographyWeight } from '../Typography';
6
6
  import { getIconComponent } from '../../utils';
7
- export const Menu = ({ icon = 'DotsThree', items, style, testKey, }) => {
7
+ export const Menu = ({ icon = 'DotsThree', items, style, testKey, size = ButtonSize.xl, hierarchy = ButtonHierarchy.Secondary, }) => {
8
8
  const [anchorEl, setAnchorEl] = useState(null);
9
9
  const open = Boolean(anchorEl);
10
10
  const handleClick = (event) => {
@@ -24,7 +24,7 @@ export const Menu = ({ icon = 'DotsThree', items, style, testKey, }) => {
24
24
  return 'var(--colors-light-text-text-error)';
25
25
  return 'var(--colors-light-text-text-title)';
26
26
  };
27
- return (_jsxs(Fragment, { children: [_jsx(MainButton, { displayIcon: icon, onClick: handleClick, type: ButtonType.Button, displayIconMode: ButtonDisplayMode.Only, hierarchy: ButtonHierarchy.Secondary, style: style, testId: `${testKey}-menu-button` }), _jsx(MuiMenu, { id: "basic-menu", "data-testid": `${testKey}-menu`, anchorEl: anchorEl, open: open, onClose: handleClose, MenuListProps: {
27
+ return (_jsxs(Fragment, { children: [_jsx(MainButton, { displayIcon: icon, onClick: handleClick, type: ButtonType.Button, displayIconMode: ButtonDisplayMode.Only, hierarchy: hierarchy, size: size, style: style, testId: `${testKey}-menu-button` }), _jsx(MuiMenu, { id: "basic-menu", "data-testid": `${testKey}-menu`, anchorEl: anchorEl, open: open, onClose: handleClose, MenuListProps: {
28
28
  'aria-labelledby': 'basic-button',
29
29
  style: {
30
30
  padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
@@ -4,3 +4,4 @@ declare const meta: Meta<typeof Menu>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
6
6
  export declare const Default: Story;
7
+ export declare const Small: Story;
@@ -1,4 +1,5 @@
1
1
  import { Menu } from './Menu';
2
+ import { ButtonSize, ButtonHierarchy } from '../Buttons';
2
3
  const meta = {
3
4
  title: 'Design System/Components/UI/Menu',
4
5
  component: Menu,
@@ -34,6 +35,24 @@ const meta = {
34
35
  type: { summary: 'CSSProperties' },
35
36
  },
36
37
  },
38
+ size: {
39
+ control: 'select',
40
+ options: Object.values(ButtonSize),
41
+ description: 'Size of the trigger button',
42
+ table: {
43
+ type: { summary: 'ButtonSize' },
44
+ defaultValue: { summary: ButtonSize.xl },
45
+ },
46
+ },
47
+ hierarchy: {
48
+ control: 'select',
49
+ options: Object.values(ButtonHierarchy),
50
+ description: 'Hierarchy of the trigger button',
51
+ table: {
52
+ type: { summary: 'ButtonHierarchy' },
53
+ defaultValue: { summary: ButtonHierarchy.Secondary },
54
+ },
55
+ },
37
56
  },
38
57
  };
39
58
  export default meta;
@@ -46,3 +65,16 @@ export const Default = {
46
65
  ],
47
66
  },
48
67
  };
68
+ export const Small = {
69
+ args: {
70
+ ...Default.args,
71
+ size: ButtonSize.sm,
72
+ },
73
+ parameters: {
74
+ docs: {
75
+ description: {
76
+ story: 'The trigger button rendered at the small size, used in compact contexts such as the EntityCard action row.',
77
+ },
78
+ },
79
+ },
80
+ };
@@ -1,5 +1,6 @@
1
1
  import { Theme, SxProps } from '@mui/material';
2
2
  import { IconName } from '../../utils';
3
+ import { ButtonSize, ButtonHierarchy } from '../Buttons';
3
4
  /**
4
5
  * Badge size variants
5
6
  */
@@ -163,6 +164,10 @@ export type MenuProps = {
163
164
  style?: React.CSSProperties;
164
165
  /** Test key */
165
166
  testKey?: string;
167
+ /** Size of the trigger button */
168
+ size?: ButtonSize;
169
+ /** Hierarchy of the trigger button */
170
+ hierarchy?: ButtonHierarchy;
166
171
  };
167
172
  /**
168
173
  * Progress indicator mode variants
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@beydesign/storybook",
3
3
  "private": false,
4
- "version": "0.1.19",
4
+ "version": "0.1.20",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",