@apify/ui-library 0.71.1-featcolortokens-178953.58 → 0.71.1-featcolortokens-178953.67
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/src/design_system/colors/generated/{dark.d.ts → css_variables.dark.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.dark.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/css_variables.dark.js +147 -0
- package/dist/src/design_system/colors/generated/css_variables.dark.js.map +1 -0
- package/dist/src/design_system/colors/generated/{light.d.ts → css_variables.light.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.light.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/css_variables.light.js +147 -0
- package/dist/src/design_system/colors/generated/css_variables.light.js.map +1 -0
- package/dist/src/design_system/colors/generated/{palette.dark.d.ts → css_variables_palette.dark.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.dark.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/css_variables_palette.dark.js +74 -0
- package/dist/src/design_system/colors/generated/css_variables_palette.dark.js.map +1 -0
- package/dist/src/design_system/colors/generated/{palette.light.d.ts → css_variables_palette.light.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.light.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/css_variables_palette.light.js +74 -0
- package/dist/src/design_system/colors/generated/css_variables_palette.light.js.map +1 -0
- package/dist/src/design_system/colors/index.d.ts +4 -4
- package/dist/src/design_system/colors/index.d.ts.map +1 -1
- package/dist/src/design_system/colors/index.js +4 -4
- package/dist/src/design_system/colors/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/codemods/generate_typograpy_tokens_files.mjs +137 -0
- package/src/components/action_link.tsx +60 -0
- package/src/components/actor_template_card.tsx +116 -0
- package/src/components/badge.tsx +148 -0
- package/src/components/banner.tsx +94 -0
- package/src/components/blog_article.tsx +85 -0
- package/src/components/box.tsx +127 -0
- package/src/components/button.tsx +305 -0
- package/src/components/chip.tsx +128 -0
- package/src/components/code/action_button.tsx +96 -0
- package/src/components/code/code_block/code_block.styled.tsx +180 -0
- package/src/components/code/code_block/code_block.tsx +224 -0
- package/src/components/code/code_block/code_block_with_tabs.tsx +257 -0
- package/src/components/code/code_block/utils.tsx +67 -0
- package/src/components/code/index.ts +5 -0
- package/src/components/code/inline_code/inline_code.tsx +62 -0
- package/src/components/code/one_line_code/one_line_code.tsx +228 -0
- package/src/components/code/prism_highlighter.tsx +180 -0
- package/src/components/color_wheel_gradient.tsx +31 -0
- package/src/components/floating/index.ts +3 -0
- package/src/components/floating/menu.tsx +189 -0
- package/src/components/floating/menu_common.tsx +31 -0
- package/src/components/floating/menu_components.tsx +99 -0
- package/src/components/image.tsx +24 -0
- package/src/components/index.ts +22 -0
- package/src/components/link.tsx +114 -0
- package/src/components/message.tsx +153 -0
- package/src/components/rating.tsx +106 -0
- package/src/components/readme_renderer/index.ts +3 -0
- package/src/components/readme_renderer/pythonize_value.ts +76 -0
- package/src/components/readme_renderer/table_of_contents.tsx +272 -0
- package/src/components/readme_renderer/utils.tsx +46 -0
- package/src/components/simple_markdown/index.ts +2 -0
- package/src/components/simple_markdown/simple_markdown.tsx +214 -0
- package/src/components/simple_markdown/simple_markdown_components.tsx +293 -0
- package/src/components/tabs/index.ts +2 -0
- package/src/components/tabs/tab.tsx +217 -0
- package/src/components/tabs/tabs.tsx +169 -0
- package/src/components/tag.tsx +196 -0
- package/src/components/text/heading_content.tsx +56 -0
- package/src/components/text/heading_marketing.tsx +55 -0
- package/src/components/text/heading_shared.tsx +55 -0
- package/src/components/text/index.ts +19 -0
- package/src/components/text/text_base.tsx +52 -0
- package/src/components/text/text_content.tsx +104 -0
- package/src/components/text/text_marketing.tsx +152 -0
- package/src/components/text/text_shared.tsx +95 -0
- package/src/components/tile/horizontal_tile.tsx +77 -0
- package/src/components/tile/index.ts +2 -0
- package/src/components/tile/shared.ts +27 -0
- package/src/components/tile/vertical_tile.tsx +59 -0
- package/src/components/to_consolidate/card.tsx +141 -0
- package/src/components/to_consolidate/index.ts +4 -0
- package/src/components/to_consolidate/markdown.tsx +609 -0
- package/src/components/to_consolidate/pagination.tsx +136 -0
- package/src/components/to_consolidate/tab_number_chip.tsx +31 -0
- package/src/design_system/colors/build_color_tokens.js +183 -0
- package/src/design_system/colors/figma_color_tokens.dark.json +886 -0
- package/src/design_system/colors/figma_color_tokens.light.json +886 -0
- package/src/design_system/colors/generated/colors_theme.dark.ts +110 -0
- package/src/design_system/colors/generated/colors_theme.light.ts +110 -0
- package/{dist/src/design_system/colors/generated/dark.js → src/design_system/colors/generated/css_variables.dark.ts} +1 -1
- package/{dist/src/design_system/colors/generated/light.js → src/design_system/colors/generated/css_variables.light.ts} +1 -1
- package/{dist/src/design_system/colors/generated/palette.dark.js → src/design_system/colors/generated/css_variables_palette.dark.ts} +1 -1
- package/{dist/src/design_system/colors/generated/palette.light.js → src/design_system/colors/generated/css_variables_palette.light.ts} +1 -1
- package/{dist/src/design_system/properties_theme.js → src/design_system/colors/generated/properties_theme.ts} +20 -156
- package/src/design_system/colors/index.ts +7 -0
- package/src/design_system/supernova_typography_tokens.json +657 -0
- package/src/design_system/theme.ts +25 -0
- package/src/design_system/tokens/index.ts +5 -0
- package/src/design_system/tokens/layouts.ts +29 -0
- package/src/design_system/tokens/radiuses.ts +22 -0
- package/src/design_system/tokens/shadows.ts +22 -0
- package/src/design_system/tokens/spaces.ts +15 -0
- package/src/design_system/tokens/transitions.ts +19 -0
- package/src/design_system/typography_theme.ts +197 -0
- package/src/index.ts +8 -0
- package/src/type_utils.ts +7 -0
- package/src/ui_dependency_provider.tsx +58 -0
- package/src/utils/copy_to_clipboard.ts +24 -0
- package/src/utils/image_color.ts +42 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/resize_observer.ts +18 -0
- package/src/utils/sanitization.ts +14 -0
- package/dist/src/design_system/colors/generated/dark.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/dark.js.map +0 -1
- package/dist/src/design_system/colors/generated/light.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/light.js.map +0 -1
- package/dist/src/design_system/colors/generated/palette.dark.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/palette.dark.js.map +0 -1
- package/dist/src/design_system/colors/generated/palette.light.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/palette.light.js.map +0 -1
- package/dist/src/design_system/colors_theme.d.ts +0 -213
- package/dist/src/design_system/colors_theme.d.ts.map +0 -1
- package/dist/src/design_system/colors_theme.js +0 -213
- package/dist/src/design_system/colors_theme.js.map +0 -1
- package/dist/src/design_system/properties_theme.d.ts +0 -175
- package/dist/src/design_system/properties_theme.d.ts.map +0 -1
- package/dist/src/design_system/properties_theme.js.map +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import styled, { css } from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import { theme } from '../design_system/theme.js';
|
|
5
|
+
import type { Size } from '../design_system/tokens/index.js';
|
|
6
|
+
import type { WithTransientProps } from '../type_utils.js';
|
|
7
|
+
|
|
8
|
+
type ExtendedSize = Size | 'none' | 'auto';
|
|
9
|
+
|
|
10
|
+
export interface MarginSpacingProps {
|
|
11
|
+
m?: ExtendedSize,
|
|
12
|
+
mt?: ExtendedSize,
|
|
13
|
+
mb?: ExtendedSize,
|
|
14
|
+
ml?: ExtendedSize,
|
|
15
|
+
mr?: ExtendedSize,
|
|
16
|
+
mx?: ExtendedSize,
|
|
17
|
+
my?: ExtendedSize,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PaddingSpacingProps {
|
|
21
|
+
p?: ExtendedSize,
|
|
22
|
+
pt?: ExtendedSize,
|
|
23
|
+
pb?: ExtendedSize,
|
|
24
|
+
pl?: ExtendedSize,
|
|
25
|
+
pr?: ExtendedSize,
|
|
26
|
+
px?: ExtendedSize,
|
|
27
|
+
py?: ExtendedSize,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type SharedBoxProps = {
|
|
31
|
+
children?: React.ReactNode,
|
|
32
|
+
className?: string,
|
|
33
|
+
style?: React.CSSProperties
|
|
34
|
+
onClick?: (e: React.MouseEvent) => void,
|
|
35
|
+
id?: string,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// This should be renamed - these props are global for any element not just Boxes
|
|
39
|
+
export type RegularBoxProps = SharedBoxProps & { as?: React.ElementType };
|
|
40
|
+
|
|
41
|
+
type OlBoxProps = SharedBoxProps & { as: 'ol', start?: number };
|
|
42
|
+
|
|
43
|
+
/** Combines together RegularBoxProps and props for specific elements. */
|
|
44
|
+
type AnyBoxProps = RegularBoxProps | OlBoxProps;
|
|
45
|
+
|
|
46
|
+
export type BoxProps = MarginSpacingProps & PaddingSpacingProps & AnyBoxProps;
|
|
47
|
+
|
|
48
|
+
const getSizeValue = (token?: ExtendedSize) => {
|
|
49
|
+
if (!token || token === 'none') return 0;
|
|
50
|
+
if (token === 'auto') return 'auto';
|
|
51
|
+
return theme.space[token] || 0;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const StyledBox = styled.div<WithTransientProps<MarginSpacingProps & PaddingSpacingProps>>`
|
|
55
|
+
${({ $mt, $my, $m }) => ($mt || $my || $m) && css`
|
|
56
|
+
margin-top: ${getSizeValue($mt || $my || $m)};
|
|
57
|
+
`}
|
|
58
|
+
|
|
59
|
+
${({ $mb, $my, $m }) => ($mb || $my || $m) && css`
|
|
60
|
+
margin-bottom: ${getSizeValue($mb || $my || $m)};
|
|
61
|
+
`}
|
|
62
|
+
|
|
63
|
+
${({ $mr, $mx, $m }) => ($mr || $mx || $m) && css`
|
|
64
|
+
margin-right: ${getSizeValue($mr || $mx || $m)};
|
|
65
|
+
`}
|
|
66
|
+
|
|
67
|
+
${({ $ml, $mx, $m }) => ($ml || $mx || $m) && css`
|
|
68
|
+
margin-left: ${getSizeValue($ml || $mx || $m)};
|
|
69
|
+
`}
|
|
70
|
+
|
|
71
|
+
${({ $pt, $py, $p }) => ($pt || $py || $p) && css`
|
|
72
|
+
padding-top: ${getSizeValue($pt || $py || $p)};
|
|
73
|
+
`}
|
|
74
|
+
|
|
75
|
+
${({ $pb, $py, $p }) => ($pb || $py || $p) && css`
|
|
76
|
+
padding-bottom: ${getSizeValue($pb || $py || $p)};
|
|
77
|
+
`}
|
|
78
|
+
|
|
79
|
+
${({ $pr, $px, $p }) => ($pr || $px || $p) && css`
|
|
80
|
+
padding-right: ${getSizeValue($pr || $px || $p)};
|
|
81
|
+
`}
|
|
82
|
+
|
|
83
|
+
${({ $pl, $px, $p }) => ($pl || $px || $p) && css`
|
|
84
|
+
padding-left: ${getSizeValue($pl || $px || $p)};
|
|
85
|
+
`}
|
|
86
|
+
`;
|
|
87
|
+
// This component should work as a base component for all low level components (Heading, Message, Card, ...) to make it easy to define spacing.
|
|
88
|
+
// Right now, it's quite common to define some sort of spacing on these components already using css. Card = styled.div`margin-bottom: theme.space.space8`
|
|
89
|
+
// We should get rid of it and define it using props for Box component Card = styled(Box).attrs({mb: 'space8'})
|
|
90
|
+
export const Box = forwardRef<HTMLElement, BoxProps>(({
|
|
91
|
+
m,
|
|
92
|
+
mt,
|
|
93
|
+
mb,
|
|
94
|
+
ml,
|
|
95
|
+
mr,
|
|
96
|
+
mx,
|
|
97
|
+
my,
|
|
98
|
+
p,
|
|
99
|
+
pt,
|
|
100
|
+
pb,
|
|
101
|
+
pl,
|
|
102
|
+
pr,
|
|
103
|
+
px,
|
|
104
|
+
py,
|
|
105
|
+
as,
|
|
106
|
+
...rest
|
|
107
|
+
}: BoxProps, ref) => (
|
|
108
|
+
<StyledBox
|
|
109
|
+
$m={m}
|
|
110
|
+
$mt={mt}
|
|
111
|
+
$mb={mb}
|
|
112
|
+
$ml={ml}
|
|
113
|
+
$mr={mr}
|
|
114
|
+
$mx={mx}
|
|
115
|
+
$my={my}
|
|
116
|
+
$p={p}
|
|
117
|
+
$pt={pt}
|
|
118
|
+
$pb={pb}
|
|
119
|
+
$pl={pl}
|
|
120
|
+
$pr={pr}
|
|
121
|
+
$px={px}
|
|
122
|
+
$py={py}
|
|
123
|
+
as={as}
|
|
124
|
+
ref={ref}
|
|
125
|
+
{...rest}
|
|
126
|
+
/>
|
|
127
|
+
));
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import styled, { css } from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import { ExternalLinkIcon } from '@apify/ui-icons';
|
|
5
|
+
|
|
6
|
+
import { theme } from '../design_system/theme.js';
|
|
7
|
+
import { type WithRequired, type WithTransientProps } from '../type_utils.js';
|
|
8
|
+
import { useSharedUiDependencies } from '../ui_dependency_provider.js';
|
|
9
|
+
import { Box, type MarginSpacingProps, type RegularBoxProps } from './box.js';
|
|
10
|
+
import { isUrlExternal, Link, type LinkProps } from './link.js';
|
|
11
|
+
|
|
12
|
+
type ButtonSize = 'medium' | 'small';
|
|
13
|
+
type ButtonColor = 'default' | 'success' | 'danger';
|
|
14
|
+
type ButtonVariant = 'primary' | 'secondary' | 'text';
|
|
15
|
+
|
|
16
|
+
export interface TransientButtonProps {
|
|
17
|
+
size?: ButtonSize;
|
|
18
|
+
color?: ButtonColor;
|
|
19
|
+
variant?: ButtonVariant;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RegularButtonProps {
|
|
23
|
+
trackingId?: string,
|
|
24
|
+
trackingData?: object,
|
|
25
|
+
LeftIcon?: React.ElementType,
|
|
26
|
+
RightIcon?: React.ElementType,
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Props shared for both types of the button
|
|
31
|
+
export type CommonButtonProps = RegularButtonProps & TransientButtonProps & MarginSpacingProps;
|
|
32
|
+
// Regular button must have onClick defined
|
|
33
|
+
export type ButtonProps = CommonButtonProps & WithRequired<RegularBoxProps, 'onClick'>;
|
|
34
|
+
// OR it can pass to to become anchor link - in that case onClick is not needed
|
|
35
|
+
export type AnchorButtonProps = CommonButtonProps & RegularBoxProps & LinkProps;
|
|
36
|
+
|
|
37
|
+
// typeguard to distinguish between the two options for props
|
|
38
|
+
function isAnchorButton(props: ButtonProps | AnchorButtonProps): props is AnchorButtonProps {
|
|
39
|
+
return (props as AnchorButtonProps).to !== undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ButtonColorCombinations = {
|
|
43
|
+
[Type in ButtonVariant]: {
|
|
44
|
+
[Size in ButtonColor]: {
|
|
45
|
+
textColor: string,
|
|
46
|
+
borderColor: string
|
|
47
|
+
backgroundColor: string,
|
|
48
|
+
|
|
49
|
+
// hover & active state affects both border & background.
|
|
50
|
+
hoverColor?: string,
|
|
51
|
+
activeColor?: string,
|
|
52
|
+
actionTextColor?: string,
|
|
53
|
+
|
|
54
|
+
// only exception is primary outlined button
|
|
55
|
+
actionBorderColor?: string
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type ButtonSizeCombinations = {
|
|
61
|
+
[Size in ButtonSize]: {
|
|
62
|
+
fontSize: number,
|
|
63
|
+
horizontalPadding: number,
|
|
64
|
+
height: number,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const BUTTON_COLOR_VARIANTS_CSS: ButtonColorCombinations = {
|
|
69
|
+
primary: {
|
|
70
|
+
default: {
|
|
71
|
+
textColor: theme.color.neutral.backgroundSubtle,
|
|
72
|
+
backgroundColor: theme.color.primary.action,
|
|
73
|
+
borderColor: theme.color.primary.action,
|
|
74
|
+
hoverColor: theme.color.primary.actionHover,
|
|
75
|
+
activeColor: theme.color.primary.actionActive,
|
|
76
|
+
},
|
|
77
|
+
success: {
|
|
78
|
+
textColor: theme.color.neutral.backgroundSubtle,
|
|
79
|
+
backgroundColor: theme.color.success.action,
|
|
80
|
+
borderColor: theme.color.success.action,
|
|
81
|
+
hoverColor: theme.color.success.actionHover,
|
|
82
|
+
activeColor: theme.color.success.actionActive,
|
|
83
|
+
},
|
|
84
|
+
danger: {
|
|
85
|
+
textColor: theme.color.neutral.backgroundSubtle,
|
|
86
|
+
backgroundColor: theme.color.danger.action,
|
|
87
|
+
borderColor: theme.color.danger.action,
|
|
88
|
+
hoverColor: theme.color.danger.actionHover,
|
|
89
|
+
activeColor: theme.color.danger.actionActive,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
secondary: {
|
|
93
|
+
default: {
|
|
94
|
+
textColor: theme.color.neutral.text,
|
|
95
|
+
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
96
|
+
borderColor: theme.color.neutral.border,
|
|
97
|
+
hoverColor: theme.color.neutral.actionSecondaryHover,
|
|
98
|
+
activeColor: theme.color.neutral.actionSecondaryActive,
|
|
99
|
+
actionBorderColor: theme.color.neutral.border,
|
|
100
|
+
},
|
|
101
|
+
success: {
|
|
102
|
+
textColor: theme.color.success.text,
|
|
103
|
+
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
104
|
+
borderColor: theme.color.neutral.border,
|
|
105
|
+
hoverColor: theme.color.success.actionHover,
|
|
106
|
+
activeColor: theme.color.success.actionActive,
|
|
107
|
+
actionTextColor: theme.color.neutral.background,
|
|
108
|
+
},
|
|
109
|
+
danger: {
|
|
110
|
+
textColor: theme.color.danger.text,
|
|
111
|
+
backgroundColor: theme.color.neutral.backgroundMuted,
|
|
112
|
+
borderColor: theme.color.neutral.border,
|
|
113
|
+
hoverColor: theme.color.danger.actionHover,
|
|
114
|
+
activeColor: theme.color.danger.actionActive,
|
|
115
|
+
actionTextColor: theme.color.neutral.background,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
text: {
|
|
119
|
+
default: {
|
|
120
|
+
textColor: theme.color.neutral.text,
|
|
121
|
+
backgroundColor: 'transparent',
|
|
122
|
+
borderColor: 'transparent',
|
|
123
|
+
// TODO: Not sure about these
|
|
124
|
+
hoverColor: theme.color.neutral.hover,
|
|
125
|
+
activeColor: theme.color.neutral.actionSecondaryActive,
|
|
126
|
+
},
|
|
127
|
+
success: {
|
|
128
|
+
textColor: theme.color.success.text,
|
|
129
|
+
backgroundColor: 'transparent',
|
|
130
|
+
borderColor: 'transparent',
|
|
131
|
+
hoverColor: theme.color.success.backgroundSubtleHover,
|
|
132
|
+
activeColor: theme.color.success.backgroundSubtleActive,
|
|
133
|
+
},
|
|
134
|
+
danger: {
|
|
135
|
+
textColor: theme.color.danger.text,
|
|
136
|
+
backgroundColor: 'transparent',
|
|
137
|
+
borderColor: 'transparent',
|
|
138
|
+
hoverColor: theme.color.danger.backgroundSubtleHover,
|
|
139
|
+
activeColor: theme.color.danger.backgroundSubtleActive,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const BUTTON_SIZE_VARIANTS_CSS: ButtonSizeCombinations = {
|
|
145
|
+
medium: {
|
|
146
|
+
fontSize: 14,
|
|
147
|
+
height: 36,
|
|
148
|
+
horizontalPadding: 12,
|
|
149
|
+
},
|
|
150
|
+
small: {
|
|
151
|
+
fontSize: 14,
|
|
152
|
+
height: 28,
|
|
153
|
+
horizontalPadding: 8,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const getButtonColorStyles = (variant: ButtonVariant = 'primary', color: ButtonColor = 'default') => {
|
|
158
|
+
const {
|
|
159
|
+
backgroundColor,
|
|
160
|
+
borderColor,
|
|
161
|
+
textColor,
|
|
162
|
+
actionTextColor,
|
|
163
|
+
activeColor,
|
|
164
|
+
hoverColor,
|
|
165
|
+
actionBorderColor,
|
|
166
|
+
} = BUTTON_COLOR_VARIANTS_CSS[variant][color];
|
|
167
|
+
|
|
168
|
+
return css`
|
|
169
|
+
color: ${textColor};
|
|
170
|
+
background-color: ${backgroundColor};
|
|
171
|
+
border-color: ${borderColor};
|
|
172
|
+
|
|
173
|
+
&:hover {
|
|
174
|
+
color: ${actionTextColor || textColor};
|
|
175
|
+
background-color: ${hoverColor};
|
|
176
|
+
border-color: ${actionBorderColor || hoverColor};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
&:active {
|
|
180
|
+
color: ${actionTextColor || textColor};
|
|
181
|
+
background-color: ${activeColor};
|
|
182
|
+
border-color: ${actionBorderColor || activeColor};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&:disabled {
|
|
186
|
+
color: ${theme.color.neutral.textDisabled};
|
|
187
|
+
background-color: ${theme.color.neutral.disabled};
|
|
188
|
+
border-color: ${variant === 'text' ? 'transparent' : theme.color.neutral.disabled};
|
|
189
|
+
|
|
190
|
+
cursor: default;
|
|
191
|
+
}
|
|
192
|
+
`;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const getButtonSizeStyles = (size: ButtonSize = 'medium') => {
|
|
196
|
+
const {
|
|
197
|
+
fontSize,
|
|
198
|
+
height,
|
|
199
|
+
horizontalPadding,
|
|
200
|
+
} = BUTTON_SIZE_VARIANTS_CSS[size];
|
|
201
|
+
|
|
202
|
+
return css`
|
|
203
|
+
height: ${height}px;
|
|
204
|
+
font-size: ${fontSize}px;
|
|
205
|
+
/* We just want to ensure padding on the sides. Height is set the the hard way for simplicity */
|
|
206
|
+
padding: 0 ${horizontalPadding}px;
|
|
207
|
+
`;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const StyledButton = styled(Box)<WithTransientProps<TransientButtonProps>>`
|
|
211
|
+
/* Basic positioning */
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
/* NOT sure about this. It needs to be set when we want 100% width button */
|
|
215
|
+
/* Maybe we can add block property */
|
|
216
|
+
justify-content: center;
|
|
217
|
+
gap: ${theme.space.space8};
|
|
218
|
+
|
|
219
|
+
/* Basic styles */
|
|
220
|
+
font-weight: 500;
|
|
221
|
+
white-space: nowrap;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
transition: border-color ${theme.transition.fastEaseOut}, background-color ${theme.transition.fastEaseOut};
|
|
224
|
+
|
|
225
|
+
/* Border is always defined, but it can be set to transparent */
|
|
226
|
+
border-style: solid;
|
|
227
|
+
border-width: 1px;
|
|
228
|
+
border-radius: ${theme.radius.radius6};
|
|
229
|
+
border-color: transparent;
|
|
230
|
+
|
|
231
|
+
/* Colors */
|
|
232
|
+
${(props) => getButtonColorStyles(props.$variant, props.$color)}
|
|
233
|
+
|
|
234
|
+
/* Paddings & font size */
|
|
235
|
+
${(props) => getButtonSizeStyles(props.$size)}
|
|
236
|
+
`;
|
|
237
|
+
|
|
238
|
+
export const Button = forwardRef<HTMLElement, ButtonProps | AnchorButtonProps>((props, ref) => {
|
|
239
|
+
const {
|
|
240
|
+
as,
|
|
241
|
+
children,
|
|
242
|
+
size,
|
|
243
|
+
color,
|
|
244
|
+
variant,
|
|
245
|
+
LeftIcon,
|
|
246
|
+
RightIcon,
|
|
247
|
+
onClick,
|
|
248
|
+
trackingId,
|
|
249
|
+
trackingData,
|
|
250
|
+
...rest
|
|
251
|
+
} = props;
|
|
252
|
+
|
|
253
|
+
const {
|
|
254
|
+
trackClick,
|
|
255
|
+
windowLocationHost,
|
|
256
|
+
} = useSharedUiDependencies();
|
|
257
|
+
const trackedOnClick = (e: React.MouseEvent) => {
|
|
258
|
+
if (trackClick && trackingId) trackClick(trackingId, trackingData);
|
|
259
|
+
if (onClick) onClick(e);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const iconSize = size === 'medium' ? '16' : '12';
|
|
263
|
+
|
|
264
|
+
if (isAnchorButton(props)) {
|
|
265
|
+
const isExternal = isUrlExternal(props.to, windowLocationHost);
|
|
266
|
+
const EffectiveRightIcon = (isExternal && !props.hideExternalIcon) ? ExternalLinkIcon : RightIcon;
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<StyledButton
|
|
270
|
+
$size={size}
|
|
271
|
+
$color={color}
|
|
272
|
+
$variant={variant}
|
|
273
|
+
// If anchor is undefined, we just render it as a regular button
|
|
274
|
+
forwardedAs={props.disabled ? 'button' : Link}
|
|
275
|
+
ref={ref}
|
|
276
|
+
onClick={trackedOnClick}
|
|
277
|
+
to={props.to}
|
|
278
|
+
{...rest}
|
|
279
|
+
// If we want to show external icon, we use button's slot for icon
|
|
280
|
+
hideExternalIcon={true}
|
|
281
|
+
>
|
|
282
|
+
{LeftIcon && <LeftIcon size={iconSize} />}
|
|
283
|
+
{children}
|
|
284
|
+
{EffectiveRightIcon && <EffectiveRightIcon size={iconSize} />}
|
|
285
|
+
</StyledButton>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<StyledButton
|
|
291
|
+
$size={size}
|
|
292
|
+
$color={color}
|
|
293
|
+
$variant={variant}
|
|
294
|
+
forwardedAs={ as || 'button'}
|
|
295
|
+
ref={ref}
|
|
296
|
+
onClick={trackedOnClick}
|
|
297
|
+
type='button'
|
|
298
|
+
{...rest}
|
|
299
|
+
>
|
|
300
|
+
{LeftIcon && <LeftIcon size={iconSize} />}
|
|
301
|
+
{children}
|
|
302
|
+
{RightIcon && <RightIcon size={iconSize} />}
|
|
303
|
+
</StyledButton>
|
|
304
|
+
);
|
|
305
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import type { FC } from 'react';
|
|
3
|
+
import React, { forwardRef } from 'react';
|
|
4
|
+
import styled, { css } from 'styled-components';
|
|
5
|
+
|
|
6
|
+
import type { ValueOf } from '@apify-packages/types';
|
|
7
|
+
|
|
8
|
+
import { theme } from '../design_system/theme.js';
|
|
9
|
+
import type { RegularBoxProps } from './box.js';
|
|
10
|
+
|
|
11
|
+
const CHIP_SIZES = {
|
|
12
|
+
EXTRA_SMALL: 'XS',
|
|
13
|
+
SMALL: 'S',
|
|
14
|
+
MEDIUM: 'M',
|
|
15
|
+
LARGE: 'L',
|
|
16
|
+
} as const;
|
|
17
|
+
type CHIP_SIZES = ValueOf<typeof CHIP_SIZES>;
|
|
18
|
+
|
|
19
|
+
const CHIP_TYPES = {
|
|
20
|
+
DEFAULT: 'DEFAULT',
|
|
21
|
+
PRIMARY: 'PRIMARY',
|
|
22
|
+
SUCCESS: 'SUCCESS',
|
|
23
|
+
WARNING: 'WARNING',
|
|
24
|
+
DANGER: 'DANGER',
|
|
25
|
+
} as const;
|
|
26
|
+
type CHIP_TYPES = ValueOf<typeof CHIP_TYPES>;
|
|
27
|
+
|
|
28
|
+
export const classNames = {
|
|
29
|
+
BODY: 'Chip-body',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const chipSizeStyle = {
|
|
33
|
+
[CHIP_SIZES.EXTRA_SMALL]: css`
|
|
34
|
+
font-size: 12px;
|
|
35
|
+
line-height: 16px;
|
|
36
|
+
padding: 0 4px;
|
|
37
|
+
border-radius: 6px;
|
|
38
|
+
`,
|
|
39
|
+
[CHIP_SIZES.SMALL]: css`
|
|
40
|
+
font-size: 12px;
|
|
41
|
+
line-height: 16px;
|
|
42
|
+
padding: 2px 4px;
|
|
43
|
+
border-radius: 6px;
|
|
44
|
+
`,
|
|
45
|
+
[CHIP_SIZES.MEDIUM]: css`
|
|
46
|
+
font-size: 14px;
|
|
47
|
+
line-height: 20px;
|
|
48
|
+
padding: 2px 8px;
|
|
49
|
+
border-radius: 100px;
|
|
50
|
+
`,
|
|
51
|
+
[CHIP_SIZES.LARGE]: css`
|
|
52
|
+
font-size: 16px;
|
|
53
|
+
line-height: 20px;
|
|
54
|
+
padding: 2px 8px;
|
|
55
|
+
border-radius: 100px;
|
|
56
|
+
`,
|
|
57
|
+
} satisfies Record<CHIP_SIZES, unknown>;
|
|
58
|
+
|
|
59
|
+
const chipTypeStyle = {
|
|
60
|
+
[CHIP_TYPES.DEFAULT]: css`
|
|
61
|
+
color: ${theme.color.neutral.text};
|
|
62
|
+
background: ${theme.color.neutral.chipBackground};
|
|
63
|
+
`,
|
|
64
|
+
[CHIP_TYPES.PRIMARY]: css`
|
|
65
|
+
color: ${theme.color.primary.chipText};
|
|
66
|
+
background: ${theme.color.primary.chipBackground};
|
|
67
|
+
`,
|
|
68
|
+
[CHIP_TYPES.SUCCESS]: css`
|
|
69
|
+
color: ${theme.color.success.chipText};
|
|
70
|
+
background: ${theme.color.success.chipBackground};
|
|
71
|
+
`,
|
|
72
|
+
[CHIP_TYPES.WARNING]: css`
|
|
73
|
+
color: ${theme.color.warning.chipText};
|
|
74
|
+
background: ${theme.color.warning.chipBackground};
|
|
75
|
+
`,
|
|
76
|
+
[CHIP_TYPES.DANGER]: css`
|
|
77
|
+
color: ${theme.color.danger.chipText};
|
|
78
|
+
background: ${theme.color.danger.chipBackground};
|
|
79
|
+
`,
|
|
80
|
+
} satisfies Record<CHIP_TYPES, unknown>;
|
|
81
|
+
|
|
82
|
+
const StyledChip = styled.span<{size: CHIP_SIZES, type: CHIP_TYPES, clickable: boolean}>`
|
|
83
|
+
${({ size }) => chipSizeStyle[size]};
|
|
84
|
+
${({ type }) => chipTypeStyle[type]};
|
|
85
|
+
/* Static styles */
|
|
86
|
+
width: fit-content;
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: row;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
align-items: center;
|
|
91
|
+
font-weight: normal;
|
|
92
|
+
white-space: nowrap;
|
|
93
|
+
cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')};
|
|
94
|
+
gap: ${theme.space.space4};
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
export type ChipProps = RegularBoxProps & {
|
|
98
|
+
type?: CHIP_TYPES
|
|
99
|
+
size?: CHIP_SIZES
|
|
100
|
+
icon?: React.ReactNode
|
|
101
|
+
clickable?: boolean
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Component for displaying status and for labelling other components.
|
|
106
|
+
*/
|
|
107
|
+
export const Chip = forwardRef(({
|
|
108
|
+
type = CHIP_TYPES.DEFAULT,
|
|
109
|
+
size = CHIP_SIZES.MEDIUM,
|
|
110
|
+
icon,
|
|
111
|
+
children,
|
|
112
|
+
className,
|
|
113
|
+
...passThroughProps
|
|
114
|
+
}: ChipProps, ref) => {
|
|
115
|
+
const otherProps = { ...passThroughProps, type, size, className: clsx(className, classNames.BODY) };
|
|
116
|
+
|
|
117
|
+
return <StyledChip ref={ref} {...otherProps}>{children}{icon}</StyledChip>;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
Chip.displayName = 'Chip';
|
|
121
|
+
|
|
122
|
+
type SpecificChipProps = Omit<ChipProps, 'type'>
|
|
123
|
+
|
|
124
|
+
export const PrimaryChip: FC<SpecificChipProps> = (props) => <Chip type={CHIP_TYPES.PRIMARY} {...props} />;
|
|
125
|
+
export const NeutralChip: FC<SpecificChipProps> = (props) => <Chip type={CHIP_TYPES.DEFAULT} {...props} />;
|
|
126
|
+
export const SuccessChip: FC<SpecificChipProps> = (props) => <Chip type={CHIP_TYPES.SUCCESS} {...props} />;
|
|
127
|
+
export const DangerChip: FC<SpecificChipProps> = (props) => <Chip type={CHIP_TYPES.DANGER} {...props} />;
|
|
128
|
+
export const WarningChip: FC<SpecificChipProps> = (props) => <Chip type={CHIP_TYPES.WARNING} {...props} />;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled, { css } from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import { CheckIcon, CopyIcon } from '@apify/ui-icons';
|
|
5
|
+
|
|
6
|
+
import { theme } from '../../design_system/theme.js';
|
|
7
|
+
import { useCopyToClipboard } from '../../utils/index.js';
|
|
8
|
+
import { Text } from '../text/index.js';
|
|
9
|
+
|
|
10
|
+
interface StyledButtonProps {
|
|
11
|
+
$successStyle?: boolean;
|
|
12
|
+
$hasText?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const StyledButton = styled.button<StyledButtonProps>`
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
align-items: center;
|
|
19
|
+
|
|
20
|
+
border: 1px solid ${theme.color.neutral.border};
|
|
21
|
+
border-radius: ${theme.radius.radius6};
|
|
22
|
+
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
|
|
25
|
+
background: ${theme.color.neutral.backgroundMuted};
|
|
26
|
+
color: ${theme.color.neutral.icon};
|
|
27
|
+
&:hover {
|
|
28
|
+
background-color: ${theme.color.neutral.hover};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
padding: ${theme.space.space4};
|
|
32
|
+
height: 2.8rem;
|
|
33
|
+
width: 2.8rem;
|
|
34
|
+
|
|
35
|
+
svg {
|
|
36
|
+
width: 2rem;
|
|
37
|
+
height: 2rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
${({ $hasText }) => $hasText
|
|
41
|
+
&& css`
|
|
42
|
+
width: auto;
|
|
43
|
+
padding: ${theme.space.space4} ${theme.space.space8};
|
|
44
|
+
p {
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
}
|
|
47
|
+
`}
|
|
48
|
+
|
|
49
|
+
${({ $successStyle }) => $successStyle
|
|
50
|
+
&& css`
|
|
51
|
+
background-color: ${theme.color.success.action};
|
|
52
|
+
color: ${theme.color.neutral.textOnPrimary};
|
|
53
|
+
border: none;
|
|
54
|
+
:active {
|
|
55
|
+
background-color: ${theme.color.success.actionActive};
|
|
56
|
+
}
|
|
57
|
+
:hover {
|
|
58
|
+
background-color: ${theme.color.success.action};
|
|
59
|
+
}
|
|
60
|
+
`}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
interface ActionButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
64
|
+
successStyle?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const ActionButton = ({
|
|
68
|
+
successStyle,
|
|
69
|
+
children,
|
|
70
|
+
...props
|
|
71
|
+
}: ActionButtonProps) => {
|
|
72
|
+
const hasText = typeof children === 'string';
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<StyledButton
|
|
76
|
+
$successStyle={successStyle}
|
|
77
|
+
$hasText={hasText}
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
{hasText ? <Text weight="bold">{children}</Text> : children}
|
|
81
|
+
</StyledButton>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
interface CopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
86
|
+
code: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const CopyButton = ({ code, ...props }: CopyButtonProps) => {
|
|
90
|
+
const [isCopied, handleClick] = useCopyToClipboard({ text: code });
|
|
91
|
+
return (
|
|
92
|
+
<ActionButton onClick={handleClick} data-test='copy_to_clipboard' {...props}>
|
|
93
|
+
{isCopied ? <CheckIcon size="16" /> : <CopyIcon size="16" />}
|
|
94
|
+
</ActionButton>
|
|
95
|
+
);
|
|
96
|
+
};
|