@beydesign/storybook 0.2.19 → 0.2.21

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 CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './stories/UI';
2
2
  export * from './stories/Agent';
3
3
  export * from './stories/EntityCard';
4
+ export * from './stories/VideoCard';
4
5
  export * from './stories/PlanCard';
5
6
  export * from './stories/Form';
6
7
  export * from './stories/Buttons';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './stories/UI';
2
2
  export * from './stories/Agent';
3
3
  export * from './stories/EntityCard';
4
+ export * from './stories/VideoCard';
4
5
  export * from './stories/PlanCard';
5
6
  export * from './stories/Form';
6
7
  export * from './stories/Buttons';
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { VideoCardProps } from './types';
3
+ export declare const VideoCard: React.FC<VideoCardProps>;
@@ -0,0 +1,47 @@
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 { keyframes } from '@emotion/react';
5
+ import { FilmSlate } from '@phosphor-icons/react';
6
+ import { Typography, TypographySize, TypographyWeight } from '../Typography';
7
+ import { Menu } from '../UI';
8
+ import { MainButton, ButtonHierarchy, ButtonSize, ButtonDisplayMode, } from '../Buttons';
9
+ const spin = keyframes `
10
+ from { transform: rotate(0deg); }
11
+ to { transform: rotate(360deg); }
12
+ `;
13
+ const SPINNER_SIZE = 28;
14
+ const SPINNER_BARS = 12;
15
+ /** A spoked activity spinner that rotates continuously. */
16
+ const Spinner = () => (_jsx(Box, { position: 'relative', width: `${SPINNER_SIZE}px`, height: `${SPINNER_SIZE}px`, sx: { animation: `${spin} 1s steps(${SPINNER_BARS}, end) infinite` }, children: Array.from({ length: SPINNER_BARS }).map((_, i) => (_jsx(Box, { position: 'absolute', top: 0, left: '50%', width: '2px', height: `${SPINNER_SIZE / 2}px`, borderRadius: '2px', bgcolor: 'var(--color-text-text-white)', sx: {
17
+ transform: `translateX(-50%) rotate(${i * (360 / SPINNER_BARS)}deg)`,
18
+ transformOrigin: `50% ${SPINNER_SIZE / 2}px`,
19
+ opacity: 0.15 + (0.85 * i) / (SPINNER_BARS - 1),
20
+ } }, i))) }));
21
+ export const VideoCard = ({ name, image, date, aspectRatio = '16 / 9', processing = false, processingText = 'Processing…', onPreview, previewButtonText, previewIcon = 'Play', menuItems = [], showMenu = false, width, testId, }) => {
22
+ const [hovered, setHovered] = useState(false);
23
+ const [imageError, setImageError] = useState(false);
24
+ const entityKey = name?.toLowerCase()?.replace(/\s+/g, '-');
25
+ const hasMenu = showMenu && menuItems.length > 0;
26
+ const canPreview = !!onPreview && !processing;
27
+ const showActions = hovered && (canPreview || hasMenu);
28
+ const showImage = !!image && !imageError;
29
+ return (_jsx(Box, { width: width ?? '340px', display: 'flex', flexDirection: 'column', padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', bgcolor: hovered
30
+ ? 'var(--color-background-bg-card-highlight-hover)'
31
+ : 'var(--color-background-bg-card-highlight)', border: '1px solid var(--color-border-border-subtle)', boxSizing: 'border-box', overflow: 'hidden', onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), sx: { transition: 'background-color 0.15s ease-in-out' }, "data-testid": testId ?? `${entityKey}-video-card`, children: _jsxs(Box, { position: 'relative', width: '100%', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', overflow: 'hidden', sx: { aspectRatio }, children: [showImage ? (_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(--color-background-bg-element)', display: 'flex', justifyContent: 'center', alignItems: 'center', children: _jsx(FilmSlate, { size: 64, weight: 'thin', color: 'var(--color-text-text-subtle)' }) })), _jsx(Box, { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, sx: {
32
+ backgroundImage: 'linear-gradient(180deg, rgba(21, 0, 73, 0) 0%, rgba(72, 29, 180, 0.152) 16.76%, rgba(32, 13, 82, 0.36) 100%)',
33
+ opacity: hovered && !processing ? 1 : 0,
34
+ transition: 'opacity 0.15s ease-in-out',
35
+ pointerEvents: 'none',
36
+ } }), processing && (_jsxs(Box, { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', bgcolor: 'var(--color-background-bg-overlay-2)', sx: { zIndex: 1 }, children: [_jsx(Spinner, {}), _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.SemiBold, color: 'var(--color-text-text-white)', children: processingText })] })), showActions && (_jsxs(Box, { position: 'absolute', top: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', right: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', sx: { zIndex: 3 }, children: [canPreview &&
37
+ (previewButtonText ? (_jsx(MainButton, { text: previewButtonText, showLeadingIcon: true, leadingIcon: previewIcon, iconWeight: 'fill', hierarchy: ButtonHierarchy.SecondaryTransparent, size: ButtonSize.sm, onClick: onPreview, testId: `${entityKey}-preview-button` })) : (_jsx(MainButton, { displayIcon: previewIcon, displayIconMode: ButtonDisplayMode.Only, hierarchy: ButtonHierarchy.SecondaryTransparent, size: ButtonSize.sm, onClick: onPreview, testId: `${entityKey}-preview-button` }))), hasMenu && (_jsx(Menu, { items: menuItems, testKey: entityKey, size: ButtonSize.sm }))] })), _jsxs(Box, { position: 'absolute', left: 0, right: 0, bottom: 0, display: 'flex', flexDirection: 'row', alignItems: 'flex-end', justifyContent: 'space-between', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-3xl) var(--spacing-tokens-size-in-px-spacing-spacing-lg) var(--spacing-tokens-size-in-px-spacing-spacing-lg)', sx: {
38
+ zIndex: 2,
39
+ pointerEvents: 'none',
40
+ backgroundImage: 'linear-gradient(rgba(45, 38, 55, 0) 0%, rgba(45, 38, 55, 0.16) 34%, rgba(45, 38, 55, 0.64) 100%)',
41
+ }, children: [_jsx(Box, { minWidth: 0, flex: 1, children: _jsx(Typography, { text: name, title: name, size: TypographySize.HeadingXS, weight: TypographyWeight.SemiBold, color: 'var(--color-text-text-white)', textStyle: {
42
+ display: 'block',
43
+ overflow: 'hidden',
44
+ textOverflow: 'ellipsis',
45
+ whiteSpace: 'nowrap',
46
+ } }) }), date && (_jsx(Typography, { text: date, size: TypographySize.TextS, weight: TypographyWeight.Regular, color: 'var(--color-text-text-white)', textStyle: { whiteSpace: 'nowrap', flexShrink: 0, opacity: 0.8 } }))] })] }) }));
47
+ };
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { VideoCard } from './VideoCard';
3
+ declare const meta: Meta<typeof VideoCard>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof VideoCard>;
6
+ export declare const Ready: Story;
7
+ export declare const Processing: Story;
8
+ export declare const NoImage: Story;
9
+ export declare const NoActions: Story;
@@ -0,0 +1,156 @@
1
+ import { VideoCard } from './VideoCard';
2
+ const meta = {
3
+ title: 'Design System/Components/VideoCard/VideoCard',
4
+ component: VideoCard,
5
+ parameters: {
6
+ layout: 'centered',
7
+ },
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ name: {
11
+ control: 'text',
12
+ description: 'Video name shown over the bottom of the thumbnail',
13
+ table: { type: { summary: 'string' } },
14
+ },
15
+ image: {
16
+ control: 'text',
17
+ description: 'Thumbnail url (video preview frame, or the avatar image as a fallback)',
18
+ table: { type: { summary: 'string' } },
19
+ },
20
+ date: {
21
+ control: 'text',
22
+ description: 'Secondary text shown to the right of the name (e.g. created date)',
23
+ table: { type: { summary: 'string' } },
24
+ },
25
+ aspectRatio: {
26
+ control: 'text',
27
+ description: 'Aspect ratio of the thumbnail',
28
+ table: {
29
+ type: { summary: 'string' },
30
+ defaultValue: { summary: '16 / 9' },
31
+ },
32
+ },
33
+ processing: {
34
+ control: 'boolean',
35
+ description: 'Show the processing overlay (spinner + label)',
36
+ table: { type: { summary: 'boolean' } },
37
+ },
38
+ processingText: {
39
+ control: 'text',
40
+ description: 'Processing overlay label',
41
+ table: {
42
+ type: { summary: 'string' },
43
+ defaultValue: { summary: 'Processing…' },
44
+ },
45
+ },
46
+ onPreview: {
47
+ description: 'Preview handler — reveals the action button on hover and makes the thumbnail clickable',
48
+ table: { type: { summary: 'function' } },
49
+ },
50
+ previewButtonText: {
51
+ control: 'text',
52
+ description: 'Label for the preview action; when set it renders text + icon, otherwise icon-only',
53
+ table: { type: { summary: 'string' } },
54
+ },
55
+ previewIcon: {
56
+ control: 'text',
57
+ description: 'Icon for the preview action',
58
+ table: {
59
+ type: { summary: 'IconName' },
60
+ defaultValue: { summary: 'Play' },
61
+ },
62
+ },
63
+ showMenu: {
64
+ control: 'boolean',
65
+ description: 'Whether to show the menu on hover',
66
+ table: { type: { summary: 'boolean' } },
67
+ },
68
+ menuItems: {
69
+ description: 'Menu items for the dropdown',
70
+ table: { type: { summary: 'array' } },
71
+ },
72
+ width: {
73
+ control: 'text',
74
+ description: 'Width of the card',
75
+ table: {
76
+ type: { summary: 'string | number' },
77
+ defaultValue: { summary: '340px' },
78
+ },
79
+ },
80
+ },
81
+ };
82
+ export default meta;
83
+ const videoThumbnail = 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?fm=jpg&q=60&w=800&ixlib=rb-4.0.3';
84
+ const menuItems = [
85
+ {
86
+ label: 'Download Video',
87
+ icon: 'DownloadSimple',
88
+ onClick: () => { },
89
+ },
90
+ { label: 'Copy Video ID', icon: 'Copy', onClick: () => { } },
91
+ {
92
+ label: 'Delete Video',
93
+ icon: 'Trash',
94
+ onClick: () => { },
95
+ destructive: true,
96
+ },
97
+ ];
98
+ export const Ready = {
99
+ args: {
100
+ name: 'Product launch announcement',
101
+ image: videoThumbnail,
102
+ date: 'Jul 6, 2026',
103
+ onPreview: () => { },
104
+ previewButtonText: 'Preview',
105
+ showMenu: true,
106
+ menuItems,
107
+ },
108
+ };
109
+ export const Processing = {
110
+ args: {
111
+ name: 'Onboarding walkthrough',
112
+ image: videoThumbnail,
113
+ date: 'Jul 6, 2026',
114
+ processing: true,
115
+ showMenu: true,
116
+ menuItems: [menuItems[2]],
117
+ },
118
+ parameters: {
119
+ docs: {
120
+ description: {
121
+ story: 'While a video renders, a spinning indicator overlays the thumbnail and the preview action is disabled. The menu stays available.',
122
+ },
123
+ },
124
+ },
125
+ };
126
+ export const NoImage = {
127
+ args: {
128
+ name: 'Product launch announcement',
129
+ date: 'Jul 6, 2026',
130
+ onPreview: () => { },
131
+ previewButtonText: 'Preview',
132
+ showMenu: true,
133
+ menuItems,
134
+ },
135
+ parameters: {
136
+ docs: {
137
+ description: {
138
+ story: 'Fallback placeholder shown when no thumbnail is provided or it fails to load.',
139
+ },
140
+ },
141
+ },
142
+ };
143
+ export const NoActions = {
144
+ args: {
145
+ name: 'Product launch announcement',
146
+ image: videoThumbnail,
147
+ date: 'Jul 6, 2026',
148
+ },
149
+ parameters: {
150
+ docs: {
151
+ description: {
152
+ story: 'A read-only card without preview or menu actions on hover.',
153
+ },
154
+ },
155
+ },
156
+ };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { VideoCardSkeletonProps } from './types';
3
+ export declare const VideoCardSkeleton: React.FC<VideoCardSkeletonProps>;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box } from '@mui/material';
3
+ import { SkeletonLoader } from '../UI';
4
+ export const VideoCardSkeleton = ({ aspectRatio = '16 / 9', width, style, }) => {
5
+ return (_jsx(Box, { width: width ?? '340px', display: 'flex', flexDirection: 'column', padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', bgcolor: 'var(--color-background-bg-card-highlight)', border: '1px solid var(--color-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 }, children: _jsx(SkeletonLoader, {}) }) }));
6
+ };
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { VideoCardSkeleton } from './VideoCardSkeleton';
3
+ declare const meta: Meta<typeof VideoCardSkeleton>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof VideoCardSkeleton>;
6
+ export declare const Default: Story;
@@ -0,0 +1,31 @@
1
+ import { VideoCardSkeleton } from './VideoCardSkeleton';
2
+ const meta = {
3
+ title: 'Design System/Components/VideoCard/VideoCardSkeleton',
4
+ component: VideoCardSkeleton,
5
+ parameters: {
6
+ layout: 'centered',
7
+ },
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ aspectRatio: {
11
+ control: 'text',
12
+ description: 'Aspect ratio of the thumbnail placeholder',
13
+ table: {
14
+ type: { summary: 'string' },
15
+ defaultValue: { summary: '16 / 9' },
16
+ },
17
+ },
18
+ width: {
19
+ control: 'text',
20
+ description: 'Width of the card',
21
+ table: {
22
+ type: { summary: 'string | number' },
23
+ defaultValue: { summary: '340px' },
24
+ },
25
+ },
26
+ },
27
+ };
28
+ export default meta;
29
+ export const Default = {
30
+ args: {},
31
+ };
@@ -0,0 +1,3 @@
1
+ export * from './VideoCard';
2
+ export * from './VideoCardSkeleton';
3
+ export * from './types';
@@ -0,0 +1,3 @@
1
+ export * from './VideoCard';
2
+ export * from './VideoCardSkeleton';
3
+ export * from './types';
@@ -0,0 +1,47 @@
1
+ import { MenuItemProps } from '../UI';
2
+ import { IconName } from '../../utils';
3
+ /**
4
+ * VideoCard component props — a landscape (16:9 by default) media tile for a
5
+ * generated video. Shows a thumbnail with the video name and date overlaid on
6
+ * the bottom gradient, a hover reveal of the preview + menu actions, and an
7
+ * optional processing overlay.
8
+ */
9
+ export interface VideoCardProps {
10
+ /** Video name shown in the footer */
11
+ name: string;
12
+ /** Thumbnail url (video preview frame, or the avatar image as a fallback) */
13
+ image?: string;
14
+ /** Secondary text shown to the right of the name (e.g. formatted created date) */
15
+ date?: string;
16
+ /** Aspect ratio of the thumbnail. Defaults to `16 / 9` */
17
+ aspectRatio?: string;
18
+ /** Show the processing overlay (spinner + label) over the thumbnail */
19
+ processing?: boolean;
20
+ /** Processing overlay label. Defaults to "Processing…" */
21
+ processingText?: string;
22
+ /** Preview handler — reveals the action button on hover and makes the thumbnail clickable */
23
+ onPreview?: () => void;
24
+ /** Label for the preview action; when set it renders text + icon, otherwise icon-only */
25
+ previewButtonText?: string;
26
+ /** Icon for the preview action (defaults to `Play`) */
27
+ previewIcon?: IconName;
28
+ /** Menu items for the dropdown — renders the menu button on hover */
29
+ menuItems?: MenuItemProps[];
30
+ /** Whether to show the menu */
31
+ showMenu?: boolean;
32
+ /** Width of the card (overrides the default) */
33
+ width?: string | number;
34
+ /** Test id */
35
+ testId?: string;
36
+ }
37
+ /**
38
+ * VideoCard skeleton props
39
+ */
40
+ export interface VideoCardSkeletonProps {
41
+ /** Aspect ratio of the thumbnail placeholder. Defaults to `16 / 9` */
42
+ aspectRatio?: string;
43
+ /** Width of the card (overrides the default) */
44
+ width?: string | number;
45
+ /** Custom style for the skeleton */
46
+ style?: React.CSSProperties;
47
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@beydesign/storybook",
3
3
  "private": false,
4
- "version": "0.2.19",
4
+ "version": "0.2.21",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",