@beydesign/storybook 0.1.20 → 0.1.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/App.js +58 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/stories/PlanCard/PlanCard.d.ts +3 -0
- package/dist/stories/PlanCard/PlanCard.js +13 -0
- package/dist/stories/PlanCard/PlanCard.stories.d.ts +9 -0
- package/dist/stories/PlanCard/PlanCard.stories.js +125 -0
- package/dist/stories/PlanCard/PlanCardSkeleton.d.ts +3 -0
- package/dist/stories/PlanCard/PlanCardSkeleton.js +6 -0
- package/dist/stories/PlanCard/PlanCardSkeleton.stories.d.ts +7 -0
- package/dist/stories/PlanCard/PlanCardSkeleton.stories.js +40 -0
- package/dist/stories/PlanCard/index.d.ts +3 -0
- package/dist/stories/PlanCard/index.js +3 -0
- package/dist/stories/PlanCard/types.d.ts +61 -0
- package/dist/stories/PlanCard/types.js +1 -0
- package/dist/stories/UI/CheckIcon.d.ts +3 -0
- package/dist/stories/UI/CheckIcon.js +36 -0
- package/dist/stories/UI/CheckIcon.stories.d.ts +7 -0
- package/dist/stories/UI/CheckIcon.stories.js +48 -0
- package/dist/stories/UI/index.d.ts +1 -0
- package/dist/stories/UI/index.js +1 -0
- package/dist/stories/UI/types.d.ts +42 -0
- package/dist/stories/UI/types.js +30 -0
- package/package.json +1 -1
package/dist/App.js
CHANGED
|
@@ -1,7 +1,51 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { EntityCard, EntityCardSkeleton } from './stories/EntityCard';
|
|
4
|
+
import { PlanCard, PlanCardSkeleton } from './stories/PlanCard';
|
|
5
|
+
import { BadgeColor } from './stories/UI';
|
|
4
6
|
import './App.css';
|
|
7
|
+
const plans = [
|
|
8
|
+
{
|
|
9
|
+
id: 'free',
|
|
10
|
+
title: 'Free',
|
|
11
|
+
description: 'Discover what Beyond Presence has to offer.',
|
|
12
|
+
price: '€0',
|
|
13
|
+
badgeText: 'Current Plan',
|
|
14
|
+
badgeColor: BadgeColor.Green,
|
|
15
|
+
buttonText: 'Current plan',
|
|
16
|
+
buttonDisabled: true,
|
|
17
|
+
features: [
|
|
18
|
+
'1 credit (1 min of Conversational Agent video)',
|
|
19
|
+
'5 stock Digital Twins',
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'personal',
|
|
24
|
+
title: 'Personal',
|
|
25
|
+
description: 'Tailored for personal projects and independent creators.',
|
|
26
|
+
price: '€50',
|
|
27
|
+
features: [
|
|
28
|
+
'50 credits (50 min of Conversational Agent video)',
|
|
29
|
+
'5 stock Digital Twins',
|
|
30
|
+
'1 active Conversational Agent',
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'pro',
|
|
35
|
+
title: 'Pro',
|
|
36
|
+
description: 'Designed for professionals looking to expand their reach.',
|
|
37
|
+
price: '€210',
|
|
38
|
+
badgeText: 'Most Popular',
|
|
39
|
+
badgeColor: BadgeColor.Lemon,
|
|
40
|
+
highlighted: true,
|
|
41
|
+
features: [
|
|
42
|
+
'300 credits (300 min of Conversational Agent video)',
|
|
43
|
+
'5 stock Digital Twins',
|
|
44
|
+
'3 active Conversational Agents',
|
|
45
|
+
'Priority support',
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
];
|
|
5
49
|
const avatars = [
|
|
6
50
|
{
|
|
7
51
|
id: 'nelly',
|
|
@@ -104,6 +148,19 @@ function App() {
|
|
|
104
148
|
gap: '16px',
|
|
105
149
|
}, children: avatars
|
|
106
150
|
.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}`))) })
|
|
151
|
+
.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}`))) }), _jsx("h2", { style: {
|
|
152
|
+
fontFamily: 'Figtree, sans-serif',
|
|
153
|
+
color: 'var(--colors-light-text-text-title)',
|
|
154
|
+
margin: '40px 0 4px',
|
|
155
|
+
}, children: "Subscription plans" }), _jsx("p", { style: {
|
|
156
|
+
fontFamily: 'Figtree, sans-serif',
|
|
157
|
+
color: 'var(--colors-light-text-text-subtle)',
|
|
158
|
+
marginBottom: '24px',
|
|
159
|
+
}, children: "Choose the plan that's right for you." }), _jsx("div", { style: {
|
|
160
|
+
display: 'flex',
|
|
161
|
+
flexWrap: 'wrap',
|
|
162
|
+
alignItems: 'flex-start',
|
|
163
|
+
gap: '16px',
|
|
164
|
+
}, children: plans.map((plan) => loading ? (_jsx(PlanCardSkeleton, { featuresCount: plan.features.length }, plan.id)) : (_jsx(PlanCard, { title: plan.title, description: plan.description, price: plan.price, badgeText: plan.badgeText, badgeColor: plan.badgeColor, highlighted: plan.highlighted, buttonText: plan.buttonText, buttonDisabled: plan.buttonDisabled, features: plan.features, onButtonClick: () => console.log('Plan action', plan.title) }, plan.id))) })] }));
|
|
108
165
|
}
|
|
109
166
|
export default App;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from '@mui/material';
|
|
3
|
+
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
4
|
+
import { MainButton, ButtonHierarchy, ButtonSize } from '../Buttons';
|
|
5
|
+
import { Badge, BadgeColor, BadgeSize, CheckIcon, CheckIconColor, CheckIconSize, CheckIconType, } from '../UI';
|
|
6
|
+
export const PlanCard = ({ title, description, price, priceSuffix = '/month', badgeText, badgeColor = BadgeColor.Lemon, highlighted = false, featuresTitle = 'This includes:', features = [], buttonText = 'Upgrade', onButtonClick, buttonDisabled = false, buttonHierarchy = ButtonHierarchy.Primary, buttonLoading = false, width = '286px', style, testId, }) => {
|
|
7
|
+
const planKey = title?.toLowerCase()?.replace(/\s+/g, '-');
|
|
8
|
+
return (_jsxs(Box, { width: width, display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', paddingX: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', paddingY: 'var(--spacing-tokens-size-in-px-spacing-spacing-2xl)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg)', bgcolor: highlighted
|
|
9
|
+
? 'var(--colors-light-background-bg-card-highlight)'
|
|
10
|
+
: 'var(--colors-light-background-bg-white)', border: `1px solid ${highlighted
|
|
11
|
+
? 'var(--colors-light-border-border-brand)'
|
|
12
|
+
: 'var(--colors-light-border-border-subtle)'}`, boxSizing: 'border-box', style: style, "data-testid": testId ?? `${planKey}-plan-card`, children: [_jsxs(Box, { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [_jsxs(Box, { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', minHeight: '24px', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [_jsx(Typography, { size: TypographySize.HeadingM, weight: TypographyWeight.Bold, color: 'var(--colors-light-text-text-title)', children: title }), badgeText && (_jsx(Badge, { text: badgeText, color: badgeColor, size: BadgeSize.xs, fill: true }))] }), description && (_jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Regular, color: 'var(--colors-light-text-text-paragraph)', textStyle: { textAlign: 'left' }, children: description })), price && (_jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'baseline', gap: '2px', children: [_jsx(Typography, { size: TypographySize.HeadingL, weight: TypographyWeight.Bold, color: 'var(--colors-light-text-text-title)', children: price }), priceSuffix && (_jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: 'var(--colors-light-text-text-paragraph)', children: priceSuffix }))] }))] }), buttonText && (_jsx(MainButton, { text: buttonText, hierarchy: buttonHierarchy, size: ButtonSize.md, disabled: buttonDisabled, loading: buttonLoading, onClick: onButtonClick, style: { width: '100%' }, testId: `${planKey}-plan-button` })), features.length > 0 && (_jsxs(Box, { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', alignItems: 'flex-start', children: [_jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Medium, color: 'var(--colors-light-text-text-paragraph)', children: featuresTitle }), features.map((feature, index) => (_jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'flex-start', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', width: '100%', children: [_jsx(CheckIcon, { color: CheckIconColor.Violet, size: CheckIconSize.xs, type: CheckIconType.Duotone }), _jsx(Typography, { size: TypographySize.TextM, weight: TypographyWeight.Regular, color: 'var(--colors-light-text-text-title)', textStyle: { textAlign: 'left' }, children: feature })] }, `${index}-${feature}`)))] }))] }));
|
|
13
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { PlanCard } from './PlanCard';
|
|
3
|
+
declare const meta: Meta<typeof PlanCard>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof PlanCard>;
|
|
6
|
+
export declare const Pro: Story;
|
|
7
|
+
export declare const Free: Story;
|
|
8
|
+
export declare const Personal: Story;
|
|
9
|
+
export declare const Custom: Story;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PlanCard } from './PlanCard';
|
|
2
|
+
import { BadgeColor } from '../UI';
|
|
3
|
+
import { ButtonHierarchy } from '../Buttons';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Components/PlanCard/PlanCard',
|
|
6
|
+
component: PlanCard,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
design: {
|
|
10
|
+
type: 'figspec',
|
|
11
|
+
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=7002-19848',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
tags: ['autodocs'],
|
|
15
|
+
argTypes: {
|
|
16
|
+
title: { control: 'text', description: 'Plan name' },
|
|
17
|
+
description: { control: 'text', description: 'Short plan description' },
|
|
18
|
+
price: {
|
|
19
|
+
control: 'text',
|
|
20
|
+
description: 'Price text (e.g. "€210" or "Custom")',
|
|
21
|
+
},
|
|
22
|
+
priceSuffix: {
|
|
23
|
+
control: 'text',
|
|
24
|
+
description: 'Price suffix',
|
|
25
|
+
table: { defaultValue: { summary: '/month' } },
|
|
26
|
+
},
|
|
27
|
+
badgeText: { control: 'text', description: 'Badge text' },
|
|
28
|
+
badgeColor: {
|
|
29
|
+
control: 'select',
|
|
30
|
+
options: Object.values(BadgeColor),
|
|
31
|
+
description: 'Badge color',
|
|
32
|
+
table: { defaultValue: { summary: BadgeColor.Lemon } },
|
|
33
|
+
},
|
|
34
|
+
highlighted: {
|
|
35
|
+
control: 'boolean',
|
|
36
|
+
description: 'Brand background + border highlight',
|
|
37
|
+
},
|
|
38
|
+
featuresTitle: {
|
|
39
|
+
control: 'text',
|
|
40
|
+
table: { defaultValue: { summary: 'This includes:' } },
|
|
41
|
+
},
|
|
42
|
+
features: { control: 'object', description: 'Feature list' },
|
|
43
|
+
buttonText: {
|
|
44
|
+
control: 'text',
|
|
45
|
+
table: { defaultValue: { summary: 'Upgrade' } },
|
|
46
|
+
},
|
|
47
|
+
buttonDisabled: { control: 'boolean' },
|
|
48
|
+
buttonHierarchy: {
|
|
49
|
+
control: 'select',
|
|
50
|
+
options: Object.values(ButtonHierarchy),
|
|
51
|
+
table: { defaultValue: { summary: ButtonHierarchy.Primary } },
|
|
52
|
+
},
|
|
53
|
+
buttonLoading: { control: 'boolean' },
|
|
54
|
+
width: {
|
|
55
|
+
control: 'text',
|
|
56
|
+
table: { defaultValue: { summary: '286px' } },
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
export default meta;
|
|
61
|
+
export const Pro = {
|
|
62
|
+
args: {
|
|
63
|
+
title: 'Pro',
|
|
64
|
+
description: 'Designed for professionals looking to expand their reach.',
|
|
65
|
+
price: '€210',
|
|
66
|
+
priceSuffix: '/month',
|
|
67
|
+
badgeText: 'Most Popular',
|
|
68
|
+
badgeColor: BadgeColor.Lemon,
|
|
69
|
+
highlighted: true,
|
|
70
|
+
buttonText: 'Upgrade',
|
|
71
|
+
features: [
|
|
72
|
+
'300 credits (300 min of Conversational Agent video)',
|
|
73
|
+
'5 stock Digital Twins',
|
|
74
|
+
'3 active Conversational Agents',
|
|
75
|
+
'Priority support',
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export const Free = {
|
|
80
|
+
args: {
|
|
81
|
+
title: 'Free',
|
|
82
|
+
description: 'Discover what Beyond Presence has to offer.',
|
|
83
|
+
price: '€0',
|
|
84
|
+
priceSuffix: '/month',
|
|
85
|
+
badgeText: 'Current Plan',
|
|
86
|
+
badgeColor: BadgeColor.Green,
|
|
87
|
+
buttonText: 'Current plan',
|
|
88
|
+
buttonDisabled: true,
|
|
89
|
+
features: [
|
|
90
|
+
'1 credit (1 min of Conversational Agent video)',
|
|
91
|
+
'5 stock Digital Twins',
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
export const Personal = {
|
|
96
|
+
args: {
|
|
97
|
+
title: 'Personal',
|
|
98
|
+
description: 'Tailored for personal projects and independent creators.',
|
|
99
|
+
price: '€50',
|
|
100
|
+
priceSuffix: '/month',
|
|
101
|
+
buttonText: 'Upgrade',
|
|
102
|
+
features: [
|
|
103
|
+
'50 credits (50 min of Conversational Agent video)',
|
|
104
|
+
'5 stock Digital Twins',
|
|
105
|
+
'1 active Conversational Agent',
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
export const Custom = {
|
|
110
|
+
args: {
|
|
111
|
+
title: 'Professional',
|
|
112
|
+
description: 'For businesses with high volume and custom needs.',
|
|
113
|
+
price: 'Custom',
|
|
114
|
+
priceSuffix: '',
|
|
115
|
+
buttonText: 'Upgrade',
|
|
116
|
+
features: ['5000+ credits (5000+ min of Conversational Agent video)'],
|
|
117
|
+
},
|
|
118
|
+
parameters: {
|
|
119
|
+
docs: {
|
|
120
|
+
description: {
|
|
121
|
+
story: 'A custom-priced plan — the price suffix is omitted.',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
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 PlanCardSkeleton = ({ showBadge = true, showButton = true, showFeatures = true, featuresCount = 4, width = '286px', style, testId, }) => {
|
|
5
|
+
return (_jsxs(Box, { width: width, display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', paddingX: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl)', paddingY: 'var(--spacing-tokens-size-in-px-spacing-spacing-2xl)', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg)', bgcolor: 'var(--colors-light-background-bg-white)', border: '1px solid var(--colors-light-border-border-subtle)', boxSizing: 'border-box', style: style, "data-testid": testId, children: [_jsxs(Box, { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [_jsxs(Box, { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', children: [_jsx(SkeletonLoader, { width: '40%', height: '24px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' }), showBadge && (_jsx(SkeletonLoader, { width: '88px', height: '24px', borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-full)' }))] }), _jsx(SkeletonLoader, { width: '100%', height: '20px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' }), _jsx(SkeletonLoader, { width: '50%', height: '32px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' })] }), showButton && (_jsx(SkeletonLoader, { width: '100%', height: '36px', borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-xs)' })), showFeatures && (_jsxs(Box, { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', alignItems: 'flex-start', children: [_jsx(SkeletonLoader, { width: '96px', height: '20px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' }), Array.from({ length: featuresCount }).map((_, index) => (_jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', width: '100%', children: [_jsx(SkeletonLoader, { width: '20px', height: '20px', borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-full)' }), _jsx(SkeletonLoader, { width: index % 2 === 0 ? '80%' : '60%', height: '18px', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)' })] }, index)))] }))] }));
|
|
6
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { PlanCardSkeleton } from './PlanCardSkeleton';
|
|
3
|
+
declare const meta: Meta<typeof PlanCardSkeleton>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof PlanCardSkeleton>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Grid: Story;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from '@mui/material';
|
|
3
|
+
import { PlanCardSkeleton } from './PlanCardSkeleton';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Components/PlanCard/PlanCardSkeleton',
|
|
6
|
+
component: PlanCardSkeleton,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: {
|
|
12
|
+
showBadge: {
|
|
13
|
+
control: 'boolean',
|
|
14
|
+
table: { defaultValue: { summary: 'true' } },
|
|
15
|
+
},
|
|
16
|
+
showButton: {
|
|
17
|
+
control: 'boolean',
|
|
18
|
+
table: { defaultValue: { summary: 'true' } },
|
|
19
|
+
},
|
|
20
|
+
showFeatures: {
|
|
21
|
+
control: 'boolean',
|
|
22
|
+
table: { defaultValue: { summary: 'true' } },
|
|
23
|
+
},
|
|
24
|
+
featuresCount: {
|
|
25
|
+
control: 'number',
|
|
26
|
+
table: { defaultValue: { summary: '4' } },
|
|
27
|
+
},
|
|
28
|
+
width: {
|
|
29
|
+
control: 'text',
|
|
30
|
+
table: { defaultValue: { summary: '286px' } },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export default meta;
|
|
35
|
+
export const Default = {
|
|
36
|
+
args: {},
|
|
37
|
+
};
|
|
38
|
+
export const Grid = {
|
|
39
|
+
render: () => (_jsxs(Box, { display: "flex", flexWrap: "wrap", gap: 2, children: [_jsx(PlanCardSkeleton, {}), _jsx(PlanCardSkeleton, { featuresCount: 3 }), _jsx(PlanCardSkeleton, { featuresCount: 5 })] })),
|
|
40
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BadgeColor } from '../UI';
|
|
3
|
+
import { ButtonHierarchy } from '../Buttons';
|
|
4
|
+
/**
|
|
5
|
+
* Plan card component props — a compact, in-app subscription plan card.
|
|
6
|
+
*/
|
|
7
|
+
export interface PlanCardProps {
|
|
8
|
+
/** Plan name (e.g. "Pro") */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Short plan description */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Price text (e.g. "€210" or "Custom") */
|
|
13
|
+
price?: string;
|
|
14
|
+
/** Price suffix shown next to the price (e.g. "/month") */
|
|
15
|
+
priceSuffix?: string;
|
|
16
|
+
/** Badge text (e.g. "Most Popular", "Current Plan") */
|
|
17
|
+
badgeText?: string;
|
|
18
|
+
/** Badge color (defaults to Lemon) */
|
|
19
|
+
badgeColor?: BadgeColor;
|
|
20
|
+
/** Highlights the card with a brand background + border */
|
|
21
|
+
highlighted?: boolean;
|
|
22
|
+
/** Heading above the feature list */
|
|
23
|
+
featuresTitle?: string;
|
|
24
|
+
/** Feature list */
|
|
25
|
+
features?: string[];
|
|
26
|
+
/** Action button label (defaults to "Upgrade"); hidden when omitted */
|
|
27
|
+
buttonText?: string;
|
|
28
|
+
/** Action button click handler */
|
|
29
|
+
onButtonClick?: () => void;
|
|
30
|
+
/** Disable the action button (e.g. for the current plan) */
|
|
31
|
+
buttonDisabled?: boolean;
|
|
32
|
+
/** Action button hierarchy (defaults to Primary) */
|
|
33
|
+
buttonHierarchy?: ButtonHierarchy;
|
|
34
|
+
/** Show a loading spinner on the action button */
|
|
35
|
+
buttonLoading?: boolean;
|
|
36
|
+
/** Width of the card */
|
|
37
|
+
width?: string | number;
|
|
38
|
+
/** Custom style */
|
|
39
|
+
style?: React.CSSProperties;
|
|
40
|
+
/** Test id */
|
|
41
|
+
testId?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Plan card skeleton props
|
|
45
|
+
*/
|
|
46
|
+
export interface PlanCardSkeletonProps {
|
|
47
|
+
/** Whether to show the badge placeholder */
|
|
48
|
+
showBadge?: boolean;
|
|
49
|
+
/** Whether to show the button placeholder */
|
|
50
|
+
showButton?: boolean;
|
|
51
|
+
/** Whether to show the features placeholder */
|
|
52
|
+
showFeatures?: boolean;
|
|
53
|
+
/** Number of feature placeholders */
|
|
54
|
+
featuresCount?: number;
|
|
55
|
+
/** Width of the card */
|
|
56
|
+
width?: string | number;
|
|
57
|
+
/** Custom style */
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
|
+
/** Test id */
|
|
60
|
+
testId?: string;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from '@mui/material';
|
|
3
|
+
import { CheckIconColor, CheckIconSize, CheckIconType, } from './types';
|
|
4
|
+
import { getIconComponent } from '../../utils';
|
|
5
|
+
const WHITE = 'var(--semantic-colors-light-foreground-fg-on-primary-accent-color)';
|
|
6
|
+
const COLOR_MAP = {
|
|
7
|
+
[CheckIconColor.Violet]: {
|
|
8
|
+
accent: 'var(--semantic-colors-light-foreground-fg-accent-violet)',
|
|
9
|
+
subtle: 'var(--semantic-colors-light-background-bg-badge-accent-brand-violet)',
|
|
10
|
+
},
|
|
11
|
+
[CheckIconColor.Green]: {
|
|
12
|
+
accent: 'var(--colors-light-foreground-fg-success)',
|
|
13
|
+
subtle: 'var(--semantic-colors-light-background-bg-badge-accent-success)',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const SIZE_MAP = {
|
|
17
|
+
[CheckIconSize.xs]: { container: 16, check: 11, border: 1.5 },
|
|
18
|
+
[CheckIconSize.sm]: { container: 20, check: 13, border: 1.5 },
|
|
19
|
+
[CheckIconSize.md]: { container: 24, check: 16, border: 2 },
|
|
20
|
+
[CheckIconSize.lg]: { container: 28, check: 18, border: 2 },
|
|
21
|
+
};
|
|
22
|
+
export const CheckIcon = ({ color = CheckIconColor.Violet, size = CheckIconSize.md, type = CheckIconType.Duotone, style, testId, }) => {
|
|
23
|
+
const { accent, subtle } = COLOR_MAP[color];
|
|
24
|
+
const { container, check, border } = SIZE_MAP[size];
|
|
25
|
+
const background = type === CheckIconType.Filled
|
|
26
|
+
? accent
|
|
27
|
+
: type === CheckIconType.Duotone
|
|
28
|
+
? subtle
|
|
29
|
+
: 'transparent';
|
|
30
|
+
const checkColor = type === CheckIconType.Filled ? WHITE : accent;
|
|
31
|
+
return (_jsx(Box, { width: `${container}px`, height: `${container}px`, flexShrink: 0, boxSizing: 'border-box', display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-full)', bgcolor: background, border: type === CheckIconType.Line ? `${border}px solid ${accent}` : undefined, style: style, "data-testid": testId, children: getIconComponent('Check', {
|
|
32
|
+
size: `${check}px`,
|
|
33
|
+
weight: 'bold',
|
|
34
|
+
color: checkColor,
|
|
35
|
+
}) }));
|
|
36
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CheckIcon } from './CheckIcon';
|
|
3
|
+
declare const meta: Meta<typeof CheckIcon>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof CheckIcon>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const AllVariants: Story;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from '@mui/material';
|
|
3
|
+
import { CheckIcon } from './CheckIcon';
|
|
4
|
+
import { CheckIconColor, CheckIconSize, CheckIconType } from './types';
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Design System/Components/UI/CheckIcon',
|
|
7
|
+
component: CheckIcon,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
design: {
|
|
11
|
+
type: 'figspec',
|
|
12
|
+
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=4781-5580',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
tags: ['autodocs'],
|
|
16
|
+
argTypes: {
|
|
17
|
+
color: {
|
|
18
|
+
control: 'select',
|
|
19
|
+
options: Object.values(CheckIconColor),
|
|
20
|
+
table: { defaultValue: { summary: CheckIconColor.Violet } },
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: Object.values(CheckIconSize),
|
|
25
|
+
table: { defaultValue: { summary: CheckIconSize.md } },
|
|
26
|
+
},
|
|
27
|
+
type: {
|
|
28
|
+
control: 'select',
|
|
29
|
+
options: Object.values(CheckIconType),
|
|
30
|
+
table: { defaultValue: { summary: CheckIconType.Duotone } },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export default meta;
|
|
35
|
+
export const Default = {
|
|
36
|
+
args: {
|
|
37
|
+
color: CheckIconColor.Violet,
|
|
38
|
+
size: CheckIconSize.md,
|
|
39
|
+
type: CheckIconType.Duotone,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export const AllVariants = {
|
|
43
|
+
render: () => (_jsx(Box, { display: "flex", flexDirection: "column", gap: 3, children: Object.values(CheckIconType).map((type) => (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 1, children: [_jsx("span", { style: {
|
|
44
|
+
fontFamily: 'Figtree, sans-serif',
|
|
45
|
+
fontSize: 12,
|
|
46
|
+
color: 'var(--colors-light-text-text-subtle)',
|
|
47
|
+
}, children: type }), Object.values(CheckIconColor).map((color) => (_jsx(Box, { display: "flex", alignItems: "center", gap: 2, children: Object.values(CheckIconSize).map((size) => (_jsx(CheckIcon, { color: color, type: type, size: size }, `${color}-${type}-${size}`))) }, color)))] }, type))) })),
|
|
48
|
+
};
|
package/dist/stories/UI/index.js
CHANGED
|
@@ -169,6 +169,48 @@ export type MenuProps = {
|
|
|
169
169
|
/** Hierarchy of the trigger button */
|
|
170
170
|
hierarchy?: ButtonHierarchy;
|
|
171
171
|
};
|
|
172
|
+
/**
|
|
173
|
+
* Check icon color variants
|
|
174
|
+
*/
|
|
175
|
+
export declare enum CheckIconColor {
|
|
176
|
+
Violet = "Violet",
|
|
177
|
+
Green = "Green"
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Check icon size variants (xs = 16px, sm = 20px, md = 24px, lg = 28px)
|
|
181
|
+
*/
|
|
182
|
+
export declare enum CheckIconSize {
|
|
183
|
+
xs = "xs",
|
|
184
|
+
sm = "sm",
|
|
185
|
+
md = "md",
|
|
186
|
+
lg = "lg"
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check icon type variants.
|
|
190
|
+
* - `Filled`: solid accent background + white check
|
|
191
|
+
* - `Line`: transparent background, accent ring + accent check
|
|
192
|
+
* - `Duotone`: light badge background + accent-colored check
|
|
193
|
+
*/
|
|
194
|
+
export declare enum CheckIconType {
|
|
195
|
+
Filled = "Filled",
|
|
196
|
+
Line = "Line",
|
|
197
|
+
Duotone = "Duotone"
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Check icon component props
|
|
201
|
+
*/
|
|
202
|
+
export interface CheckIconProps {
|
|
203
|
+
/** Color variant */
|
|
204
|
+
color?: CheckIconColor;
|
|
205
|
+
/** Size variant (xs = 16px, md = 24px) */
|
|
206
|
+
size?: CheckIconSize;
|
|
207
|
+
/** Fill style */
|
|
208
|
+
type?: CheckIconType;
|
|
209
|
+
/** Custom style */
|
|
210
|
+
style?: React.CSSProperties;
|
|
211
|
+
/** Test id */
|
|
212
|
+
testId?: string;
|
|
213
|
+
}
|
|
172
214
|
/**
|
|
173
215
|
* Progress indicator mode variants
|
|
174
216
|
*/
|
package/dist/stories/UI/types.js
CHANGED
|
@@ -61,6 +61,36 @@ export var LogoVariant;
|
|
|
61
61
|
LogoVariant["Vertical"] = "vertical";
|
|
62
62
|
LogoVariant["Icon"] = "icon";
|
|
63
63
|
})(LogoVariant || (LogoVariant = {}));
|
|
64
|
+
/**
|
|
65
|
+
* Check icon color variants
|
|
66
|
+
*/
|
|
67
|
+
export var CheckIconColor;
|
|
68
|
+
(function (CheckIconColor) {
|
|
69
|
+
CheckIconColor["Violet"] = "Violet";
|
|
70
|
+
CheckIconColor["Green"] = "Green";
|
|
71
|
+
})(CheckIconColor || (CheckIconColor = {}));
|
|
72
|
+
/**
|
|
73
|
+
* Check icon size variants (xs = 16px, sm = 20px, md = 24px, lg = 28px)
|
|
74
|
+
*/
|
|
75
|
+
export var CheckIconSize;
|
|
76
|
+
(function (CheckIconSize) {
|
|
77
|
+
CheckIconSize["xs"] = "xs";
|
|
78
|
+
CheckIconSize["sm"] = "sm";
|
|
79
|
+
CheckIconSize["md"] = "md";
|
|
80
|
+
CheckIconSize["lg"] = "lg";
|
|
81
|
+
})(CheckIconSize || (CheckIconSize = {}));
|
|
82
|
+
/**
|
|
83
|
+
* Check icon type variants.
|
|
84
|
+
* - `Filled`: solid accent background + white check
|
|
85
|
+
* - `Line`: transparent background, accent ring + accent check
|
|
86
|
+
* - `Duotone`: light badge background + accent-colored check
|
|
87
|
+
*/
|
|
88
|
+
export var CheckIconType;
|
|
89
|
+
(function (CheckIconType) {
|
|
90
|
+
CheckIconType["Filled"] = "Filled";
|
|
91
|
+
CheckIconType["Line"] = "Line";
|
|
92
|
+
CheckIconType["Duotone"] = "Duotone";
|
|
93
|
+
})(CheckIconType || (CheckIconType = {}));
|
|
64
94
|
/**
|
|
65
95
|
* Progress indicator mode variants
|
|
66
96
|
*/
|