@apify/ui-library 1.155.1 → 1.156.0
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/components/button/button.d.ts +6 -33
- package/dist/components/button/button.d.ts.map +1 -1
- package/dist/components/button/button.js +46 -231
- package/dist/components/button/button.style.d.ts +37 -0
- package/dist/components/button/button.style.d.ts.map +1 -0
- package/dist/components/button/button.style.js +250 -0
- package/dist/components/icon_button/icon_button.js +2 -1
- package/dist/components/select/select.js +2 -2
- package/dist/components/select/select.test_ids.d.ts +1 -0
- package/dist/components/select/select.test_ids.d.ts.map +1 -1
- package/dist/components/select/select.test_ids.js +2 -1
- package/dist/components/spinner/spinner.d.ts.map +1 -1
- package/dist/components/spinner/spinner.js +3 -0
- package/dist/components/spinner/spinner.test_ids.d.ts +4 -0
- package/dist/components/spinner/spinner.test_ids.d.ts.map +1 -0
- package/dist/components/spinner/spinner.test_ids.js +4 -0
- package/dist/components/tabs/tab.d.ts.map +1 -1
- package/dist/components/tabs/tab.js +1 -1
- package/dist/files_hash_at_build.txt +1 -1
- package/dist/index.js +2 -1
- package/dist/src/components/button/button.d.ts +6 -33
- package/dist/src/components/button/button.d.ts.map +1 -1
- package/dist/src/components/button/button.js +24 -221
- package/dist/src/components/button/button.js.map +1 -1
- package/dist/src/components/button/button.style.d.ts +37 -0
- package/dist/src/components/button/button.style.d.ts.map +1 -0
- package/dist/src/components/button/button.style.js +256 -0
- package/dist/src/components/button/button.style.js.map +1 -0
- package/dist/src/components/select/select.js +2 -2
- package/dist/src/components/select/select.js.map +1 -1
- package/dist/src/components/select/select.test_ids.d.ts +1 -0
- package/dist/src/components/select/select.test_ids.d.ts.map +1 -1
- package/dist/src/components/select/select.test_ids.js +2 -0
- package/dist/src/components/select/select.test_ids.js.map +1 -1
- package/dist/src/components/spinner/spinner.d.ts.map +1 -1
- package/dist/src/components/spinner/spinner.js +2 -1
- package/dist/src/components/spinner/spinner.js.map +1 -1
- package/dist/src/components/spinner/spinner.test_ids.d.ts +4 -0
- package/dist/src/components/spinner/spinner.test_ids.d.ts.map +1 -0
- package/dist/src/components/spinner/spinner.test_ids.js +4 -0
- package/dist/src/components/spinner/spinner.test_ids.js.map +1 -0
- package/dist/src/components/tabs/tab.d.ts.map +1 -1
- package/dist/src/components/tabs/tab.js +1 -1
- package/dist/src/components/tabs/tab.js.map +1 -1
- package/dist/src/test_ids.d.ts +2 -1
- package/dist/src/test_ids.d.ts.map +1 -1
- package/dist/src/test_ids.js +2 -1
- package/dist/src/test_ids.js.map +1 -1
- package/dist/test_ids.d.ts +2 -1
- package/dist/test_ids.d.ts.map +1 -1
- package/dist/test_ids.js +3 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/button/button.stories.tsx +55 -0
- package/src/components/button/button.style.ts +311 -0
- package/src/components/button/button.tsx +75 -293
- package/src/components/select/select.test_ids.ts +3 -0
- package/src/components/select/select.tsx +2 -2
- package/src/components/spinner/spinner.test_ids.ts +3 -0
- package/src/components/spinner/spinner.tsx +8 -1
- package/src/components/tabs/tab.tsx +6 -1
- package/src/test_ids.ts +2 -1
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import type { AriaAttributes } from 'react';
|
|
2
2
|
import type React from 'react';
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
|
-
import styled, { css } from 'styled-components';
|
|
5
4
|
|
|
6
|
-
import { ExternalLinkIcon
|
|
5
|
+
import { ExternalLinkIcon } from '@apify/ui-icons';
|
|
7
6
|
|
|
8
|
-
import {
|
|
9
|
-
import { type WithRequired, type WithTransientProps } from '../../type_utils';
|
|
7
|
+
import { type WithRequired } from '../../type_utils';
|
|
10
8
|
import { useSharedUiDependencies } from '../../ui_dependency_provider';
|
|
11
|
-
import {
|
|
9
|
+
import { type MarginSpacingProps, type RegularBoxProps } from '../box';
|
|
12
10
|
import { isUrlExternal, Link, type LinkProps } from '../link';
|
|
11
|
+
import { AnimatedBorder, BUTTON_SIZE_VARIANTS_CSS, StyledButton } from './button.style';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
BUTTON_COLOR_VARIANTS_CSS,
|
|
15
|
+
BUTTON_SIZE_VARIANTS_CSS,
|
|
16
|
+
getButtonColorStyles,
|
|
17
|
+
getButtonSizeStyles,
|
|
18
|
+
} from './button.style';
|
|
13
19
|
|
|
14
20
|
export type ButtonSize = 'extraLarge' | 'large' | 'medium' | 'small' | 'extraSmall';
|
|
15
|
-
type ButtonColor = 'default' | 'success' | 'danger' | 'primaryBlack';
|
|
16
|
-
type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
|
|
21
|
+
export type ButtonColor = 'default' | 'success' | 'danger' | 'primaryBlack';
|
|
22
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
|
|
17
23
|
type ButtonType = 'button' | 'submit';
|
|
18
24
|
|
|
19
25
|
export interface TransientButtonProps {
|
|
@@ -34,7 +40,13 @@ export interface RegularButtonProps {
|
|
|
34
40
|
type ButtonAriaProps = Pick<AriaAttributes, 'aria-label' | 'aria-labelledby'>;
|
|
35
41
|
|
|
36
42
|
// Props shared for both types of the button
|
|
37
|
-
export type CommonButtonProps = RegularButtonProps &
|
|
43
|
+
export type CommonButtonProps = RegularButtonProps &
|
|
44
|
+
ButtonAriaProps &
|
|
45
|
+
TransientButtonProps &
|
|
46
|
+
MarginSpacingProps & {
|
|
47
|
+
// The animated shine sweep effect is only rendered for the primary variant.
|
|
48
|
+
animated?: boolean;
|
|
49
|
+
};
|
|
38
50
|
// Regular button must have onClick defined
|
|
39
51
|
export type ButtonProps = CommonButtonProps & WithRequired<RegularBoxProps, 'onClick'>;
|
|
40
52
|
// OR it can pass to to become anchor link - in that case onClick is not needed
|
|
@@ -45,264 +57,6 @@ function isAnchorButton(props: ButtonProps | AnchorButtonProps): props is Anchor
|
|
|
45
57
|
return (props as AnchorButtonProps).to !== undefined;
|
|
46
58
|
}
|
|
47
59
|
|
|
48
|
-
type ButtonColorCombinations = {
|
|
49
|
-
[Type in ButtonVariant]: {
|
|
50
|
-
[Size in ButtonColor]: {
|
|
51
|
-
textColor: string;
|
|
52
|
-
borderColor: string;
|
|
53
|
-
backgroundColor: string;
|
|
54
|
-
|
|
55
|
-
// hover & active state effects
|
|
56
|
-
actionTextColor?: string;
|
|
57
|
-
// only exception is primary outlined button
|
|
58
|
-
actionBorderColor?: string;
|
|
59
|
-
|
|
60
|
-
// hover state effects override
|
|
61
|
-
hoverColor?: string;
|
|
62
|
-
// Optional gradient overlay on hover (e.g., for primaryBlack)
|
|
63
|
-
hoverGradient?: string;
|
|
64
|
-
|
|
65
|
-
// active state effects override
|
|
66
|
-
activeColor?: string;
|
|
67
|
-
activeTextColor?: string;
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
type ButtonSizeCombinations = {
|
|
73
|
-
[Size in ButtonSize]: {
|
|
74
|
-
typography: string;
|
|
75
|
-
size: number;
|
|
76
|
-
horizontalPadding: number;
|
|
77
|
-
borderRadius: string;
|
|
78
|
-
iconSize: IconSize;
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const BUTTON_COLOR_VARIANTS_CSS: ButtonColorCombinations = {
|
|
83
|
-
primary: {
|
|
84
|
-
default: {
|
|
85
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
86
|
-
backgroundColor: theme.color.primary.action,
|
|
87
|
-
borderColor: theme.color.primary.action,
|
|
88
|
-
hoverColor: theme.color.primary.actionHover,
|
|
89
|
-
activeColor: theme.color.primary.actionActive,
|
|
90
|
-
},
|
|
91
|
-
success: {
|
|
92
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
93
|
-
backgroundColor: theme.color.success.action,
|
|
94
|
-
borderColor: theme.color.success.action,
|
|
95
|
-
hoverColor: theme.color.success.actionHover,
|
|
96
|
-
activeColor: theme.color.success.actionActive,
|
|
97
|
-
},
|
|
98
|
-
danger: {
|
|
99
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
100
|
-
backgroundColor: theme.color.danger.action,
|
|
101
|
-
borderColor: theme.color.danger.action,
|
|
102
|
-
hoverColor: theme.color.danger.actionHover,
|
|
103
|
-
activeColor: theme.color.danger.actionActive,
|
|
104
|
-
},
|
|
105
|
-
primaryBlack: {
|
|
106
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
107
|
-
backgroundColor: theme.color.primaryBlack.action,
|
|
108
|
-
borderColor: theme.color.primaryBlack.action,
|
|
109
|
-
hoverGradient: `linear-gradient(to bottom, color-mix(in srgb, ${theme.color.neutral.textOnPrimary} 16%, transparent), transparent)`,
|
|
110
|
-
activeColor: theme.color.primaryBlack.actionActive,
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
secondary: {
|
|
114
|
-
default: {
|
|
115
|
-
textColor: theme.color.neutral.text,
|
|
116
|
-
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
117
|
-
borderColor: theme.color.neutral.border,
|
|
118
|
-
hoverColor: theme.color.neutral.actionSecondaryHover,
|
|
119
|
-
activeColor: theme.color.neutral.actionSecondaryActive,
|
|
120
|
-
actionBorderColor: theme.color.neutral.border,
|
|
121
|
-
},
|
|
122
|
-
success: {
|
|
123
|
-
textColor: theme.color.success.text,
|
|
124
|
-
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
125
|
-
borderColor: theme.color.neutral.border,
|
|
126
|
-
hoverColor: theme.color.success.actionHover,
|
|
127
|
-
activeColor: theme.color.success.actionActive,
|
|
128
|
-
actionTextColor: theme.color.neutral.background,
|
|
129
|
-
},
|
|
130
|
-
danger: {
|
|
131
|
-
textColor: theme.color.danger.text,
|
|
132
|
-
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
133
|
-
borderColor: theme.color.neutral.border,
|
|
134
|
-
hoverColor: theme.color.danger.backgroundHover,
|
|
135
|
-
actionBorderColor: theme.color.danger.borderSubtle,
|
|
136
|
-
activeColor: theme.color.danger.actionActive,
|
|
137
|
-
activeTextColor: theme.color.neutral.textOnPrimary,
|
|
138
|
-
},
|
|
139
|
-
primaryBlack: {
|
|
140
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
141
|
-
backgroundColor: theme.color.primaryBlack.action,
|
|
142
|
-
borderColor: theme.color.primaryBlack.action,
|
|
143
|
-
hoverGradient: `linear-gradient(to bottom, color-mix(in srgb, ${theme.color.neutral.textOnPrimary} 16%, transparent), transparent)`,
|
|
144
|
-
activeColor: theme.color.primaryBlack.actionActive,
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
tertiary: {
|
|
148
|
-
default: {
|
|
149
|
-
textColor: theme.color.neutral.text,
|
|
150
|
-
backgroundColor: 'transparent',
|
|
151
|
-
borderColor: 'transparent',
|
|
152
|
-
// TODO: Not sure about these
|
|
153
|
-
hoverColor: theme.color.neutral.hover,
|
|
154
|
-
activeColor: theme.color.neutral.actionSecondaryActive,
|
|
155
|
-
},
|
|
156
|
-
success: {
|
|
157
|
-
textColor: theme.color.success.text,
|
|
158
|
-
backgroundColor: 'transparent',
|
|
159
|
-
borderColor: 'transparent',
|
|
160
|
-
hoverColor: theme.color.success.backgroundSubtleHover,
|
|
161
|
-
activeColor: theme.color.success.backgroundSubtleActive,
|
|
162
|
-
},
|
|
163
|
-
danger: {
|
|
164
|
-
textColor: theme.color.danger.text,
|
|
165
|
-
backgroundColor: 'transparent',
|
|
166
|
-
borderColor: 'transparent',
|
|
167
|
-
hoverColor: theme.color.danger.backgroundSubtleHover,
|
|
168
|
-
activeColor: theme.color.danger.backgroundSubtleActive,
|
|
169
|
-
},
|
|
170
|
-
primaryBlack: {
|
|
171
|
-
textColor: theme.color.neutral.textOnPrimary,
|
|
172
|
-
backgroundColor: theme.color.primaryBlack.action,
|
|
173
|
-
borderColor: theme.color.primaryBlack.action,
|
|
174
|
-
hoverGradient: `linear-gradient(to bottom, color-mix(in srgb, ${theme.color.neutral.textOnPrimary} 16%, transparent), transparent)`,
|
|
175
|
-
activeColor: theme.color.primaryBlack.actionActive,
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
export const BUTTON_SIZE_VARIANTS_CSS: ButtonSizeCombinations = {
|
|
181
|
-
extraLarge: {
|
|
182
|
-
typography: theme.typography.shared.mobile.bodyMMedium,
|
|
183
|
-
size: 40,
|
|
184
|
-
horizontalPadding: 12,
|
|
185
|
-
borderRadius: theme.radius.radius8,
|
|
186
|
-
iconSize: '20',
|
|
187
|
-
},
|
|
188
|
-
large: {
|
|
189
|
-
typography: theme.typography.shared.mobile.bodyMMedium,
|
|
190
|
-
size: 36,
|
|
191
|
-
horizontalPadding: 12,
|
|
192
|
-
borderRadius: theme.radius.radius6,
|
|
193
|
-
iconSize: '20',
|
|
194
|
-
},
|
|
195
|
-
medium: {
|
|
196
|
-
typography: theme.typography.shared.mobile.bodyMMedium,
|
|
197
|
-
size: 32,
|
|
198
|
-
horizontalPadding: 12,
|
|
199
|
-
borderRadius: theme.radius.radius6,
|
|
200
|
-
iconSize: '20',
|
|
201
|
-
},
|
|
202
|
-
small: {
|
|
203
|
-
typography: theme.typography.shared.mobile.bodySMedium,
|
|
204
|
-
size: 28,
|
|
205
|
-
horizontalPadding: 8,
|
|
206
|
-
borderRadius: theme.radius.radius6,
|
|
207
|
-
iconSize: '16',
|
|
208
|
-
},
|
|
209
|
-
extraSmall: {
|
|
210
|
-
typography: theme.typography.shared.mobile.bodySMedium,
|
|
211
|
-
size: 24,
|
|
212
|
-
horizontalPadding: 6,
|
|
213
|
-
borderRadius: theme.radius.radius6,
|
|
214
|
-
iconSize: '16',
|
|
215
|
-
},
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
export const getButtonColorStyles = (variant: ButtonVariant = 'primary', color: ButtonColor = 'default') => {
|
|
219
|
-
const {
|
|
220
|
-
backgroundColor,
|
|
221
|
-
borderColor,
|
|
222
|
-
textColor,
|
|
223
|
-
actionBorderColor,
|
|
224
|
-
actionTextColor,
|
|
225
|
-
hoverColor,
|
|
226
|
-
hoverGradient,
|
|
227
|
-
activeColor,
|
|
228
|
-
activeTextColor,
|
|
229
|
-
} = BUTTON_COLOR_VARIANTS_CSS[variant][color];
|
|
230
|
-
|
|
231
|
-
return css`
|
|
232
|
-
color: ${textColor};
|
|
233
|
-
background-color: ${backgroundColor};
|
|
234
|
-
border-color: ${borderColor};
|
|
235
|
-
|
|
236
|
-
&:hover {
|
|
237
|
-
color: ${actionTextColor || textColor};
|
|
238
|
-
${hoverGradient
|
|
239
|
-
? css`
|
|
240
|
-
background-image: ${hoverGradient};
|
|
241
|
-
background-color: ${backgroundColor};
|
|
242
|
-
`
|
|
243
|
-
: css`
|
|
244
|
-
background-color: ${hoverColor};
|
|
245
|
-
`}
|
|
246
|
-
border-color: ${actionBorderColor || (hoverGradient ? borderColor : hoverColor)};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
&:active {
|
|
250
|
-
color: ${activeTextColor || actionTextColor || textColor};
|
|
251
|
-
background-color: ${activeColor};
|
|
252
|
-
${hoverGradient && 'background-image: none;'}
|
|
253
|
-
border-color: ${actionBorderColor || activeColor};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
&:disabled {
|
|
257
|
-
color: ${theme.color.neutral.textDisabled};
|
|
258
|
-
background-color: ${variant === 'tertiary' ? 'transparent' : theme.color.neutral.disabled};
|
|
259
|
-
border-color: ${variant === 'tertiary' ? 'transparent' : theme.color.neutral.disabled};
|
|
260
|
-
|
|
261
|
-
cursor: default;
|
|
262
|
-
}
|
|
263
|
-
`;
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
export const getButtonSizeStyles = (size: ButtonSize = 'medium') => {
|
|
267
|
-
const { typography, size: height, horizontalPadding, borderRadius } = BUTTON_SIZE_VARIANTS_CSS[size];
|
|
268
|
-
|
|
269
|
-
return css`
|
|
270
|
-
${typography};
|
|
271
|
-
height: ${height}px;
|
|
272
|
-
/* We just want to ensure padding on the sides. Height is set the the hard way for simplicity */
|
|
273
|
-
padding: 0 ${horizontalPadding}px;
|
|
274
|
-
border-radius: ${borderRadius};
|
|
275
|
-
`;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const StyledButton = styled(Box)<WithTransientProps<Required<TransientButtonProps>>>`
|
|
279
|
-
/* Basic positioning */
|
|
280
|
-
display: inline-flex;
|
|
281
|
-
align-items: center;
|
|
282
|
-
/* NOT sure about this. It needs to be set when we want 100% width button */
|
|
283
|
-
/* Maybe we can add block property */
|
|
284
|
-
justify-content: center;
|
|
285
|
-
gap: ${theme.space.space4};
|
|
286
|
-
|
|
287
|
-
/* Basic styles */
|
|
288
|
-
white-space: nowrap;
|
|
289
|
-
cursor: pointer;
|
|
290
|
-
transition:
|
|
291
|
-
border-color ${theme.transition.fastEaseOut},
|
|
292
|
-
background-color ${theme.transition.fastEaseOut};
|
|
293
|
-
|
|
294
|
-
/* Border is always defined, but it can be set to transparent */
|
|
295
|
-
border-style: solid;
|
|
296
|
-
border-width: 1px;
|
|
297
|
-
border-color: transparent;
|
|
298
|
-
|
|
299
|
-
/* Colors */
|
|
300
|
-
${(props) => getButtonColorStyles(props.$variant, props.$color)}
|
|
301
|
-
|
|
302
|
-
/* Paddings & font size */
|
|
303
|
-
${(props) => getButtonSizeStyles(props.$size)}
|
|
304
|
-
`;
|
|
305
|
-
|
|
306
60
|
export const Button = forwardRef<HTMLElement, ButtonProps | AnchorButtonProps>((props, ref) => {
|
|
307
61
|
const {
|
|
308
62
|
as,
|
|
@@ -310,12 +64,21 @@ export const Button = forwardRef<HTMLElement, ButtonProps | AnchorButtonProps>((
|
|
|
310
64
|
size = 'medium',
|
|
311
65
|
color = 'default',
|
|
312
66
|
variant = 'primary',
|
|
67
|
+
animated = false,
|
|
313
68
|
type = 'button',
|
|
314
69
|
LeftIcon,
|
|
315
70
|
RightIcon,
|
|
316
71
|
onClick,
|
|
317
72
|
trackingId,
|
|
318
73
|
trackingData,
|
|
74
|
+
className,
|
|
75
|
+
m,
|
|
76
|
+
mt,
|
|
77
|
+
mb,
|
|
78
|
+
ml,
|
|
79
|
+
mr,
|
|
80
|
+
mx,
|
|
81
|
+
my,
|
|
319
82
|
...rest
|
|
320
83
|
} = props;
|
|
321
84
|
|
|
@@ -325,47 +88,66 @@ export const Button = forwardRef<HTMLElement, ButtonProps | AnchorButtonProps>((
|
|
|
325
88
|
if (onClick) onClick(e);
|
|
326
89
|
};
|
|
327
90
|
|
|
328
|
-
const { iconSize } = BUTTON_SIZE_VARIANTS_CSS[size];
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
91
|
+
const { iconSize, borderRadius } = BUTTON_SIZE_VARIANTS_CSS[size];
|
|
92
|
+
|
|
93
|
+
// When animated, these are applied to the outer wrapper instead of the button (see below).
|
|
94
|
+
const layoutProps = { className, m, mt, mb, ml, mr, mx, my };
|
|
95
|
+
|
|
96
|
+
const renderButton = (buttonLayoutProps: MarginSpacingProps & { className?: string } = {}) => {
|
|
97
|
+
if (isAnchorButton(props)) {
|
|
98
|
+
const isExternal = isUrlExternal(props.to, windowLocationHost);
|
|
99
|
+
const EffectiveRightIcon = isExternal && !props.hideExternalIcon ? ExternalLinkIcon : RightIcon;
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<StyledButton
|
|
103
|
+
$size={size}
|
|
104
|
+
$color={color}
|
|
105
|
+
$variant={variant}
|
|
106
|
+
// If anchor is undefined, we just render it as a regular button
|
|
107
|
+
forwardedAs={props.disabled ? 'button' : Link}
|
|
108
|
+
ref={ref}
|
|
109
|
+
onClick={trackedOnClick}
|
|
110
|
+
to={props.to}
|
|
111
|
+
{...rest}
|
|
112
|
+
{...buttonLayoutProps}
|
|
113
|
+
// If we want to show external icon, we use button's slot for icon
|
|
114
|
+
hideExternalIcon={true}
|
|
115
|
+
>
|
|
116
|
+
{LeftIcon && <LeftIcon size={iconSize} />}
|
|
117
|
+
{children}
|
|
118
|
+
{EffectiveRightIcon && <EffectiveRightIcon size={iconSize} />}
|
|
119
|
+
</StyledButton>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
333
122
|
|
|
334
123
|
return (
|
|
335
124
|
<StyledButton
|
|
336
125
|
$size={size}
|
|
337
126
|
$color={color}
|
|
338
127
|
$variant={variant}
|
|
339
|
-
|
|
340
|
-
forwardedAs={props.disabled ? 'button' : Link}
|
|
128
|
+
forwardedAs={as || 'button'}
|
|
341
129
|
ref={ref}
|
|
342
130
|
onClick={trackedOnClick}
|
|
343
|
-
|
|
131
|
+
type={type}
|
|
344
132
|
{...rest}
|
|
345
|
-
|
|
346
|
-
hideExternalIcon={true}
|
|
133
|
+
{...buttonLayoutProps}
|
|
347
134
|
>
|
|
348
135
|
{LeftIcon && <LeftIcon size={iconSize} />}
|
|
349
136
|
{children}
|
|
350
|
-
{
|
|
137
|
+
{RightIcon && <RightIcon size={iconSize} />}
|
|
351
138
|
</StyledButton>
|
|
352
139
|
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// The animated shine sweep is only available for the primary variant.
|
|
143
|
+
// A disabled button should look inert, so it never shimmers.
|
|
144
|
+
if (animated && variant === 'primary' && !props.disabled) {
|
|
145
|
+
return (
|
|
146
|
+
<AnimatedBorder forwardedAs="span" $radius={borderRadius} {...layoutProps}>
|
|
147
|
+
{renderButton()}
|
|
148
|
+
</AnimatedBorder>
|
|
149
|
+
);
|
|
353
150
|
}
|
|
354
151
|
|
|
355
|
-
return (
|
|
356
|
-
<StyledButton
|
|
357
|
-
$size={size}
|
|
358
|
-
$color={color}
|
|
359
|
-
$variant={variant}
|
|
360
|
-
forwardedAs={as || 'button'}
|
|
361
|
-
ref={ref}
|
|
362
|
-
onClick={trackedOnClick}
|
|
363
|
-
type={type}
|
|
364
|
-
{...rest}
|
|
365
|
-
>
|
|
366
|
-
{LeftIcon && <LeftIcon size={iconSize} />}
|
|
367
|
-
{children}
|
|
368
|
-
{RightIcon && <RightIcon size={iconSize} />}
|
|
369
|
-
</StyledButton>
|
|
370
|
-
);
|
|
152
|
+
return renderButton(layoutProps);
|
|
371
153
|
});
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
// Clear indicator button, keyed by the select's id (or name as a fallback)
|
|
2
2
|
export const selectClearTestId = (idOrName: string | undefined): string => `${idOrName}--clear`;
|
|
3
|
+
|
|
4
|
+
// Label of a selected value in a multi-select, keyed the same way
|
|
5
|
+
export const selectMultiValueLabelTestId = (idOrName: string | undefined): string => `${idOrName}--multi-value-label`;
|
|
@@ -17,7 +17,7 @@ import { CaretDownIcon, CaretUpIcon, CrossIcon, XCircleIcon } from '@apify/ui-ic
|
|
|
17
17
|
import { theme } from '../../design_system/theme';
|
|
18
18
|
import { IconButton } from '../icon_button';
|
|
19
19
|
import { Text } from '../text';
|
|
20
|
-
import { selectClearTestId } from './select.test_ids';
|
|
20
|
+
import { selectClearTestId, selectMultiValueLabelTestId } from './select.test_ids';
|
|
21
21
|
|
|
22
22
|
const DEFAULT_Z_INDEX_IN_MODAL = 99;
|
|
23
23
|
const DEFAULT_Z_INDEX_OUTSIDE_MODAL = 9;
|
|
@@ -320,7 +320,7 @@ const SelectMultiValueLabel: FC<MultiValueGenericProps<SelectOption>> = ({ inner
|
|
|
320
320
|
innerProps={
|
|
321
321
|
{
|
|
322
322
|
...innerProps,
|
|
323
|
-
'data-test':
|
|
323
|
+
'data-test': selectMultiValueLabelTestId(rest.selectProps?.id ?? rest.selectProps?.name),
|
|
324
324
|
} as typeof innerProps
|
|
325
325
|
}
|
|
326
326
|
/>
|
|
@@ -2,6 +2,7 @@ import styled, { keyframes } from 'styled-components';
|
|
|
2
2
|
|
|
3
3
|
import { theme } from '../../design_system/theme';
|
|
4
4
|
import type { WithTransientProps } from '../../type_utils';
|
|
5
|
+
import { spinnerTestIds } from './spinner.test_ids';
|
|
5
6
|
|
|
6
7
|
export const spinnerClassNames = {
|
|
7
8
|
SPINNER: 'spinner',
|
|
@@ -75,7 +76,13 @@ const SpinnerWrapper = styled.span<SpinnerWrapperProps>`
|
|
|
75
76
|
*/
|
|
76
77
|
export const Spinner = ({ loadingReason, small, ...props }: SpinnerProps) => {
|
|
77
78
|
return (
|
|
78
|
-
<SpinnerWrapper
|
|
79
|
+
<SpinnerWrapper
|
|
80
|
+
{...props}
|
|
81
|
+
title={loadingReason}
|
|
82
|
+
$small={small}
|
|
83
|
+
data-testid={spinnerTestIds.SPINNER}
|
|
84
|
+
aria-busy="true"
|
|
85
|
+
>
|
|
79
86
|
<svg className={spinnerClassNames.SPINNER} viewBox="0 0 50 50">
|
|
80
87
|
<circle
|
|
81
88
|
className="path"
|
|
@@ -211,7 +211,12 @@ export const Tab = ({
|
|
|
211
211
|
$variant={variant}
|
|
212
212
|
>
|
|
213
213
|
{Icon && <Icon size="16" className={TAB_CLASSNAMES.ICON} />}
|
|
214
|
-
<Text
|
|
214
|
+
<Text
|
|
215
|
+
size={tabVariantTextSize[variant]}
|
|
216
|
+
className={TAB_CLASSNAMES.TITLE}
|
|
217
|
+
weight={active ? 'bold' : 'medium'}
|
|
218
|
+
as="div"
|
|
219
|
+
>
|
|
215
220
|
{title}
|
|
216
221
|
</Text>
|
|
217
222
|
{chip && (
|
package/src/test_ids.ts
CHANGED
|
@@ -10,7 +10,8 @@ export { prismHighlighterTestIds } from './components/code/prism_highlighter.tes
|
|
|
10
10
|
export { collapsibleCardTestIds } from './components/collapsible_card/collapsible_card.test_ids.js';
|
|
11
11
|
export { dropdownTestIds } from './components/dropdown/dropdown.test_ids.js';
|
|
12
12
|
export { paginationTestIds } from './components/pagination/pagination.test_ids.js';
|
|
13
|
-
export { selectClearTestId } from './components/select/select.test_ids.js';
|
|
13
|
+
export { selectClearTestId, selectMultiValueLabelTestId } from './components/select/select.test_ids.js';
|
|
14
|
+
export { spinnerTestIds } from './components/spinner/spinner.test_ids.js';
|
|
14
15
|
export { storeActorHeaderTestIds } from './components/store/store_actor_header.test_ids.js';
|
|
15
16
|
export { tableTestIds } from './components/table/table.test_ids.js';
|
|
16
17
|
export { tabTestIds } from './components/tabs/tab.test_ids.js';
|