@beydesign/storybook 0.4.2 → 0.4.3
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/Buttons/MainButton.js +101 -110
- package/dist/stories/EntityCard/EntityCard.js +31 -4
- package/dist/stories/Form/AutoComplete.js +2 -4
- package/dist/stories/Form/Checkbox.js +66 -42
- package/dist/stories/Form/DatePicker.js +3 -2
- package/dist/stories/Navigation/Drawer/DrawerCreditsCard.d.ts +1 -1
- package/dist/stories/Navigation/Drawer/DrawerCreditsCard.js +3 -3
- package/dist/stories/Navigation/Drawer/types.d.ts +2 -2
- package/dist/stories/PlanCard/PlanCard.js +1 -1
- package/dist/stories/Typography/Typography.js +3 -5
- package/dist/stories/UI/ConversationalAvatarsBanner.js +4 -1
- package/dist/stories/UI/ConversationalVoiceAgentsBanner.js +3 -4
- package/dist/stories/UI/bannerAvatars.d.ts +1 -1
- package/dist/stories/UI/bannerAvatars.js +1 -1
- package/dist/utils/typography.d.ts +0 -2
- package/dist/utils/typography.js +4 -5
- package/package.json +2 -2
|
@@ -4,53 +4,107 @@ import styled from '@emotion/styled';
|
|
|
4
4
|
import { ButtonSize, ButtonHierarchy, ButtonState, ButtonShape, ButtonDisplayMode, ButtonType, } from './types';
|
|
5
5
|
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
6
6
|
import { getIconComponent } from '../../utils';
|
|
7
|
+
const isDisabled = (props) => props.$state === ButtonState.Disabled || props.$disabled;
|
|
8
|
+
const getTextColor = (props) => {
|
|
9
|
+
if (props.$destructive) {
|
|
10
|
+
if (isDisabled(props))
|
|
11
|
+
return 'var(--color-text-text-disabled)';
|
|
12
|
+
return 'var(--color-text-text-white)';
|
|
13
|
+
}
|
|
14
|
+
if (isDisabled(props))
|
|
15
|
+
return 'var(--color-text-text-inactive)';
|
|
16
|
+
switch (props.$hierarchy) {
|
|
17
|
+
case ButtonHierarchy.Primary:
|
|
18
|
+
return 'var(--color-text-text-on-accent-color)';
|
|
19
|
+
case ButtonHierarchy.PrimaryLemon:
|
|
20
|
+
return 'var(--color-text-text-title)';
|
|
21
|
+
case ButtonHierarchy.Secondary:
|
|
22
|
+
return 'var(--color-text-text-title)';
|
|
23
|
+
case ButtonHierarchy.SecondaryColor:
|
|
24
|
+
return 'var(--color-text-text-clicable)';
|
|
25
|
+
case ButtonHierarchy.SecondaryTransparent:
|
|
26
|
+
return 'var(--color-text-text-white)';
|
|
27
|
+
case ButtonHierarchy.Tertiary:
|
|
28
|
+
return 'var(--color-text-text-title)';
|
|
29
|
+
case ButtonHierarchy.TertiaryColor:
|
|
30
|
+
return 'var(--color-text-text-clicable)';
|
|
31
|
+
case ButtonHierarchy.WhiteText:
|
|
32
|
+
return 'var(--color-text-text-white)';
|
|
33
|
+
default:
|
|
34
|
+
return 'var(--color-text-text-white)';
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const ICON_ONLY_SIZE = {
|
|
38
|
+
[ButtonShape.Square]: {
|
|
39
|
+
[ButtonSize.xxs]: 32,
|
|
40
|
+
[ButtonSize.xs]: 36,
|
|
41
|
+
[ButtonSize.sm]: 40,
|
|
42
|
+
[ButtonSize.md]: 44,
|
|
43
|
+
[ButtonSize.lg]: 48,
|
|
44
|
+
[ButtonSize.xl]: 56,
|
|
45
|
+
},
|
|
46
|
+
[ButtonShape.Circle]: {
|
|
47
|
+
[ButtonSize.xxs]: 28,
|
|
48
|
+
[ButtonSize.xs]: 32,
|
|
49
|
+
[ButtonSize.sm]: 36,
|
|
50
|
+
[ButtonSize.md]: 40,
|
|
51
|
+
[ButtonSize.lg]: 44,
|
|
52
|
+
[ButtonSize.xl]: 52,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
7
55
|
const StyledButton = styled.button `
|
|
8
56
|
text-transform: none;
|
|
57
|
+
box-sizing: border-box;
|
|
9
58
|
padding: ${(props) => props.$displayIconMode === ButtonDisplayMode.Only
|
|
10
|
-
? '
|
|
59
|
+
? '0'
|
|
11
60
|
: props.$sizeStyles.padding};
|
|
61
|
+
${(props) => {
|
|
62
|
+
if (props.$displayIconMode !== ButtonDisplayMode.Only)
|
|
63
|
+
return '';
|
|
64
|
+
const box = `${ICON_ONLY_SIZE[props.$shape][props.$size]}px`;
|
|
65
|
+
return `width: ${box};
|
|
66
|
+
height: ${box};`;
|
|
67
|
+
}}
|
|
12
68
|
font-size: ${(props) => props.$sizeStyles.fontSize};
|
|
13
69
|
border-radius: ${(props) => props.$shape === ButtonShape.Square
|
|
14
70
|
? 'var(--spacing-tokens-size-in-px-radius-radius-xs)'
|
|
15
71
|
: 'var(--spacing-tokens-size-in-px-spacing-spacing-11xl)'};
|
|
16
72
|
background: ${(props) => {
|
|
17
73
|
if (props.$destructive) {
|
|
18
|
-
|
|
74
|
+
// Destructive is the one hierarchy Figma gives its own disabled fill,
|
|
75
|
+
// rather than the shared bg-button-disabled every other one uses.
|
|
76
|
+
if (isDisabled(props))
|
|
19
77
|
return 'var(--color-background-bg-element)';
|
|
20
78
|
return 'var(--color-background-bg-error)';
|
|
21
79
|
}
|
|
80
|
+
if (isDisabled(props)) {
|
|
81
|
+
switch (props.$hierarchy) {
|
|
82
|
+
case ButtonHierarchy.Tertiary:
|
|
83
|
+
case ButtonHierarchy.TertiaryColor:
|
|
84
|
+
return 'transparent';
|
|
85
|
+
case ButtonHierarchy.WhiteText:
|
|
86
|
+
// Stays a scrim when disabled so it reads over media.
|
|
87
|
+
return 'var(--primitives-white-primary-black-10)';
|
|
88
|
+
default:
|
|
89
|
+
return 'var(--color-background-bg-button-disabled)';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
22
92
|
switch (props.$hierarchy) {
|
|
23
93
|
case ButtonHierarchy.Primary:
|
|
24
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
25
|
-
return 'var(--color-background-bg-button-disabled)';
|
|
26
94
|
return 'var(--color-background-bg-brand-primary)';
|
|
27
95
|
case ButtonHierarchy.PrimaryLemon:
|
|
28
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
29
|
-
return 'var(--color-background-bg-element)';
|
|
30
96
|
return 'var(--color-background-bg-brand-secondary)';
|
|
31
97
|
case ButtonHierarchy.Secondary:
|
|
32
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
33
|
-
return 'var(--color-background-bg-button-disabled)';
|
|
34
98
|
return 'transparent';
|
|
35
99
|
case ButtonHierarchy.SecondaryColor:
|
|
36
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
37
|
-
return 'var(--color-background-bg-element)';
|
|
38
100
|
return 'var(--color-background-bg-secondary-action)';
|
|
39
101
|
case ButtonHierarchy.SecondaryTransparent:
|
|
40
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
41
|
-
return 'var(--color-background-bg-overlay-1)';
|
|
42
102
|
return 'var(--color-background-bg-button-transparent)';
|
|
43
103
|
case ButtonHierarchy.Tertiary:
|
|
44
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
45
|
-
return 'transparent';
|
|
46
104
|
return 'transparent';
|
|
47
105
|
case ButtonHierarchy.TertiaryColor:
|
|
48
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
49
|
-
return 'transparent';
|
|
50
106
|
return 'transparent';
|
|
51
107
|
case ButtonHierarchy.WhiteText:
|
|
52
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
53
|
-
return 'var(--color-background-bg-button-disabled)';
|
|
54
108
|
// Figma "White-text" fill is the Primary/Black/40 primitive
|
|
55
109
|
// (rgba(0,0,0,0.4)) — a dark scrim over media, not an overlay token.
|
|
56
110
|
return 'var(--primitives-white-primary-black-40)';
|
|
@@ -58,89 +112,43 @@ const StyledButton = styled.button `
|
|
|
58
112
|
return 'var(--color-background-bg-brand-primary)';
|
|
59
113
|
}
|
|
60
114
|
}};
|
|
61
|
-
color: ${
|
|
62
|
-
if (props.$destructive) {
|
|
63
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
64
|
-
return 'var(--color-text-text-disabled)';
|
|
65
|
-
return 'var(--color-text-text-white)';
|
|
66
|
-
}
|
|
67
|
-
switch (props.$hierarchy) {
|
|
68
|
-
case ButtonHierarchy.Primary:
|
|
69
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
70
|
-
return 'var(--color-text-text-inactive)';
|
|
71
|
-
return 'var(--color-text-text-on-accent-color)';
|
|
72
|
-
case ButtonHierarchy.PrimaryLemon:
|
|
73
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
74
|
-
return 'var(--color-text-text-subtle)';
|
|
75
|
-
return 'var(--color-text-text-title)';
|
|
76
|
-
case ButtonHierarchy.Secondary:
|
|
77
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
78
|
-
return 'var(--color-text-text-inactive)';
|
|
79
|
-
return 'var(--color-text-text-title)';
|
|
80
|
-
case ButtonHierarchy.SecondaryColor:
|
|
81
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
82
|
-
return 'var(--color-text-text-disabled)';
|
|
83
|
-
return 'var(--color-text-text-clicable)';
|
|
84
|
-
case ButtonHierarchy.SecondaryTransparent:
|
|
85
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
86
|
-
return 'var(--color-text-text-white)';
|
|
87
|
-
return 'var(--color-text-text-white)';
|
|
88
|
-
case ButtonHierarchy.Tertiary:
|
|
89
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
90
|
-
return 'var(--color-text-text-disabled)';
|
|
91
|
-
return 'var(--color-text-text-title)';
|
|
92
|
-
case ButtonHierarchy.TertiaryColor:
|
|
93
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
94
|
-
return 'var(--color-text-text-disabled)';
|
|
95
|
-
return 'var(--color-text-text-clicable)';
|
|
96
|
-
case ButtonHierarchy.WhiteText:
|
|
97
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
98
|
-
return 'var(--color-text-text-inactive)';
|
|
99
|
-
return 'var(--color-text-text-white)';
|
|
100
|
-
default:
|
|
101
|
-
return 'var(--color-text-text-white)';
|
|
102
|
-
}
|
|
103
|
-
}};
|
|
115
|
+
color: ${getTextColor};
|
|
104
116
|
border: 1px solid
|
|
105
117
|
${(props) => {
|
|
106
118
|
if (props.$destructive) {
|
|
107
|
-
if (props
|
|
119
|
+
if (isDisabled(props))
|
|
108
120
|
return 'var(--color-background-bg-element)';
|
|
109
121
|
return 'var(--color-background-bg-error)';
|
|
110
122
|
}
|
|
123
|
+
if (isDisabled(props)) {
|
|
124
|
+
switch (props.$hierarchy) {
|
|
125
|
+
case ButtonHierarchy.Tertiary:
|
|
126
|
+
case ButtonHierarchy.TertiaryColor:
|
|
127
|
+
case ButtonHierarchy.WhiteText:
|
|
128
|
+
return 'transparent';
|
|
129
|
+
default:
|
|
130
|
+
return 'var(--color-border-border-disabled)';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
111
133
|
switch (props.$hierarchy) {
|
|
112
134
|
case ButtonHierarchy.Primary:
|
|
113
|
-
|
|
114
|
-
return 'var(--color-border-border-disabled)';
|
|
115
|
-
return 'var(--color-background-bg-brand-primary)';
|
|
135
|
+
return 'var(--color-border-border-brand)';
|
|
116
136
|
case ButtonHierarchy.PrimaryLemon:
|
|
117
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
118
|
-
return 'var(--color-border-border-component)';
|
|
119
137
|
return 'var(--color-background-bg-brand-secondary)';
|
|
120
138
|
case ButtonHierarchy.Secondary:
|
|
121
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
122
|
-
return 'var(--color-border-border-disabled)';
|
|
123
139
|
return 'var(--color-border-border-component)';
|
|
124
140
|
case ButtonHierarchy.SecondaryColor:
|
|
125
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
126
|
-
return 'var(--color-border-border-component)';
|
|
127
141
|
return 'var(--color-border-border-secondary-action)';
|
|
128
142
|
case ButtonHierarchy.SecondaryTransparent:
|
|
129
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
130
|
-
return 'var(--color-border-border-disabled)';
|
|
131
143
|
return 'transparent';
|
|
132
144
|
case ButtonHierarchy.Tertiary:
|
|
133
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
134
|
-
return 'transparent';
|
|
135
145
|
return 'transparent';
|
|
136
146
|
case ButtonHierarchy.TertiaryColor:
|
|
137
|
-
if (props.$state === ButtonState.Disabled || props.$disabled)
|
|
138
|
-
return 'transparent';
|
|
139
147
|
return 'transparent';
|
|
140
148
|
case ButtonHierarchy.WhiteText:
|
|
141
149
|
return 'transparent';
|
|
142
150
|
default:
|
|
143
|
-
return 'var(--color-
|
|
151
|
+
return 'var(--color-border-border-brand)';
|
|
144
152
|
}
|
|
145
153
|
}};
|
|
146
154
|
display: flex;
|
|
@@ -181,9 +189,9 @@ const StyledButton = styled.button `
|
|
|
181
189
|
case ButtonHierarchy.SecondaryTransparent:
|
|
182
190
|
return 'var(--color-background-bg-button-transparent-hover)';
|
|
183
191
|
case ButtonHierarchy.Tertiary:
|
|
184
|
-
return 'var(--color-background-bg-
|
|
192
|
+
return 'var(--color-background-bg-button-overlay)';
|
|
185
193
|
case ButtonHierarchy.TertiaryColor:
|
|
186
|
-
return 'var(--
|
|
194
|
+
return 'var(--primitives-white-primary-white-10)';
|
|
187
195
|
case ButtonHierarchy.WhiteText:
|
|
188
196
|
// Darken the black-40 scrim one step on hover (no black-50 exists).
|
|
189
197
|
return 'var(--primitives-white-primary-black-60)';
|
|
@@ -191,6 +199,9 @@ const StyledButton = styled.button `
|
|
|
191
199
|
return 'var(--color-background-bg-brand-primary-hover)';
|
|
192
200
|
}
|
|
193
201
|
}};
|
|
202
|
+
color: ${(props) => !props.$destructive && props.$hierarchy === ButtonHierarchy.TertiaryColor
|
|
203
|
+
? 'var(--color-text-text-clicable-hover)'
|
|
204
|
+
: getTextColor(props)};
|
|
194
205
|
border-color: ${(props) => {
|
|
195
206
|
if (props.$destructive) {
|
|
196
207
|
return 'var(--primitives-desktop-primary-red-700)';
|
|
@@ -224,58 +235,38 @@ const StyledButton = styled.button `
|
|
|
224
235
|
}
|
|
225
236
|
`;
|
|
226
237
|
export const MainButton = ({ onClick, text, disabled = false, loading = false, type = ButtonType.Button, style, size = ButtonSize.xl, hierarchy = ButtonHierarchy.Primary, displayIcon, iconWeight = 'regular', displayIconMode = ButtonDisplayMode.Default, state = ButtonState.Default, shape = ButtonShape.Square, destructive = false, showLeadingIcon = false, showTrailingIcon = false, leadingIcon = 'Circle', trailingIcon = 'Circle', testId, }) => {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
[ButtonSize.lg]: 22,
|
|
231
|
-
[ButtonSize.md]: 20,
|
|
232
|
-
[ButtonSize.sm]: 18,
|
|
233
|
-
[ButtonSize.xs]: 16,
|
|
234
|
-
[ButtonSize.xxs]: 14,
|
|
235
|
-
};
|
|
236
|
-
return sizes[size] || sizes[ButtonSize.xl];
|
|
237
|
-
};
|
|
238
|
+
// Figma draws a 20px icon at every button size.
|
|
239
|
+
const iconSize = 20;
|
|
240
|
+
// Icon-only buttons take their box from ICON_ONLY_SIZE and ignore padding.
|
|
238
241
|
const getButtonSize = () => {
|
|
239
242
|
const sizes = {
|
|
240
243
|
[ButtonSize.xl]: {
|
|
241
|
-
padding:
|
|
242
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-md)'
|
|
243
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg) var(--spacing-tokens-size-in-px-spacing-spacing-3xl)',
|
|
244
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg) var(--spacing-tokens-size-in-px-spacing-spacing-3xl)',
|
|
244
245
|
fontSize: 'var(--global-font-size-3)',
|
|
245
246
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)',
|
|
246
247
|
},
|
|
247
248
|
[ButtonSize.lg]: {
|
|
248
|
-
padding:
|
|
249
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-md)'
|
|
250
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg) var(--spacing-tokens-size-in-px-spacing-spacing-2xl)',
|
|
249
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-lg) var(--spacing-tokens-size-in-px-spacing-spacing-2xl)',
|
|
251
250
|
fontSize: 'var(--global-font-size-3)',
|
|
252
251
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)',
|
|
253
252
|
},
|
|
254
253
|
[ButtonSize.md]: {
|
|
255
|
-
padding:
|
|
256
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-md)'
|
|
257
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-xl)',
|
|
254
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-xl)',
|
|
258
255
|
fontSize: 'var(--global-font-size-2)',
|
|
259
256
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)',
|
|
260
257
|
},
|
|
261
258
|
[ButtonSize.sm]: {
|
|
262
|
-
padding:
|
|
263
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-md)'
|
|
264
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-xl)',
|
|
259
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-xl)',
|
|
265
260
|
fontSize: 'var(--global-font-size-1)',
|
|
266
261
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
|
|
267
262
|
},
|
|
268
263
|
[ButtonSize.xs]: {
|
|
269
|
-
padding:
|
|
270
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-md)'
|
|
271
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-lg)',
|
|
264
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-md) var(--spacing-tokens-size-in-px-spacing-spacing-lg)',
|
|
272
265
|
fontSize: 'var(--global-font-size-1)',
|
|
273
266
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
|
|
274
267
|
},
|
|
275
268
|
[ButtonSize.xxs]: {
|
|
276
|
-
padding:
|
|
277
|
-
? 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)'
|
|
278
|
-
: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm) var(--spacing-tokens-size-in-px-spacing-spacing-md)',
|
|
269
|
+
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm) var(--spacing-tokens-size-in-px-spacing-spacing-md)',
|
|
279
270
|
fontSize: 'var(--global-font-size-0)',
|
|
280
271
|
gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
|
|
281
272
|
},
|
|
@@ -283,7 +274,7 @@ export const MainButton = ({ onClick, text, disabled = false, loading = false, t
|
|
|
283
274
|
return sizes[size] || sizes[ButtonSize.xl];
|
|
284
275
|
};
|
|
285
276
|
const iconProps = {
|
|
286
|
-
size:
|
|
277
|
+
size: iconSize,
|
|
287
278
|
color: disabled ? 'var(--color-text-text-disabled)' : 'currentColor',
|
|
288
279
|
weight: iconWeight,
|
|
289
280
|
};
|
|
@@ -18,6 +18,8 @@ const ASPECT_RATIO_BY_VIEW = {
|
|
|
18
18
|
agent: '1 / 1',
|
|
19
19
|
video: '16 / 9',
|
|
20
20
|
};
|
|
21
|
+
/** Hook the root's hover/focus rules use to reveal the action buttons. */
|
|
22
|
+
const ACTIONS_CLASS = 'EntityCard-actions';
|
|
21
23
|
const spin = keyframes `
|
|
22
24
|
from { transform: rotate(0deg); }
|
|
23
25
|
to { transform: rotate(360deg); }
|
|
@@ -34,19 +36,44 @@ export const EntityCard = ({ view = 'avatar', name, image, description = '', sho
|
|
|
34
36
|
const hasMenu = showMenu && menuItems.length > 0;
|
|
35
37
|
const isProcessing = processing && !error;
|
|
36
38
|
const canPreview = !!onPreview && !isProcessing && !error;
|
|
37
|
-
const showActions =
|
|
39
|
+
const showActions = canPreview || hasMenu;
|
|
38
40
|
const showBadge = showStatusBadge && !!statusBadgeText;
|
|
39
41
|
const showImage = !!image && !imageError;
|
|
40
42
|
const resolvedTestId = testId ?? `${entityKey}-${isVideo ? 'video' : 'entity'}-card`;
|
|
43
|
+
const handlePreviewButtonClick = (event) => {
|
|
44
|
+
event.stopPropagation();
|
|
45
|
+
onPreview?.();
|
|
46
|
+
};
|
|
41
47
|
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: hovered
|
|
42
48
|
? 'var(--color-background-bg-card-highlight-hover)'
|
|
43
|
-
: '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),
|
|
49
|
+
: '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), role: canPreview ? 'button' : undefined, tabIndex: canPreview ? 0 : undefined, "aria-label": canPreview ? (previewButtonText ?? name) : undefined, onClick: canPreview ? onPreview : undefined, onKeyDown: canPreview
|
|
50
|
+
? (event) => {
|
|
51
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
onPreview?.();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
: undefined, sx: {
|
|
57
|
+
transition: 'background-color 0.15s ease-in-out',
|
|
58
|
+
cursor: canPreview ? 'pointer' : 'default',
|
|
59
|
+
[`&:hover .${ACTIONS_CLASS}, &:focus-within .${ACTIONS_CLASS}`]: {
|
|
60
|
+
opacity: 1,
|
|
61
|
+
pointerEvents: 'auto',
|
|
62
|
+
},
|
|
63
|
+
}, "data-testid": resolvedTestId, children: [_jsxs(Box, { position: 'relative', width: '100%', borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', overflow: 'hidden', sx: { aspectRatio: imageAspectRatio }, 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: isVideo ? (_jsx(FilmSlate, { size: 64, weight: 'thin', color: 'var(--color-text-text-subtle)' })) : (_jsx(UserCircle, { size: 74, weight: 'thin', color: 'var(--color-text-text-subtle)' })) })), _jsx(Box, { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', sx: {
|
|
44
64
|
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%)',
|
|
45
65
|
opacity: hovered && !isProcessing && !error ? 1 : 0,
|
|
46
66
|
transition: 'opacity 0.15s ease-in-out',
|
|
47
67
|
pointerEvents: 'none',
|
|
48
|
-
} }), isProcessing && (_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 })] })), error && (_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-error-solid)', sx: { zIndex: 3, opacity: 0.7 }, children: [_jsx(Warning, { size: 74, color: 'var(--color-text-text-white)' }), _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.SemiBold, color: 'var(--color-text-text-white)', children: errorText })] })), showBadge && (_jsx(Box, { position: 'absolute', top: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', left: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', sx: { zIndex: 2 }, children: _jsx(Badge, { text: statusBadgeText, color: statusBadgeColor, size: BadgeSize.md, showIcon: true, icon: 'Circle', iconWeight: 'fill', iconSize: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)' }) })), 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: {
|
|
49
|
-
|
|
68
|
+
} }), isProcessing && (_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 })] })), error && (_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-error-solid)', sx: { zIndex: 3, opacity: 0.7 }, children: [_jsx(Warning, { size: 74, color: 'var(--color-text-text-white)' }), _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.SemiBold, color: 'var(--color-text-text-white)', children: errorText })] })), showBadge && (_jsx(Box, { position: 'absolute', top: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', left: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', sx: { zIndex: 2 }, children: _jsx(Badge, { text: statusBadgeText, color: statusBadgeColor, size: BadgeSize.md, showIcon: true, icon: 'Circle', iconWeight: 'fill', iconSize: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)' }) })), showActions && (_jsxs(Box, { className: ACTIONS_CLASS, 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: {
|
|
69
|
+
zIndex: 4,
|
|
70
|
+
transition: 'opacity 0.15s ease-in-out',
|
|
71
|
+
'@media (hover: hover)': {
|
|
72
|
+
opacity: 0,
|
|
73
|
+
pointerEvents: 'none',
|
|
74
|
+
},
|
|
75
|
+
}, children: [canPreview &&
|
|
76
|
+
(previewButtonText ? (_jsx(MainButton, { text: previewButtonText, showLeadingIcon: true, leadingIcon: previewIcon, iconWeight: 'fill', hierarchy: ButtonHierarchy.SecondaryTransparent, size: ButtonSize.sm, onClick: handlePreviewButtonClick, testId: `${entityKey}-preview-button` })) : (_jsx(MainButton, { displayIcon: previewIcon, displayIconMode: ButtonDisplayMode.Only, hierarchy: ButtonHierarchy.SecondaryTransparent, size: ButtonSize.sm, onClick: handlePreviewButtonClick, testId: `${entityKey}-preview-button` }))), hasMenu && (_jsx(Box, { onClick: (event) => event.stopPropagation(), children: _jsx(Menu, { items: menuItems, testKey: entityKey, size: ButtonSize.sm }) }))] })), isVideo ? (_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: {
|
|
50
77
|
zIndex: 2,
|
|
51
78
|
pointerEvents: 'none',
|
|
52
79
|
backgroundImage: 'linear-gradient(rgba(45, 38, 55, 0) 0%, rgba(45, 38, 55, 0.16) 34%, rgba(45, 38, 55, 0.64) 100%)',
|
|
@@ -118,7 +118,7 @@ export const AutoComplete = ({ options, value, onChange, leadingIcon = 'Magnifyi
|
|
|
118
118
|
}, [options, searchText]);
|
|
119
119
|
const sizeToken = getTypographySizeToken(TypographySize.TextS);
|
|
120
120
|
const weightToken = getTypographyWeightToken(TypographyWeight.Regular);
|
|
121
|
-
const { fontSize, fontWeight, fontFamily, lineHeight,
|
|
121
|
+
const { fontSize, fontWeight, fontFamily, lineHeight, paragraphIndent, textDecoration, textTransform, } = getTextStyles(sizeToken, weightToken);
|
|
122
122
|
return (_jsxs(Box, { display: 'flex', flexDirection: 'column', position: 'relative', width: "100%", children: [_jsxs(Box, { display: 'flex', flexDirection: 'row', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)', paddingX: 'var(--spacing-tokens-size-in-px-spacing-spacing-md)', paddingY: 'var(--spacing-tokens-size-in-px-spacing-spacing-sm)', alignItems: 'center', justifyContent: 'center', border: `1px solid ${focused ? 'var(--color-border-border-component-active)' : 'var(--color-border-border-component)'}`, borderRadius: '4px', bgcolor: disabled
|
|
123
123
|
? 'var(--color-background-bg-component-disabled)'
|
|
124
124
|
: 'var(--color-background-bg-component)', children: [getIconComponent(leadingIcon, {
|
|
@@ -133,10 +133,8 @@ export const AutoComplete = ({ options, value, onChange, leadingIcon = 'Magnifyi
|
|
|
133
133
|
fontSize: fontSize,
|
|
134
134
|
fontWeight: fontWeight,
|
|
135
135
|
fontFamily: fontFamily + ', sans-serif',
|
|
136
|
-
lineHeight: lineHeight
|
|
137
|
-
letterSpacing: letterSpacing,
|
|
136
|
+
lineHeight: lineHeight,
|
|
138
137
|
textIndent: paragraphIndent,
|
|
139
|
-
marginBottom: paragraphSpacing,
|
|
140
138
|
textTransform: textTransform,
|
|
141
139
|
textDecoration: textDecoration,
|
|
142
140
|
color: disabled
|
|
@@ -2,6 +2,56 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Checkbox as MuiCheckbox } from '@mui/material';
|
|
3
3
|
import { CheckboxType } from './types';
|
|
4
4
|
import { Typography, TypographySize, TypographyWeight } from '../Typography';
|
|
5
|
+
import { getIconComponent } from '../../utils';
|
|
6
|
+
/** Control is 20px; the check insets 12.5% and the radio dot 31.25% per Figma. */
|
|
7
|
+
const CONTROL_SIZE = 20;
|
|
8
|
+
const CHECK_SIZE = 15;
|
|
9
|
+
const RADIO_DOT_SIZE = 7.5;
|
|
10
|
+
const RADIUS_FULL = 'var(--spacing-tokens-size-in-px-radius-radius-full)';
|
|
11
|
+
const FG_TERTIARY = 'var(--color-foreground-fg-tertiary)';
|
|
12
|
+
const FG_DISABLED = 'var(--color-foreground-fg-disabled)';
|
|
13
|
+
const FG_ON_ACCENT = 'var(--color-foreground-fg-on-primary-accent-color)';
|
|
14
|
+
/** Class hook so the MUI root can drive the control's hover border. */
|
|
15
|
+
const CONTROL_CLASS = 'BeyCheckbox-control';
|
|
16
|
+
const accentFor = (type) => type === CheckboxType.Radio
|
|
17
|
+
? 'var(--color-foreground-fg-accent-violet)'
|
|
18
|
+
: 'var(--color-foreground-fg-violet)';
|
|
19
|
+
const controlStyles = (type, checked, disabled) => ({
|
|
20
|
+
boxSizing: 'border-box',
|
|
21
|
+
width: `${CONTROL_SIZE}px`,
|
|
22
|
+
height: `${CONTROL_SIZE}px`,
|
|
23
|
+
display: 'flex',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
justifyContent: 'center',
|
|
26
|
+
flexShrink: 0,
|
|
27
|
+
borderRadius: type === CheckboxType.Radio
|
|
28
|
+
? RADIUS_FULL
|
|
29
|
+
: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
|
|
30
|
+
// Only checked + enabled is a solid fill; every other state is an outline,
|
|
31
|
+
// disabled included — so a disabled checked control stays hollow.
|
|
32
|
+
border: checked && !disabled
|
|
33
|
+
? 'none'
|
|
34
|
+
: `1px solid ${disabled ? FG_DISABLED : FG_TERTIARY}`,
|
|
35
|
+
backgroundColor: checked && !disabled ? accentFor(type) : 'transparent',
|
|
36
|
+
transition: 'all 0.2s ease-in-out',
|
|
37
|
+
});
|
|
38
|
+
/** The check glyph or radio dot shown once the control is checked. */
|
|
39
|
+
const ControlMark = ({ type, disabled, }) => {
|
|
40
|
+
const color = disabled ? FG_DISABLED : FG_ON_ACCENT;
|
|
41
|
+
if (type === CheckboxType.Radio) {
|
|
42
|
+
return (_jsx(Box, { sx: {
|
|
43
|
+
width: `${RADIO_DOT_SIZE}px`,
|
|
44
|
+
height: `${RADIO_DOT_SIZE}px`,
|
|
45
|
+
borderRadius: RADIUS_FULL,
|
|
46
|
+
backgroundColor: color,
|
|
47
|
+
} }));
|
|
48
|
+
}
|
|
49
|
+
return getIconComponent('Check', {
|
|
50
|
+
size: `${CHECK_SIZE}px`,
|
|
51
|
+
weight: 'bold',
|
|
52
|
+
color,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
5
55
|
export const Checkbox = ({ type = CheckboxType.Checkbox, label, checked, disabled, required, onChange, style, }) => {
|
|
6
56
|
const props = {
|
|
7
57
|
checked,
|
|
@@ -18,48 +68,22 @@ export const Checkbox = ({ type = CheckboxType.Checkbox, label, checked, disable
|
|
|
18
68
|
onChange(event);
|
|
19
69
|
}
|
|
20
70
|
};
|
|
21
|
-
|
|
71
|
+
// A checked control has no border, so the hover colour is a no-op there and
|
|
72
|
+
// this stays correct even when MUI owns the checked state. The checkbox is
|
|
73
|
+
// hovered via its MUI root (the input overlays the control), the radio
|
|
74
|
+
// directly.
|
|
75
|
+
const hoverBorder = { borderColor: accentFor(type) };
|
|
76
|
+
const checkboxHoverSx = disabled
|
|
77
|
+
? undefined
|
|
78
|
+
: { [`&:hover .${CONTROL_CLASS}`]: hoverBorder };
|
|
79
|
+
const radioHoverSx = disabled ? undefined : { '&:hover': hoverBorder };
|
|
80
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)', gap: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)', sx: style, children: [type === CheckboxType.Checkbox ? (_jsx(MuiCheckbox, { ...props, icon: _jsx(Box, { className: CONTROL_CLASS, sx: controlStyles(type, false, !!disabled) }), checkedIcon: _jsx(Box, { className: CONTROL_CLASS, sx: controlStyles(type, true, !!disabled), children: _jsx(ControlMark, { type: type, disabled: !!disabled }) }), sx: {
|
|
22
81
|
padding: 0,
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
borderRadius: 'var(--spacing-tokens-size-in-px-spacing-spacing-xs)',
|
|
28
|
-
'&:hover': {
|
|
29
|
-
color: 'var(--color-background-bg-brand-primary-hover)',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
} })) : type === CheckboxType.Radio ? (_jsx(Box, { onClick: handleRadioClick, sx: {
|
|
33
|
-
width: '20px',
|
|
34
|
-
height: '20px',
|
|
35
|
-
borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-full)',
|
|
36
|
-
border: checked ? '6px solid' : '1px solid',
|
|
37
|
-
borderColor: disabled
|
|
38
|
-
? 'var(--color-background-bg-button-disabled)'
|
|
39
|
-
: checked
|
|
40
|
-
? 'var(--color-background-bg-brand-primary)'
|
|
41
|
-
: 'var(--color-background-bg-button-disabled)',
|
|
42
|
-
display: 'flex',
|
|
43
|
-
alignItems: 'center',
|
|
44
|
-
justifyContent: 'center',
|
|
82
|
+
'&:hover': { backgroundColor: 'transparent' },
|
|
83
|
+
...checkboxHoverSx,
|
|
84
|
+
} })) : type === CheckboxType.Radio ? (_jsx(Box, { onClick: handleRadioClick, className: CONTROL_CLASS, sx: {
|
|
85
|
+
...controlStyles(type, !!checked, !!disabled),
|
|
45
86
|
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
boxSizing: 'border-box',
|
|
49
|
-
transition: 'all 0.2s ease-in-out',
|
|
50
|
-
'&:hover': !disabled
|
|
51
|
-
? {
|
|
52
|
-
borderColor: 'var(--color-background-bg-brand-primary-hover)',
|
|
53
|
-
}
|
|
54
|
-
: undefined,
|
|
55
|
-
'&::after': {
|
|
56
|
-
content: '""',
|
|
57
|
-
position: 'absolute',
|
|
58
|
-
width: '10px',
|
|
59
|
-
height: '10px',
|
|
60
|
-
borderRadius: 'var(--spacing-tokens-size-in-px-radius-radius-full)',
|
|
61
|
-
backgroundColor: 'transparent',
|
|
62
|
-
transition: 'all 0.2s ease-in-out',
|
|
63
|
-
},
|
|
64
|
-
} })) : null, label && (_jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Medium, children: label }))] }));
|
|
87
|
+
...radioHoverSx,
|
|
88
|
+
}, children: checked && _jsx(ControlMark, { type: type, disabled: !!disabled }) })) : null, label && (_jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Medium, children: label }))] }));
|
|
65
89
|
};
|
|
@@ -24,6 +24,7 @@ const COLOR = {
|
|
|
24
24
|
component: 'var(--color-background-bg-component)',
|
|
25
25
|
borderComponent: 'var(--color-border-border-component)',
|
|
26
26
|
borderBrand: 'var(--color-border-border-brand)',
|
|
27
|
+
borderDarkOnly: 'var(--color-border-border-only-for-dark-mode)',
|
|
27
28
|
fgSecondary: 'var(--color-foreground-fg-secondary)',
|
|
28
29
|
};
|
|
29
30
|
const RADIUS_FULL = 'var(--spacing-tokens-size-in-px-radius-radius-full)';
|
|
@@ -106,7 +107,7 @@ const CalendarCell = ({ label, onClick, disabled = false, muted = false, today =
|
|
|
106
107
|
boxSizing: 'border-box',
|
|
107
108
|
cursor: interactive ? 'pointer' : 'default',
|
|
108
109
|
...hoverSx,
|
|
109
|
-
}, children: _jsx(Box, { className: "datepicker-cell-inner", display: "flex", alignItems: "center", justifyContent: "center", width: "28px", height: "28px", borderRadius: "14px", bgcolor: innerBg, children: _jsx(Typography, { className: "datepicker-cell-label", size: TypographySize.TextS, weight: TypographyWeight.Regular, color: textColor,
|
|
110
|
+
}, children: _jsx(Box, { className: "datepicker-cell-inner", display: "flex", alignItems: "center", justifyContent: "center", width: "28px", height: "28px", borderRadius: "14px", bgcolor: innerBg, children: _jsx(Typography, { className: "datepicker-cell-label", size: TypographySize.TextS, weight: TypographyWeight.Regular, color: textColor, children: label }) }) }));
|
|
110
111
|
};
|
|
111
112
|
const CalendarHeader = ({ title, onPrev, onNext, onTitleClick, }) => {
|
|
112
113
|
const caretButton = (icon, onClick) => (_jsx(Box, { onClick: onClick, display: "flex", alignItems: "center", justifyContent: "center", padding: "10px", borderRadius: RADIUS_XS, flexShrink: 0, sx: {
|
|
@@ -279,7 +280,7 @@ export const DatePicker = ({ label = 'Select date', placeholder = 'Select a date
|
|
|
279
280
|
'aria-label': 'Clear date',
|
|
280
281
|
role: 'button',
|
|
281
282
|
tabIndex: 0,
|
|
282
|
-
}) }))] }), _jsx(Popper, { open: open, anchorEl: anchorRef.current, placement: "bottom-start", style: { zIndex: 1300 }, children: _jsxs(Box, { bgcolor: COLOR.card, borderRadius: SPACING_MD, mt: "4px", paddingX: "24px", paddingY: "20px", width: "
|
|
283
|
+
}) }))] }), _jsx(Popper, { open: open, anchorEl: anchorRef.current, placement: "bottom-start", style: { zIndex: 1300 }, children: _jsxs(Box, { bgcolor: COLOR.card, border: `1px solid ${COLOR.borderDarkOnly}`, borderRadius: SPACING_MD, mt: "4px", paddingX: "24px", paddingY: "20px", width: "330px", role: "dialog", sx: {
|
|
283
284
|
boxSizing: 'border-box',
|
|
284
285
|
boxShadow: '0px 20px 24px -4px rgba(34, 7, 56, 0.08)',
|
|
285
286
|
}, children: [view === 'date' && renderDateView(), view === 'month' && renderMonthView(), view === 'year' && renderYearView()] }) })] }) }));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { DrawerCreditsCardProps } from './types';
|
|
3
3
|
/**
|
|
4
|
-
* Compact "Upgrade
|
|
4
|
+
* Compact "Upgrade Plan" credits card for the {@link Drawer} footer. Shows a
|
|
5
5
|
* progress bar and a credits caption, with an info tooltip listing the credit
|
|
6
6
|
* conversion rates. When collapsed it shrinks to the gem glyph and reveals the
|
|
7
7
|
* full details (and an upgrade action) in a hover popover. Fully theme-aware.
|
|
@@ -128,13 +128,13 @@ const PopoverGroup = styled.div `
|
|
|
128
128
|
`;
|
|
129
129
|
const InfoLines = ({ lines }) => (_jsx("div", { style: { display: 'flex', flexDirection: 'column' }, children: lines.map((line, i) => (_jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.Regular, color: "var(--color-text-text-white)", children: line }, i))) }));
|
|
130
130
|
/**
|
|
131
|
-
* Compact "Upgrade
|
|
131
|
+
* Compact "Upgrade Plan" credits card for the {@link Drawer} footer. Shows a
|
|
132
132
|
* progress bar and a credits caption, with an info tooltip listing the credit
|
|
133
133
|
* conversion rates. When collapsed it shrinks to the gem glyph and reveals the
|
|
134
134
|
* full details (and an upgrade action) in a hover popover. Fully theme-aware.
|
|
135
135
|
*/
|
|
136
|
-
export const DrawerCreditsCard = ({ size = DrawerSize.Expanded, usedCredits = 0, maxCredits = 0, upgradeLabel = 'Upgrade
|
|
137
|
-
const caption = creditsCaption ?? `${usedCredits} credits used
|
|
136
|
+
export const DrawerCreditsCard = ({ size = DrawerSize.Expanded, usedCredits = 0, maxCredits = 0, upgradeLabel = 'Upgrade Plan', creditsCaption, icon, infoLines = DEFAULT_INFO_LINES, onUpgradeClick, className, style, testId, }) => {
|
|
137
|
+
const caption = creditsCaption ?? `${usedCredits} credits used of ${maxCredits}`;
|
|
138
138
|
const glyph = icon ? (getIconComponent(icon, { size: 20 })) : (_jsx(GemIcon, { size: 20 }));
|
|
139
139
|
if (size === DrawerSize.Collapsed) {
|
|
140
140
|
return (_jsx(Popover, { placement: "right", content: _jsxs(PopoverBody, { children: [_jsx(PopoverButton, { type: "button", onClick: () => onUpgradeClick?.(), children: _jsx(Typography, { size: TypographySize.TextS, weight: TypographyWeight.SemiBold, color: "var(--color-text-text-on-accent-color)", children: upgradeLabel }) }), _jsxs(PopoverGroup, { children: [_jsx(CreditsBar, { used: usedCredits, max: maxCredits }), _jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: "var(--color-text-text-white)", children: caption })] }), _jsx(InfoLines, { lines: infoLines })] }), children: _jsx(CollapsedBox, { className: className, style: style, "data-testid": testId, onClick: () => onUpgradeClick?.(), children: glyph }) }));
|
|
@@ -48,10 +48,10 @@ export interface DrawerCreditsCardProps {
|
|
|
48
48
|
usedCredits?: number;
|
|
49
49
|
/** Total credits available in the plan. */
|
|
50
50
|
maxCredits?: number;
|
|
51
|
-
/** Title/link label. Defaults to "Upgrade
|
|
51
|
+
/** Title/link label. Defaults to "Upgrade Plan". */
|
|
52
52
|
upgradeLabel?: string;
|
|
53
53
|
/**
|
|
54
|
-
* Overrides the auto-generated "{used} credits used
|
|
54
|
+
* Overrides the auto-generated "{used} credits used of {max}" caption.
|
|
55
55
|
*/
|
|
56
56
|
creditsCaption?: string;
|
|
57
57
|
/** Leading icon. Defaults to the gem glyph. */
|
|
@@ -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(CheckIcon, { color: CheckIconColor.Violet, size: CheckIconSize.xs, type: CheckIconType.Duotone })), _jsx(Typography, { size: TypographySize.TextM, weight: isHeading
|
|
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.xs, 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
|
})] }))] }));
|
|
@@ -4,19 +4,17 @@ import { getTextStyles, getTypographySizeToken, getTypographyWeightToken, } from
|
|
|
4
4
|
export const Typography = ({ text, color, size = TypographySize.HeadingL, weight = TypographyWeight.Bold, className, required = false, textStyle, children, title, }) => {
|
|
5
5
|
const sizeToken = getTypographySizeToken(size);
|
|
6
6
|
const weightToken = getTypographyWeightToken(weight);
|
|
7
|
-
const { fontSize, fontWeight, fontFamily, lineHeight,
|
|
7
|
+
const { fontSize, fontWeight, fontFamily, lineHeight, paragraphIndent, textDecoration, textTransform, } = getTextStyles(sizeToken, weightToken);
|
|
8
8
|
const requiredColor = 'var(--color-text-text-error)';
|
|
9
9
|
return (_jsxs("span", { className: className, style: {
|
|
10
10
|
fontSize: fontSize,
|
|
11
11
|
fontWeight: fontWeight,
|
|
12
12
|
fontFamily: fontFamily + ', sans-serif',
|
|
13
|
-
lineHeight: lineHeight
|
|
14
|
-
letterSpacing: letterSpacing,
|
|
13
|
+
lineHeight: lineHeight,
|
|
15
14
|
textIndent: paragraphIndent,
|
|
16
|
-
marginBottom: paragraphSpacing,
|
|
17
15
|
textTransform: textTransform,
|
|
18
16
|
textDecoration: textDecoration,
|
|
19
|
-
color: color
|
|
17
|
+
color: color,
|
|
20
18
|
...textStyle,
|
|
21
19
|
}, title: title, children: [children || text, required && _jsx("span", { style: { color: requiredColor }, children: ' *' })] }));
|
|
22
20
|
};
|
|
@@ -36,7 +36,10 @@ export const ConversationalAvatarsBanner = ({ title, description, actions = [],
|
|
|
36
36
|
padding: 'var(--spacing-tokens-size-in-px-spacing-spacing-xl) var(--spacing-tokens-size-in-px-spacing-spacing-lg)',
|
|
37
37
|
},
|
|
38
38
|
...customStyle,
|
|
39
|
-
}, "data-testid": testId, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-xl)", flex: 1, minWidth: 0, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)", children: [title && (_jsx(Typography, { size: TypographySize.HeadingM, weight: TypographyWeight.Bold, color: "var(--color-text-text-title)", children: title })), description && (_jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: "var(--color-text-text-label)", children: description }))] }), actions.length > 0 && (_jsx(Box, { display: "flex", alignItems: "center", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)",
|
|
39
|
+
}, "data-testid": testId, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-xl)", flex: 1, minWidth: 0, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)", children: [title && (_jsx(Typography, { size: TypographySize.HeadingM, weight: TypographyWeight.Bold, color: "var(--color-text-text-title)", children: title })), description && (_jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: "var(--color-text-text-label)", children: description }))] }), actions.length > 0 && (_jsx(Box, { display: "flex", alignItems: "center", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)", sx: {
|
|
40
|
+
flexWrap: 'wrap',
|
|
41
|
+
'& button': { whiteSpace: 'nowrap' },
|
|
42
|
+
}, children: actions.map(renderAction) }))] }), _jsx(Box, { flexShrink: 0, alignSelf: "stretch", position: "relative", overflow: "hidden", width: `${AVATAR_TILE_WIDTH}px`, sx: {
|
|
40
43
|
marginY: 'calc(-1 * var(--spacing-tokens-size-in-px-spacing-spacing-3xl))',
|
|
41
44
|
[MOBILE]: {
|
|
42
45
|
marginY: 'calc(-1 * var(--spacing-tokens-size-in-px-spacing-spacing-xl))',
|
|
@@ -25,12 +25,11 @@ export const ConversationalVoiceAgentsBanner = ({ title, description, actions =
|
|
|
25
25
|
},
|
|
26
26
|
...customStyle,
|
|
27
27
|
}, "data-testid": testId, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-xl)", flex: 1, minWidth: 0, children: [_jsxs(Box, { display: "flex", flexDirection: "column", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)", children: [title && (_jsx(Typography, { size: TypographySize.HeadingM, weight: TypographyWeight.Bold, color: "var(--color-text-text-title)", children: title })), description && (_jsx(Typography, { size: TypographySize.TextXS, weight: TypographyWeight.Regular, color: "var(--color-text-text-label)", children: description }))] }), actions.length > 0 && (_jsx(Box, { display: "flex", alignItems: "center", gap: "var(--spacing-tokens-size-in-px-spacing-spacing-md)", sx: {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
flexWrap: 'wrap',
|
|
29
|
+
'& button': { whiteSpace: 'nowrap' },
|
|
30
30
|
[MOBILE]: {
|
|
31
31
|
width: '100%',
|
|
32
|
-
'& > *': { flex: 1
|
|
33
|
-
'& button': { width: '100%' },
|
|
32
|
+
'& > *': { flex: '1 1 auto' },
|
|
34
33
|
},
|
|
35
34
|
}, children: actions.map(renderAction) }))] }), _jsxs(Box, { position: "relative", flexShrink: 0, overflow: "hidden", width: `${PREVIEW_WIDTH}px`, height: `${PREVIEW_HEIGHT}px`, borderRadius: "var(--spacing-tokens-size-in-px-radius-radius-sm)", sx: {
|
|
36
35
|
[MOBILE]: {
|
|
@@ -8,5 +8,5 @@ export declare const BANNER_AVATARS: {
|
|
|
8
8
|
};
|
|
9
9
|
export declare const AVATAR_TILE_BACKGROUND = "linear-gradient(180deg, #e9e9e9 0%, #beb1df 100%)";
|
|
10
10
|
export declare const BANNER_VIDEO_PREVIEW = "https://storage.googleapis.com/bey-dev-public/yuruo-preview.png";
|
|
11
|
-
export declare const AVATAR_TILE_WIDTH =
|
|
11
|
+
export declare const AVATAR_TILE_WIDTH = 120;
|
|
12
12
|
export declare const AVATAR_TILE_HEIGHT = 150;
|
|
@@ -16,5 +16,5 @@ export const AVATAR_TILE_BACKGROUND = 'linear-gradient(180deg, #e9e9e9 0%, #beb1
|
|
|
16
16
|
// Poster/thumbnail shown in the ConversationalVoiceAgentsBanner video preview.
|
|
17
17
|
export const BANNER_VIDEO_PREVIEW = `${AVATAR_BASE}/yuruo-preview.png`;
|
|
18
18
|
// Size of a single avatar tile in the collages.
|
|
19
|
-
export const AVATAR_TILE_WIDTH =
|
|
19
|
+
export const AVATAR_TILE_WIDTH = 120;
|
|
20
20
|
export const AVATAR_TILE_HEIGHT = 150;
|
|
@@ -6,9 +6,7 @@ export declare const getTextStyles: (sizeToken: string, weightToken: string) =>
|
|
|
6
6
|
fontWeight: string;
|
|
7
7
|
fontFamily: string;
|
|
8
8
|
lineHeight: string;
|
|
9
|
-
letterSpacing: string;
|
|
10
9
|
paragraphIndent: string;
|
|
11
|
-
paragraphSpacing: string;
|
|
12
10
|
textDecoration: string;
|
|
13
11
|
textTransform: "uppercase" | "none";
|
|
14
12
|
};
|
package/dist/utils/typography.js
CHANGED
|
@@ -26,10 +26,11 @@ export const getTextStyles = (sizeToken, weightToken) => {
|
|
|
26
26
|
const fontSize = `var(--global-${sizeToken}-${weightToken}-font-size)`;
|
|
27
27
|
const fontWeight = `var(--global-${sizeToken}-${weightToken}-font-weight)`;
|
|
28
28
|
const fontFamily = `var(--global-${sizeToken}-${weightToken}-font-family)`;
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// The line-height tokens are unitless numbers, and var() substitutes tokens
|
|
30
|
+
// rather than text: `var(--x)px` yields `24 px`, not `24px`. calc() is what
|
|
31
|
+
// actually attaches the unit.
|
|
32
|
+
const lineHeight = `calc(var(--global-${sizeToken}-${weightToken}-line-height) * 1px)`;
|
|
31
33
|
const paragraphIndent = `var(--global-${sizeToken}-${weightToken}-paragraph-indent)`;
|
|
32
|
-
const paragraphSpacing = `var(--global-${sizeToken}-${weightToken}-paragraph-spacing)`;
|
|
33
34
|
const textDecoration = `var(--global-${sizeToken}-${weightToken}-text-decoration)`;
|
|
34
35
|
const textTransform = getTextTransform(sizeToken, weightToken);
|
|
35
36
|
return {
|
|
@@ -37,9 +38,7 @@ export const getTextStyles = (sizeToken, weightToken) => {
|
|
|
37
38
|
fontWeight,
|
|
38
39
|
fontFamily,
|
|
39
40
|
lineHeight,
|
|
40
|
-
letterSpacing,
|
|
41
41
|
paragraphIndent,
|
|
42
|
-
paragraphSpacing,
|
|
43
42
|
textDecoration,
|
|
44
43
|
textTransform,
|
|
45
44
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beydesign/storybook",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@beydesign/tokens": "^0.1.
|
|
28
|
+
"@beydesign/tokens": "^0.1.2",
|
|
29
29
|
"@emotion/react": "^11.14.0",
|
|
30
30
|
"@emotion/styled": "^11.14.1",
|
|
31
31
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|