@apify/ui-library 1.167.0 → 1.168.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/avatar/actor_avatar.d.ts +2 -0
- package/dist/components/avatar/actor_avatar.d.ts.map +1 -1
- package/dist/components/avatar/actor_avatar.js +6 -3
- package/dist/components/floating/tooltip.d.ts +1 -0
- package/dist/components/floating/tooltip.d.ts.map +1 -1
- package/dist/components/floating/tooltip.js +1 -0
- package/dist/components/icon_button/icon_button.d.ts +3 -2
- package/dist/components/icon_button/icon_button.d.ts.map +1 -1
- package/dist/components/readme_renderer/pythonize_value.d.ts.map +1 -1
- package/dist/components/readme_renderer/pythonize_value.js +1 -1
- package/dist/components/split_button/split_button.d.ts +1 -0
- package/dist/components/split_button/split_button.d.ts.map +1 -1
- package/dist/components/split_button/split_button.js +35 -33
- package/dist/components/store/store_actor_header.d.ts.map +1 -1
- package/dist/components/store/store_actor_header.js +1 -2
- package/dist/files_hash_at_build.txt +1 -1
- package/dist/index.js +2 -2
- package/dist/src/components/avatar/actor_avatar.d.ts +2 -0
- package/dist/src/components/avatar/actor_avatar.d.ts.map +1 -1
- package/dist/src/components/avatar/actor_avatar.js +5 -3
- package/dist/src/components/avatar/actor_avatar.js.map +1 -1
- package/dist/src/components/floating/tooltip.d.ts +1 -0
- package/dist/src/components/floating/tooltip.d.ts.map +1 -1
- package/dist/src/components/floating/tooltip.js +1 -0
- package/dist/src/components/floating/tooltip.js.map +1 -1
- package/dist/src/components/icon_button/icon_button.d.ts +3 -2
- package/dist/src/components/icon_button/icon_button.d.ts.map +1 -1
- package/dist/src/components/icon_button/icon_button.js.map +1 -1
- package/dist/src/components/readme_renderer/pythonize_value.d.ts.map +1 -1
- package/dist/src/components/readme_renderer/pythonize_value.js +2 -1
- package/dist/src/components/readme_renderer/pythonize_value.js.map +1 -1
- package/dist/src/components/split_button/split_button.d.ts +1 -0
- package/dist/src/components/split_button/split_button.d.ts.map +1 -1
- package/dist/src/components/split_button/split_button.js +6 -7
- package/dist/src/components/split_button/split_button.js.map +1 -1
- package/dist/src/components/store/store_actor_header.d.ts.map +1 -1
- package/dist/src/components/store/store_actor_header.js +1 -1
- package/dist/src/components/store/store_actor_header.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/components/avatar/actor_avatar.tsx +7 -3
- package/src/components/button/button.stories.tsx +43 -1
- package/src/components/floating/tooltip.tsx +1 -0
- package/src/components/icon_button/icon_button.tsx +2 -3
- package/src/components/readme_renderer/pythonize_value.ts +2 -1
- package/src/components/split_button/split_button.stories.tsx +16 -5
- package/src/components/split_button/split_button.tsx +35 -34
- package/src/components/store/store_actor_header.tsx +1 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apify/ui-library",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.168.0",
|
|
4
4
|
"description": "React UI library used by apify.com",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"styled-components": "^6.1.19"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@apify-packages/types": "^3.
|
|
78
|
+
"@apify-packages/types": "^3.454.0",
|
|
79
79
|
"@storybook/react-vite": "^10.3.5",
|
|
80
80
|
"@testing-library/react": "^16.3.2",
|
|
81
81
|
"@types/hast": "^3.0.4",
|
|
@@ -95,5 +95,5 @@
|
|
|
95
95
|
"src",
|
|
96
96
|
"style"
|
|
97
97
|
],
|
|
98
|
-
"gitHead": "
|
|
98
|
+
"gitHead": "6a2d3eedb716e9e766ea4328f4ef3c5554fc6426"
|
|
99
99
|
}
|
|
@@ -34,10 +34,13 @@ const StyledBoringAvatarMarble = styled(BoringAvatarMarble)<{ $borderRadius: str
|
|
|
34
34
|
}
|
|
35
35
|
`;
|
|
36
36
|
|
|
37
|
-
const StyledImg = styled.img
|
|
38
|
-
border-radius: ${
|
|
37
|
+
const StyledImg = styled.img<{ $borderRadius: string | number }>`
|
|
38
|
+
border-radius: ${({ $borderRadius }) => $borderRadius};
|
|
39
39
|
`;
|
|
40
40
|
|
|
41
|
+
/** Corner radius in px for an Actor avatar of the given size, shared with bordered avatars. */
|
|
42
|
+
export const getActorAvatarBorderRadius = (size: number) => size / 4 + 2;
|
|
43
|
+
|
|
41
44
|
interface ActorAvatarProps extends React.ImgHTMLAttributes<HTMLImageElement> {
|
|
42
45
|
name?: string;
|
|
43
46
|
className?: string;
|
|
@@ -53,7 +56,7 @@ export const ActorAvatarInner: FC<ActorAvatarProps> = ({
|
|
|
53
56
|
url,
|
|
54
57
|
size,
|
|
55
58
|
alt,
|
|
56
|
-
borderRadius =
|
|
59
|
+
borderRadius = `${getActorAvatarBorderRadius(size)}px`,
|
|
57
60
|
...rest
|
|
58
61
|
}) => {
|
|
59
62
|
const [hasImageError, setHasImageError] = useState(false);
|
|
@@ -110,6 +113,7 @@ export const ActorAvatarInner: FC<ActorAvatarProps> = ({
|
|
|
110
113
|
height={size}
|
|
111
114
|
alt={altText}
|
|
112
115
|
onError={onError}
|
|
116
|
+
$borderRadius={borderRadius}
|
|
113
117
|
{...rest}
|
|
114
118
|
/>
|
|
115
119
|
);
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { Meta } from '@storybook/react-vite';
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
// eslint-disable-next-line import-x/extensions
|
|
3
3
|
import { action } from 'storybook/actions';
|
|
4
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
|
4
5
|
import styled from 'styled-components';
|
|
5
6
|
|
|
6
7
|
import { CrossIcon } from '@apify/ui-icons';
|
|
7
8
|
|
|
8
9
|
import { theme } from '../../design_system/theme';
|
|
10
|
+
import { Tooltip } from '../floating';
|
|
9
11
|
import { Button, type ButtonProps } from './button';
|
|
10
12
|
|
|
11
13
|
export default {
|
|
@@ -219,3 +221,43 @@ export const Animated = () => {
|
|
|
219
221
|
</Wrapper>
|
|
220
222
|
);
|
|
221
223
|
};
|
|
224
|
+
|
|
225
|
+
// Tooltip renders only its children when `content` is empty, so a conditional tooltip needs no branching.
|
|
226
|
+
export const WithTooltip: StoryObj = {
|
|
227
|
+
render: () => (
|
|
228
|
+
<Wrapper>
|
|
229
|
+
<ButtonGrid>
|
|
230
|
+
<Tooltip content="Saves the current draft" delayShow={0}>
|
|
231
|
+
<Button onClick={action('onClick')}>Save</Button>
|
|
232
|
+
</Tooltip>
|
|
233
|
+
<Tooltip content="Fill in all required fields first" delayShow={0}>
|
|
234
|
+
<Button onClick={action('onClick')} disabled>
|
|
235
|
+
Disabled with reason
|
|
236
|
+
</Button>
|
|
237
|
+
</Tooltip>
|
|
238
|
+
<Tooltip content={undefined}>
|
|
239
|
+
<Button onClick={action('onClick')}>No tooltip</Button>
|
|
240
|
+
</Tooltip>
|
|
241
|
+
</ButtonGrid>
|
|
242
|
+
</Wrapper>
|
|
243
|
+
),
|
|
244
|
+
play: async ({ canvasElement }) => {
|
|
245
|
+
const canvas = within(canvasElement);
|
|
246
|
+
|
|
247
|
+
await userEvent.hover(canvas.getByRole('button', { name: 'Save' }));
|
|
248
|
+
await expect(await canvas.findByText('Saves the current draft')).toBeInTheDocument();
|
|
249
|
+
await userEvent.unhover(canvas.getByRole('button', { name: 'Save' }));
|
|
250
|
+
|
|
251
|
+
// A disabled button fires no pointer events, the tooltip's wrapping span does.
|
|
252
|
+
const disabledButton = canvas.getByRole('button', { name: 'Disabled with reason' });
|
|
253
|
+
await userEvent.hover(disabledButton.parentElement as HTMLElement);
|
|
254
|
+
await expect(await canvas.findByText('Fill in all required fields first')).toBeInTheDocument();
|
|
255
|
+
await userEvent.unhover(disabledButton.parentElement as HTMLElement);
|
|
256
|
+
await waitFor(async () =>
|
|
257
|
+
expect(canvas.queryByText('Fill in all required fields first')).not.toBeInTheDocument(),
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const plainButton = canvas.getByRole('button', { name: 'No tooltip' });
|
|
261
|
+
await expect(plainButton.parentElement?.tagName).not.toBe('SPAN');
|
|
262
|
+
},
|
|
263
|
+
};
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
type RegularButtonProps,
|
|
15
15
|
type TransientButtonProps,
|
|
16
16
|
} from '../button';
|
|
17
|
-
import { Tooltip } from '../floating';
|
|
17
|
+
import { Tooltip, type TooltipProps } from '../floating';
|
|
18
18
|
import { Link, type RegularLinkProps } from '../link';
|
|
19
19
|
import { InlineSpinner, spinnerClassNames } from '../spinner';
|
|
20
20
|
|
|
@@ -212,7 +212,7 @@ export type IconButtonProps<T extends IconButtonNodeType> = RegularBoxProps &
|
|
|
212
212
|
disabled?: boolean;
|
|
213
213
|
isLoading?: boolean;
|
|
214
214
|
title?: string;
|
|
215
|
-
tooltipProps?:
|
|
215
|
+
tooltipProps?: Omit<TooltipProps, 'children'>;
|
|
216
216
|
} & Omit<IconButtonNodePropsMap[T]['props'], 'size' | 'variant'>;
|
|
217
217
|
|
|
218
218
|
/**
|
|
@@ -261,7 +261,6 @@ export const IconButton = forwardRef(
|
|
|
261
261
|
);
|
|
262
262
|
|
|
263
263
|
return title ? (
|
|
264
|
-
// @ts-expect-error tooltip is not migrated to TS yet
|
|
265
264
|
<Tooltip content={title} {...tooltipProps}>
|
|
266
265
|
{button}
|
|
267
266
|
</Tooltip>
|
|
@@ -66,7 +66,8 @@ export const pythonizeValue = <T>(value: T, depth = 0): string | T => {
|
|
|
66
66
|
|
|
67
67
|
// Object values
|
|
68
68
|
if (typeof value === 'object') {
|
|
69
|
-
|
|
69
|
+
// Keys with `undefined` values are left out, like in `JSON.stringify`
|
|
70
|
+
const entries = Object.entries(value).filter(([, v]) => v !== undefined);
|
|
70
71
|
if (entries.length === 0) return '{}';
|
|
71
72
|
if (entries.length === 1)
|
|
72
73
|
return '{ ' + pythonQuoteString(entries[0][0]) + ': ' + pythonizeValue(entries[0][1], depth + 1) + ' }';
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
import { action } from 'storybook/actions';
|
|
3
|
-
import { expect, userEvent, within } from 'storybook/test';
|
|
3
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
|
|
6
6
|
import { BuildIcon, PlayIcon } from '@apify/ui-icons';
|
|
7
7
|
|
|
8
|
+
import { Tooltip } from '../floating';
|
|
8
9
|
import { SplitButton, type SplitButtonAction } from './';
|
|
9
10
|
|
|
10
11
|
const defaultActions: SplitButtonAction[] = [
|
|
@@ -204,10 +205,20 @@ export const AllActionsDisabled: Story = {
|
|
|
204
205
|
};
|
|
205
206
|
|
|
206
207
|
export const WithTooltip: Story = {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
render: (args) => (
|
|
209
|
+
<Tooltip content="Run this Actor with the current input" delayShow={0}>
|
|
210
|
+
<SplitButton {...args} />
|
|
211
|
+
</Tooltip>
|
|
212
|
+
),
|
|
213
|
+
play: async ({ canvasElement }) => {
|
|
214
|
+
const canvas = within(canvasElement);
|
|
215
|
+
|
|
216
|
+
await userEvent.hover(canvas.getAllByRole('button')[0]);
|
|
217
|
+
await expect(await canvas.findByText('Run this Actor with the current input')).toBeInTheDocument();
|
|
218
|
+
await userEvent.unhover(canvas.getAllByRole('button')[0]);
|
|
219
|
+
await waitFor(async () =>
|
|
220
|
+
expect(canvas.queryByText('Run this Actor with the current input')).not.toBeInTheDocument(),
|
|
221
|
+
);
|
|
211
222
|
},
|
|
212
223
|
};
|
|
213
224
|
|
|
@@ -7,7 +7,7 @@ import styled from 'styled-components';
|
|
|
7
7
|
import type { MarginSpacingProps } from '../box';
|
|
8
8
|
import { Button, type ButtonColor, type ButtonSize, type ButtonVariant } from '../button';
|
|
9
9
|
import { Dropdown, DropdownShell } from '../dropdown';
|
|
10
|
-
import { type TooltipProps
|
|
10
|
+
import { Tooltip, type TooltipProps } from '../floating';
|
|
11
11
|
import { Text } from '../text';
|
|
12
12
|
import { splitButtonClassNames, StyledDropdownChevron, StyledSplitButtonWrapper } from './split_button.styled';
|
|
13
13
|
import { splitButtonMainActionTestId, splitButtonTriggerTestId } from './split_button.test_ids';
|
|
@@ -36,6 +36,7 @@ export interface SplitButtonProps
|
|
|
36
36
|
align?: PopperContentProps['align'];
|
|
37
37
|
width?: string;
|
|
38
38
|
showMainIcon?: boolean;
|
|
39
|
+
/** @deprecated Wrap `SplitButton` in `Tooltip` instead. */
|
|
39
40
|
tooltipProps?: TooltipProps;
|
|
40
41
|
/** Forwarded to the dropdown's DropdownShell - override when a consumer renders inside a modal/overlay stack. */
|
|
41
42
|
zIndex?: number;
|
|
@@ -48,8 +49,6 @@ const ButtonWrapper = styled.div`
|
|
|
48
49
|
align-items: center;
|
|
49
50
|
`;
|
|
50
51
|
|
|
51
|
-
const ButtonWrapperWithTooltip = withTooltip(ButtonWrapper);
|
|
52
|
-
|
|
53
52
|
export const SplitButton = ({
|
|
54
53
|
className,
|
|
55
54
|
actions,
|
|
@@ -84,40 +83,42 @@ export const SplitButton = ({
|
|
|
84
83
|
);
|
|
85
84
|
const buttonMainLabel = label || mainAction.label;
|
|
86
85
|
|
|
87
|
-
const
|
|
86
|
+
const buttons = (
|
|
87
|
+
<ButtonWrapper ref={triggerRef}>
|
|
88
|
+
<Button
|
|
89
|
+
data-test={splitButtonMainActionTestId(mainAction.trackingId)}
|
|
90
|
+
{...passedProps}
|
|
91
|
+
className={mainActionClassNames}
|
|
92
|
+
disabled={mainAction.disabled}
|
|
93
|
+
mr="none"
|
|
94
|
+
onClick={() => {
|
|
95
|
+
mainAction.onClick();
|
|
96
|
+
setActionsVisible(false);
|
|
97
|
+
}}
|
|
98
|
+
trackingId={mainAction.trackingId}
|
|
99
|
+
>
|
|
100
|
+
{mainAction.icon && showMainIcon ? <mainAction.icon /> : null}
|
|
101
|
+
{buttonMainLabel}
|
|
102
|
+
</Button>
|
|
103
|
+
<Button
|
|
104
|
+
{...passedProps}
|
|
105
|
+
className={triggerClassNames}
|
|
106
|
+
ml="none"
|
|
107
|
+
onClick={() => setActionsVisible((prevActionsVisible) => !prevActionsVisible)}
|
|
108
|
+
trackingId={mainAction.trackingId ? `${mainAction.trackingId}-OpenDropdown` : undefined}
|
|
109
|
+
data-test={splitButtonTriggerTestId(mainAction.trackingId)}
|
|
110
|
+
aria-haspopup="menu"
|
|
111
|
+
aria-expanded={actionsVisible}
|
|
112
|
+
aria-label={triggerAriaLabel}
|
|
113
|
+
>
|
|
114
|
+
<StyledDropdownChevron $isOpen={actionsVisible} size="16" />
|
|
115
|
+
</Button>
|
|
116
|
+
</ButtonWrapper>
|
|
117
|
+
);
|
|
88
118
|
|
|
89
119
|
return (
|
|
90
120
|
<StyledSplitButtonWrapper className={wrapperClassNames}>
|
|
91
|
-
<
|
|
92
|
-
<Button
|
|
93
|
-
data-test={splitButtonMainActionTestId(mainAction.trackingId)}
|
|
94
|
-
{...passedProps}
|
|
95
|
-
className={mainActionClassNames}
|
|
96
|
-
disabled={mainAction.disabled}
|
|
97
|
-
mr="none"
|
|
98
|
-
onClick={() => {
|
|
99
|
-
mainAction.onClick();
|
|
100
|
-
setActionsVisible(false);
|
|
101
|
-
}}
|
|
102
|
-
trackingId={mainAction.trackingId}
|
|
103
|
-
>
|
|
104
|
-
{mainAction.icon && showMainIcon ? <mainAction.icon /> : null}
|
|
105
|
-
{buttonMainLabel}
|
|
106
|
-
</Button>
|
|
107
|
-
<Button
|
|
108
|
-
{...passedProps}
|
|
109
|
-
className={triggerClassNames}
|
|
110
|
-
ml="none"
|
|
111
|
-
onClick={() => setActionsVisible((prevActionsVisible) => !prevActionsVisible)}
|
|
112
|
-
trackingId={mainAction.trackingId ? `${mainAction.trackingId}-OpenDropdown` : undefined}
|
|
113
|
-
data-test={splitButtonTriggerTestId(mainAction.trackingId)}
|
|
114
|
-
aria-haspopup="menu"
|
|
115
|
-
aria-expanded={actionsVisible}
|
|
116
|
-
aria-label={triggerAriaLabel}
|
|
117
|
-
>
|
|
118
|
-
<StyledDropdownChevron $isOpen={actionsVisible} size="16" />
|
|
119
|
-
</Button>
|
|
120
|
-
</Wrapper>
|
|
121
|
+
{tooltipProps ? <Tooltip {...tooltipProps}>{buttons}</Tooltip> : buttons}
|
|
121
122
|
|
|
122
123
|
<DropdownShell
|
|
123
124
|
isOpen={actionsVisible}
|
|
@@ -96,12 +96,7 @@ export const StoreActorHeader: React.FC<StoreActorHeaderProps & BoxProps> = ({
|
|
|
96
96
|
return (
|
|
97
97
|
<StyledStoreActorHeader data-test={storeActorHeaderTestIds.HEADER} $compact={compact} {...rest}>
|
|
98
98
|
<ActorAvatarWrapper>
|
|
99
|
-
<ActorAvatar
|
|
100
|
-
size={compact ? 20 : avatarSize}
|
|
101
|
-
url={pictureUrl}
|
|
102
|
-
name={title}
|
|
103
|
-
borderRadius={compact ? theme.radius.radius4 : theme.radius.radius8}
|
|
104
|
-
/>
|
|
99
|
+
<ActorAvatar size={compact ? 20 : avatarSize} url={pictureUrl} name={title} />
|
|
105
100
|
{!compact && hasRisingStarBadge && (
|
|
106
101
|
<StyledCompactBadge
|
|
107
102
|
variant="primary_blue"
|