@beydesign/storybook 0.5.3 → 0.5.5
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/EntityCard/EntityCard.js +1 -12
- package/dist/stories/EntityCard/EntityCardSkeleton.js +1 -12
- package/dist/stories/EntityCard/constants.d.ts +9 -0
- package/dist/stories/EntityCard/constants.js +16 -0
- package/dist/stories/EntityCard/types.d.ts +1 -1
- package/dist/stories/PlanCard/PlanCard.js +1 -1
- package/dist/stories/UI/CheckIcon.js +40 -19
- package/dist/stories/UI/CheckIcon.stories.js +1 -1
- package/dist/stories/UI/types.d.ts +9 -6
- package/dist/stories/UI/types.js +7 -4
- package/package.json +1 -1
|
@@ -3,22 +3,11 @@ import { useState } from 'react';
|
|
|
3
3
|
import { Box } from '@mui/material';
|
|
4
4
|
import { keyframes } from '@emotion/react';
|
|
5
5
|
import { ArrowsClockwise, Warning } from '@phosphor-icons/react';
|
|
6
|
+
import { ASPECT_RATIO_BY_VIEW, WIDTH_BY_VIEW } from './constants';
|
|
6
7
|
import { AvatarSilhouette } from './AvatarSilhouette';
|
|
7
8
|
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
8
9
|
import { Menu, Badge, BadgeColor, BadgeSize } from '../UI';
|
|
9
10
|
import { MainButton, ButtonHierarchy, ButtonSize, ButtonDisplayMode, } from '../Buttons';
|
|
10
|
-
/** Default card width per view variant. */
|
|
11
|
-
const WIDTH_BY_VIEW = {
|
|
12
|
-
avatar: '208px',
|
|
13
|
-
agent: '280px',
|
|
14
|
-
video: '340px',
|
|
15
|
-
};
|
|
16
|
-
/** Default image aspect ratio per view variant. */
|
|
17
|
-
const ASPECT_RATIO_BY_VIEW = {
|
|
18
|
-
avatar: '203 / 264',
|
|
19
|
-
agent: '264 / 268',
|
|
20
|
-
video: '16 / 9',
|
|
21
|
-
};
|
|
22
11
|
/** Empty-state label per view variant, shown over the silhouette when there is no image. */
|
|
23
12
|
const EMPTY_TEXT_BY_VIEW = {
|
|
24
13
|
avatar: 'Avatar is not available',
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box } from '@mui/material';
|
|
3
|
+
import { ASPECT_RATIO_BY_VIEW, WIDTH_BY_VIEW } from './constants';
|
|
3
4
|
import { SkeletonLoader } from '../UI';
|
|
4
|
-
/** Default card width per view variant. */
|
|
5
|
-
const WIDTH_BY_VIEW = {
|
|
6
|
-
avatar: '208px',
|
|
7
|
-
agent: '280px',
|
|
8
|
-
video: '340px',
|
|
9
|
-
};
|
|
10
|
-
/** Default image aspect ratio per view variant. */
|
|
11
|
-
const ASPECT_RATIO_BY_VIEW = {
|
|
12
|
-
avatar: '203 / 264',
|
|
13
|
-
agent: '1 / 1',
|
|
14
|
-
video: '16 / 9',
|
|
15
|
-
};
|
|
16
5
|
export const EntityCardSkeleton = ({ view = 'avatar', aspectRatio, width, showDescription = false, style, }) => {
|
|
17
6
|
const cardWidth = width ?? WIDTH_BY_VIEW[view];
|
|
18
7
|
const imageAspectRatio = aspectRatio ?? ASPECT_RATIO_BY_VIEW[view];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EntityCardView } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Card metrics shared by EntityCard and EntityCardSkeleton — the skeleton
|
|
4
|
+
* stands in for the card while its media loads, so both must measure the same.
|
|
5
|
+
*/
|
|
6
|
+
/** Default card width per view variant. */
|
|
7
|
+
export declare const WIDTH_BY_VIEW: Record<EntityCardView, string>;
|
|
8
|
+
/** Default image aspect ratio per view variant. */
|
|
9
|
+
export declare const ASPECT_RATIO_BY_VIEW: Record<EntityCardView, string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card metrics shared by EntityCard and EntityCardSkeleton — the skeleton
|
|
3
|
+
* stands in for the card while its media loads, so both must measure the same.
|
|
4
|
+
*/
|
|
5
|
+
/** Default card width per view variant. */
|
|
6
|
+
export const WIDTH_BY_VIEW = {
|
|
7
|
+
avatar: '208px',
|
|
8
|
+
agent: '280px',
|
|
9
|
+
video: '340px',
|
|
10
|
+
};
|
|
11
|
+
/** Default image aspect ratio per view variant. */
|
|
12
|
+
export const ASPECT_RATIO_BY_VIEW = {
|
|
13
|
+
avatar: '203 / 264',
|
|
14
|
+
agent: '264 / 268',
|
|
15
|
+
video: '16 / 9',
|
|
16
|
+
};
|
|
@@ -62,7 +62,7 @@ export interface EntityCardProps {
|
|
|
62
62
|
export interface EntityCardSkeletonProps {
|
|
63
63
|
/** View variant — drives default width and image aspect ratio */
|
|
64
64
|
view?: EntityCardView;
|
|
65
|
-
/** Aspect ratio of the placeholder — overrides the per-view default */
|
|
65
|
+
/** Aspect ratio of the placeholder — overrides the per-view default (`203 / 264` avatar, `264 / 268` agent, `16 / 9` video) */
|
|
66
66
|
aspectRatio?: string;
|
|
67
67
|
/** Width of the card (overrides the view default) */
|
|
68
68
|
width?: string | number;
|
|
@@ -11,7 +11,7 @@ export const PlanCard = ({ title, description, price, priceSuffix = '/month', ba
|
|
|
11
11
|
? 'var(--color-border-border-brand)'
|
|
12
12
|
: 'var(--color-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(--color-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(--color-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(--color-text-text-title)', children: price }), priceSuffix && (_jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: 'var(--color-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(--color-text-text-paragraph)', children: featuresTitle }), features.map((feature, index) => {
|
|
13
13
|
const isHeading = feature?.startsWith('-');
|
|
14
|
-
return (_jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'flex-start', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', width: '100%', children: [!isHeading && (_jsx(Box, { display: 'flex', alignItems: 'center', flexShrink: 0, height: '1lh', fontFamily: 'var(--global-text-m-regular-font-family), sans-serif', fontSize: 'var(--global-text-m-regular-font-size)', lineHeight: 'calc(var(--global-text-m-regular-line-height) * 1px)', children: _jsx(CheckIcon, { color: CheckIconColor.Violet, size: CheckIconSize.
|
|
14
|
+
return (_jsxs(Box, { display: 'flex', flexDirection: 'row', alignItems: 'flex-start', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', width: '100%', children: [!isHeading && (_jsx(Box, { display: 'flex', alignItems: 'center', flexShrink: 0, height: '1lh', fontFamily: 'var(--global-text-m-regular-font-family), sans-serif', fontSize: 'var(--global-text-m-regular-font-size)', lineHeight: 'calc(var(--global-text-m-regular-line-height) * 1px)', children: _jsx(CheckIcon, { color: CheckIconColor.Violet, size: CheckIconSize.md, type: CheckIconType.Duotone }) })), _jsx(Typography, { size: TypographySize.TextM, weight: isHeading
|
|
15
15
|
? TypographyWeight.Medium
|
|
16
16
|
: TypographyWeight.Regular, color: 'var(--color-text-text-title)', textStyle: { textAlign: 'left' }, children: isHeading ? feature?.slice(1)?.trim() : feature })] }, `${index}-${feature}`));
|
|
17
17
|
})] }))] }));
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Box } from '@mui/material';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
2
|
import { CheckIconColor, CheckIconSize, CheckIconType, } from './types';
|
|
4
|
-
import { getIconComponent } from '../../utils';
|
|
5
3
|
const WHITE = 'var(--color-foreground-fg-on-primary-accent-color)';
|
|
6
4
|
const COLOR_MAP = {
|
|
7
5
|
[CheckIconColor.Violet]: {
|
|
@@ -12,25 +10,48 @@ const COLOR_MAP = {
|
|
|
12
10
|
accent: 'var(--color-foreground-fg-success)',
|
|
13
11
|
subtle: 'var(--color-background-bg-badge-accent-success)',
|
|
14
12
|
},
|
|
13
|
+
/**
|
|
14
|
+
* Pinned to the primitives the offboarding screens use, not the
|
|
15
|
+
* `fg-accent-lemon` / `bg-badge-accent-brand-lemon` semantics the other
|
|
16
|
+
* colors follow — those resolve to different values per theme and would not
|
|
17
|
+
* match the design. The tint is 12% alpha rather than an opaque wash, so this
|
|
18
|
+
* variant is theme-invariant and is meant for dark surfaces.
|
|
19
|
+
*/
|
|
20
|
+
[CheckIconColor.Lemon]: {
|
|
21
|
+
accent: 'var(--primitives-white-primary-brand-lemon-500)',
|
|
22
|
+
subtle: 'var(--primitives-white-primary-transparent-lemon-12)',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
/** Nominal frame of the icon in px — the space the component occupies. */
|
|
26
|
+
const FRAME_MAP = {
|
|
27
|
+
[CheckIconSize.xs]: 16,
|
|
28
|
+
[CheckIconSize.sm]: 20,
|
|
29
|
+
[CheckIconSize.md]: 24,
|
|
30
|
+
[CheckIconSize.lg]: 28,
|
|
15
31
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Figma draws the glyph on a grid of 32 units per frame, with the ink inset
|
|
34
|
+
* inside the frame: the circle is 75% of the frame (r = 12/32) and the check
|
|
35
|
+
* runs (11,17) → (14,20) → (21,13). Keeping the geometry in grid units lets a
|
|
36
|
+
* single path serve every size; only the stroke widths are converted back to px.
|
|
37
|
+
*/
|
|
38
|
+
const GRID = 32;
|
|
39
|
+
const CENTER = GRID / 2;
|
|
40
|
+
const RADIUS = 12;
|
|
41
|
+
const CHECK_PATH = 'M11 17L14 20L21 13';
|
|
42
|
+
/** Ring stroke in px — constant across sizes in Figma, not scaled with the frame. */
|
|
43
|
+
const RING_STROKE_PX = 1.5;
|
|
44
|
+
/** Check stroke in px — Duotone is drawn heavier than Filled/Line. */
|
|
45
|
+
const CHECK_STROKE_PX = {
|
|
46
|
+
[CheckIconType.Filled]: 1.5,
|
|
47
|
+
[CheckIconType.Line]: 1.5,
|
|
48
|
+
[CheckIconType.Duotone]: 2,
|
|
21
49
|
};
|
|
22
50
|
export const CheckIcon = ({ color = CheckIconColor.Violet, size = CheckIconSize.md, type = CheckIconType.Duotone, style, testId, }) => {
|
|
23
51
|
const { accent, subtle } = COLOR_MAP[color];
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
: type === CheckIconType.Duotone
|
|
28
|
-
? subtle
|
|
29
|
-
: 'transparent';
|
|
52
|
+
const frame = FRAME_MAP[size];
|
|
53
|
+
// Grid units per px, so a px stroke keeps its width at any frame size.
|
|
54
|
+
const unitsPerPx = GRID / frame;
|
|
30
55
|
const checkColor = type === CheckIconType.Filled ? WHITE : accent;
|
|
31
|
-
return (
|
|
32
|
-
size: `${check}px`,
|
|
33
|
-
weight: 'bold',
|
|
34
|
-
color: checkColor,
|
|
35
|
-
}) }));
|
|
56
|
+
return (_jsxs("svg", { width: frame, height: frame, viewBox: `0 0 ${GRID} ${GRID}`, fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": true, focusable: 'false', style: { display: 'block', flexShrink: 0, ...style }, "data-testid": testId, children: [type === CheckIconType.Line ? (_jsx("circle", { cx: CENTER, cy: CENTER, r: RADIUS, stroke: accent, strokeWidth: RING_STROKE_PX * unitsPerPx })) : (_jsx("circle", { cx: CENTER, cy: CENTER, r: RADIUS, fill: type === CheckIconType.Filled ? accent : subtle })), _jsx("path", { d: CHECK_PATH, stroke: checkColor, strokeWidth: CHECK_STROKE_PX[type] * unitsPerPx, strokeLinecap: 'round', strokeLinejoin: 'round' })] }));
|
|
36
57
|
};
|
|
@@ -9,7 +9,7 @@ const meta = {
|
|
|
9
9
|
layout: 'centered',
|
|
10
10
|
design: {
|
|
11
11
|
type: 'figspec',
|
|
12
|
-
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=4781-
|
|
12
|
+
url: 'https://www.figma.com/design/mIhjz2yJjcpLlIqw6oUivt/Beyond-Presence?node-id=4781-5383',
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
tags: ['autodocs'],
|
|
@@ -225,10 +225,13 @@ export type MenuProps = {
|
|
|
225
225
|
*/
|
|
226
226
|
export declare enum CheckIconColor {
|
|
227
227
|
Violet = "Violet",
|
|
228
|
-
Green = "Green"
|
|
228
|
+
Green = "Green",
|
|
229
|
+
Lemon = "Lemon"
|
|
229
230
|
}
|
|
230
231
|
/**
|
|
231
|
-
* Check icon size variants
|
|
232
|
+
* Check icon size variants. The value is the frame the icon occupies
|
|
233
|
+
* (xs = 16px, sm = 20px, md = 24px, lg = 28px); the circle itself is drawn at
|
|
234
|
+
* 75% of that (12 / 15 / 18 / 21px), matching Figma.
|
|
232
235
|
*/
|
|
233
236
|
export declare enum CheckIconSize {
|
|
234
237
|
xs = "xs",
|
|
@@ -238,9 +241,9 @@ export declare enum CheckIconSize {
|
|
|
238
241
|
}
|
|
239
242
|
/**
|
|
240
243
|
* Check icon type variants.
|
|
241
|
-
* - `Filled`: solid accent
|
|
242
|
-
* - `Line`: transparent
|
|
243
|
-
* - `Duotone`:
|
|
244
|
+
* - `Filled`: solid accent circle + white check (1.5px)
|
|
245
|
+
* - `Line`: transparent circle, 1.5px accent ring + accent check (1.5px)
|
|
246
|
+
* - `Duotone`: subtle badge circle + accent check, drawn heavier (2px)
|
|
244
247
|
*/
|
|
245
248
|
export declare enum CheckIconType {
|
|
246
249
|
Filled = "Filled",
|
|
@@ -253,7 +256,7 @@ export declare enum CheckIconType {
|
|
|
253
256
|
export interface CheckIconProps {
|
|
254
257
|
/** Color variant */
|
|
255
258
|
color?: CheckIconColor;
|
|
256
|
-
/** Size variant (xs = 16px
|
|
259
|
+
/** Size variant — the frame the icon occupies (xs = 16px … lg = 28px) */
|
|
257
260
|
size?: CheckIconSize;
|
|
258
261
|
/** Fill style */
|
|
259
262
|
type?: CheckIconType;
|
package/dist/stories/UI/types.js
CHANGED
|
@@ -77,9 +77,12 @@ export var CheckIconColor;
|
|
|
77
77
|
(function (CheckIconColor) {
|
|
78
78
|
CheckIconColor["Violet"] = "Violet";
|
|
79
79
|
CheckIconColor["Green"] = "Green";
|
|
80
|
+
CheckIconColor["Lemon"] = "Lemon";
|
|
80
81
|
})(CheckIconColor || (CheckIconColor = {}));
|
|
81
82
|
/**
|
|
82
|
-
* Check icon size variants
|
|
83
|
+
* Check icon size variants. The value is the frame the icon occupies
|
|
84
|
+
* (xs = 16px, sm = 20px, md = 24px, lg = 28px); the circle itself is drawn at
|
|
85
|
+
* 75% of that (12 / 15 / 18 / 21px), matching Figma.
|
|
83
86
|
*/
|
|
84
87
|
export var CheckIconSize;
|
|
85
88
|
(function (CheckIconSize) {
|
|
@@ -90,9 +93,9 @@ export var CheckIconSize;
|
|
|
90
93
|
})(CheckIconSize || (CheckIconSize = {}));
|
|
91
94
|
/**
|
|
92
95
|
* Check icon type variants.
|
|
93
|
-
* - `Filled`: solid accent
|
|
94
|
-
* - `Line`: transparent
|
|
95
|
-
* - `Duotone`:
|
|
96
|
+
* - `Filled`: solid accent circle + white check (1.5px)
|
|
97
|
+
* - `Line`: transparent circle, 1.5px accent ring + accent check (1.5px)
|
|
98
|
+
* - `Duotone`: subtle badge circle + accent check, drawn heavier (2px)
|
|
96
99
|
*/
|
|
97
100
|
export var CheckIconType;
|
|
98
101
|
(function (CheckIconType) {
|