@apify/ui-library 0.71.1-featcolortokens-178953.55 → 0.71.1-featcolortokens-178953.58
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/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +7 -5
- package/.stylelintrc +0 -12
- package/CHANGELOG.md +0 -3334
- package/CODEOWNERS +0 -7
- package/eslint.config.mjs +0 -44
- package/src/codemods/generate_typograpy_tokens_files.mjs +0 -137
- package/src/components/action_link.tsx +0 -60
- package/src/components/actor_template_card.tsx +0 -116
- package/src/components/badge.tsx +0 -148
- package/src/components/banner.tsx +0 -94
- package/src/components/blog_article.tsx +0 -85
- package/src/components/box.tsx +0 -127
- package/src/components/button.tsx +0 -305
- package/src/components/chip.tsx +0 -128
- package/src/components/code/action_button.tsx +0 -96
- package/src/components/code/code_block/code_block.styled.tsx +0 -180
- package/src/components/code/code_block/code_block.tsx +0 -224
- package/src/components/code/code_block/code_block_with_tabs.tsx +0 -257
- package/src/components/code/code_block/utils.tsx +0 -67
- package/src/components/code/index.ts +0 -5
- package/src/components/code/inline_code/inline_code.tsx +0 -62
- package/src/components/code/one_line_code/one_line_code.tsx +0 -228
- package/src/components/code/prism_highlighter.tsx +0 -180
- package/src/components/color_wheel_gradient.tsx +0 -31
- package/src/components/floating/index.ts +0 -3
- package/src/components/floating/menu.tsx +0 -189
- package/src/components/floating/menu_common.tsx +0 -31
- package/src/components/floating/menu_components.tsx +0 -99
- package/src/components/image.tsx +0 -24
- package/src/components/index.ts +0 -22
- package/src/components/link.tsx +0 -114
- package/src/components/message.tsx +0 -153
- package/src/components/rating.tsx +0 -106
- package/src/components/readme_renderer/index.ts +0 -3
- package/src/components/readme_renderer/pythonize_value.ts +0 -76
- package/src/components/readme_renderer/table_of_contents.tsx +0 -272
- package/src/components/readme_renderer/utils.tsx +0 -46
- package/src/components/simple_markdown/index.ts +0 -2
- package/src/components/simple_markdown/simple_markdown.tsx +0 -214
- package/src/components/simple_markdown/simple_markdown_components.tsx +0 -293
- package/src/components/tabs/index.ts +0 -2
- package/src/components/tabs/tab.tsx +0 -217
- package/src/components/tabs/tabs.tsx +0 -169
- package/src/components/tag.tsx +0 -196
- package/src/components/text/heading_content.tsx +0 -56
- package/src/components/text/heading_marketing.tsx +0 -55
- package/src/components/text/heading_shared.tsx +0 -55
- package/src/components/text/index.ts +0 -19
- package/src/components/text/text_base.tsx +0 -52
- package/src/components/text/text_content.tsx +0 -104
- package/src/components/text/text_marketing.tsx +0 -152
- package/src/components/text/text_shared.tsx +0 -95
- package/src/components/tile/horizontal_tile.tsx +0 -77
- package/src/components/tile/index.ts +0 -2
- package/src/components/tile/shared.ts +0 -27
- package/src/components/tile/vertical_tile.tsx +0 -59
- package/src/components/to_consolidate/card.tsx +0 -141
- package/src/components/to_consolidate/index.ts +0 -4
- package/src/components/to_consolidate/markdown.tsx +0 -609
- package/src/components/to_consolidate/pagination.tsx +0 -136
- package/src/components/to_consolidate/tab_number_chip.tsx +0 -31
- package/src/design_system/colors/build_color_tokens.js +0 -169
- package/src/design_system/colors/figma_color_tokens.dark.json +0 -886
- package/src/design_system/colors/figma_color_tokens.light.json +0 -886
- package/src/design_system/colors/generated/colors_theme.dark.ts +0 -110
- package/src/design_system/colors/generated/colors_theme.light.ts +0 -110
- package/src/design_system/colors/generated/dark.ts +0 -147
- package/src/design_system/colors/generated/light.ts +0 -147
- package/src/design_system/colors/generated/palette.dark.ts +0 -74
- package/src/design_system/colors/generated/palette.light.ts +0 -74
- package/src/design_system/colors/generated/properties_theme.ts +0 -179
- package/src/design_system/colors/index.ts +0 -7
- package/src/design_system/colors_theme.ts +0 -213
- package/src/design_system/properties_theme.ts +0 -453
- package/src/design_system/supernova_typography_tokens.json +0 -657
- package/src/design_system/theme.ts +0 -25
- package/src/design_system/tokens/index.ts +0 -5
- package/src/design_system/tokens/layouts.ts +0 -29
- package/src/design_system/tokens/radiuses.ts +0 -22
- package/src/design_system/tokens/shadows.ts +0 -22
- package/src/design_system/tokens/spaces.ts +0 -15
- package/src/design_system/tokens/transitions.ts +0 -19
- package/src/design_system/typography_theme.ts +0 -197
- package/src/index.ts +0 -8
- package/src/type_utils.ts +0 -7
- package/src/ui_dependency_provider.tsx +0 -58
- package/src/utils/copy_to_clipboard.ts +0 -24
- package/src/utils/image_color.ts +0 -42
- package/src/utils/index.ts +0 -4
- package/src/utils/resize_observer.ts +0 -18
- package/src/utils/sanitization.ts +0 -14
- package/style-dictionary.config.json +0 -29
- package/tsconfig.build.json +0 -17
- package/tsconfig.json +0 -10
- /package/{src/design_system/colors/generated → style/colors}/dark.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/light.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/palette.dark.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/palette.light.scss +0 -0
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FloatingFocusManager,
|
|
3
|
-
FloatingPortal,
|
|
4
|
-
useClick,
|
|
5
|
-
useDismiss,
|
|
6
|
-
useInteractions,
|
|
7
|
-
useListNavigation,
|
|
8
|
-
useRole,
|
|
9
|
-
useTypeahead,
|
|
10
|
-
} from '@floating-ui/react';
|
|
11
|
-
import clsx from 'clsx';
|
|
12
|
-
import React, {
|
|
13
|
-
useMemo,
|
|
14
|
-
useRef,
|
|
15
|
-
useState,
|
|
16
|
-
} from 'react';
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
Box,
|
|
20
|
-
type BoxProps,
|
|
21
|
-
} from '../box.js';
|
|
22
|
-
import { Text } from '../text/index.js';
|
|
23
|
-
import { useFloatingMenu } from './menu_common.js';
|
|
24
|
-
import {
|
|
25
|
-
DropdownMenuBaseComponent,
|
|
26
|
-
ListMenuComponent,
|
|
27
|
-
ListMenuItemComponent,
|
|
28
|
-
} from './menu_components.js';
|
|
29
|
-
|
|
30
|
-
export const menuClassNames = {
|
|
31
|
-
WRAPPER: 'menu-wrapper',
|
|
32
|
-
BASE: 'menu-base',
|
|
33
|
-
LIST: 'menu-list',
|
|
34
|
-
ITEM: 'menu-item',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type SelectActionType = 'click' | 'enter' | 'space' | 'type';
|
|
38
|
-
|
|
39
|
-
// It might be tempting to define label as ReactNode, but we need to have the string value for keyboard navigation
|
|
40
|
-
// More difficult cases can be handled using renderOption prop
|
|
41
|
-
export interface MenuOption {
|
|
42
|
-
label: string,
|
|
43
|
-
value: string,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface MenuProps<T = MenuOption> {
|
|
47
|
-
options: T[],
|
|
48
|
-
value?: string,
|
|
49
|
-
onSelect: (newValue: string, selectedBy: SelectActionType) => void,
|
|
50
|
-
defaultLabel?: React.ReactNode,
|
|
51
|
-
closeOnSelect?: boolean,
|
|
52
|
-
renderOption?: (option: T) => React.ReactNode,
|
|
53
|
-
components?: {
|
|
54
|
-
MenuBase?: React.ElementType,
|
|
55
|
-
Menu?: React.ElementType,
|
|
56
|
-
MenuItem?: React.ElementType,
|
|
57
|
-
},
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const defaultRenderOption = ({ label }: MenuOption) => (<Text as='span'>{label}</Text>);
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* This example is a Select taken from https://floating-ui.com/docs/react-examples
|
|
64
|
-
* It tries to mimic API of react-select as closely as possible
|
|
65
|
-
*/
|
|
66
|
-
export const Menu = <T extends MenuOption>({
|
|
67
|
-
options,
|
|
68
|
-
value,
|
|
69
|
-
onSelect,
|
|
70
|
-
closeOnSelect = true,
|
|
71
|
-
defaultLabel,
|
|
72
|
-
components,
|
|
73
|
-
renderOption,
|
|
74
|
-
className,
|
|
75
|
-
...rest
|
|
76
|
-
}: MenuProps<T> & BoxProps) => {
|
|
77
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
78
|
-
const { refs, floatingStyles, context } = useFloatingMenu({
|
|
79
|
-
isOpen,
|
|
80
|
-
setIsOpen,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const selectedIndex = useMemo(() => {
|
|
84
|
-
const foundIndex = options.findIndex((option) => option.value === value);
|
|
85
|
-
return foundIndex < 0 ? null : foundIndex;
|
|
86
|
-
}, [options, value]);
|
|
87
|
-
|
|
88
|
-
const [activeIndex, setActiveIndex] = useState<number | null>(null);
|
|
89
|
-
const handleSelect = (newIndex: number, selectedBy: SelectActionType) => {
|
|
90
|
-
onSelect(options[newIndex].value, selectedBy);
|
|
91
|
-
if (closeOnSelect) setIsOpen(false);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const listRef = useRef<(HTMLElement | null)[]>([]);
|
|
95
|
-
const isTypingRef = useRef(false);
|
|
96
|
-
const listContentRef = useRef(options.map((option) => option.label));
|
|
97
|
-
|
|
98
|
-
const click = useClick(context, { event: 'mousedown' });
|
|
99
|
-
const dismiss = useDismiss(context);
|
|
100
|
-
const typeahead = useTypeahead(context, {
|
|
101
|
-
listRef: listContentRef,
|
|
102
|
-
activeIndex,
|
|
103
|
-
selectedIndex,
|
|
104
|
-
onMatch: isOpen ? setActiveIndex : (newIndex) => onSelect(options[newIndex].value, 'type'),
|
|
105
|
-
onTypingChange(isTyping) {
|
|
106
|
-
isTypingRef.current = isTyping;
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
const role = useRole(context, { role: 'listbox' });
|
|
110
|
-
const listNav = useListNavigation(context, {
|
|
111
|
-
listRef,
|
|
112
|
-
activeIndex,
|
|
113
|
-
selectedIndex,
|
|
114
|
-
onNavigate: setActiveIndex,
|
|
115
|
-
loop: true,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const { getFloatingProps, getItemProps, getReferenceProps } = useInteractions([click, dismiss, role, listNav, typeahead]);
|
|
119
|
-
|
|
120
|
-
const MenuBaseComponent = components?.MenuBase || DropdownMenuBaseComponent;
|
|
121
|
-
const MenuComponent = components?.Menu || ListMenuComponent;
|
|
122
|
-
const MenuItemComponent = components?.MenuItem || ListMenuItemComponent;
|
|
123
|
-
|
|
124
|
-
const effectiveRenderOption = renderOption || defaultRenderOption;
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<Box
|
|
128
|
-
className={clsx(className, menuClassNames.WRAPPER)}
|
|
129
|
-
{...rest}
|
|
130
|
-
>
|
|
131
|
-
<MenuBaseComponent
|
|
132
|
-
aria-labelledby="select-label"
|
|
133
|
-
aria-autocomplete="none"
|
|
134
|
-
ref={refs.setReference}
|
|
135
|
-
{...getReferenceProps()}
|
|
136
|
-
className={menuClassNames.BASE}
|
|
137
|
-
tabindex="0"
|
|
138
|
-
>
|
|
139
|
-
{selectedIndex !== null ? options[selectedIndex].label : defaultLabel}
|
|
140
|
-
</MenuBaseComponent>
|
|
141
|
-
{isOpen && (
|
|
142
|
-
<FloatingPortal>
|
|
143
|
-
<FloatingFocusManager
|
|
144
|
-
context={context}
|
|
145
|
-
modal={false}
|
|
146
|
-
>
|
|
147
|
-
<MenuComponent
|
|
148
|
-
ref={refs.setFloating}
|
|
149
|
-
style={floatingStyles}
|
|
150
|
-
{...getFloatingProps()}
|
|
151
|
-
className={menuClassNames.LIST}
|
|
152
|
-
>
|
|
153
|
-
{options.map((option, i) => (
|
|
154
|
-
<MenuItemComponent
|
|
155
|
-
key={option.value}
|
|
156
|
-
$isSelected={i === selectedIndex}
|
|
157
|
-
$isActive={i === activeIndex}
|
|
158
|
-
ref={(node: HTMLElement | null) => {
|
|
159
|
-
listRef.current[i] = node;
|
|
160
|
-
}}
|
|
161
|
-
role="option"
|
|
162
|
-
tabIndex={i === activeIndex ? 0 : -1}
|
|
163
|
-
className={menuClassNames.ITEM}
|
|
164
|
-
aria-selected={i === selectedIndex && i === activeIndex}
|
|
165
|
-
{...getItemProps({
|
|
166
|
-
onClick: () => handleSelect(i, 'click'), // Handles mouse click
|
|
167
|
-
onKeyDown: (event) => {
|
|
168
|
-
if (event.key === 'Enter') {
|
|
169
|
-
event.preventDefault();
|
|
170
|
-
handleSelect(i, 'enter'); // Handles enter press
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (event.key === ' ' && !isTypingRef.current) {
|
|
174
|
-
event.preventDefault();
|
|
175
|
-
handleSelect(i, 'space');
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
})}
|
|
179
|
-
>
|
|
180
|
-
{effectiveRenderOption(option)}
|
|
181
|
-
</MenuItemComponent>
|
|
182
|
-
))}
|
|
183
|
-
</MenuComponent>
|
|
184
|
-
</FloatingFocusManager>
|
|
185
|
-
</FloatingPortal>
|
|
186
|
-
)}
|
|
187
|
-
</Box>
|
|
188
|
-
);
|
|
189
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
autoUpdate,
|
|
3
|
-
offset,
|
|
4
|
-
size,
|
|
5
|
-
useFloating,
|
|
6
|
-
} from '@floating-ui/react';
|
|
7
|
-
|
|
8
|
-
export const useFloatingMenu = ({
|
|
9
|
-
isOpen,
|
|
10
|
-
setIsOpen,
|
|
11
|
-
}: {
|
|
12
|
-
isOpen: boolean,
|
|
13
|
-
setIsOpen: (newIsOpen: boolean) => void
|
|
14
|
-
}) => useFloating<Element>({
|
|
15
|
-
placement: 'bottom-start',
|
|
16
|
-
open: isOpen,
|
|
17
|
-
onOpenChange: setIsOpen,
|
|
18
|
-
whileElementsMounted: autoUpdate,
|
|
19
|
-
middleware: [
|
|
20
|
-
offset(5),
|
|
21
|
-
size({
|
|
22
|
-
apply({ elements, availableHeight }) {
|
|
23
|
-
Object.assign(elements.floating.style, {
|
|
24
|
-
maxHeight: `${availableHeight}px`,
|
|
25
|
-
minHeight: '50px',
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
padding: 10,
|
|
29
|
-
}),
|
|
30
|
-
],
|
|
31
|
-
});
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ReferenceType,
|
|
3
|
-
type UseFloatingReturn,
|
|
4
|
-
} from '@floating-ui/react';
|
|
5
|
-
import { forwardRef } from 'react';
|
|
6
|
-
import styled, { css } from 'styled-components';
|
|
7
|
-
|
|
8
|
-
import { ChevronDownIcon } from '@apify/ui-icons';
|
|
9
|
-
|
|
10
|
-
import { theme } from '../../design_system/theme.js';
|
|
11
|
-
import type { BoxProps } from '../box.js';
|
|
12
|
-
import { Box } from '../box.js';
|
|
13
|
-
|
|
14
|
-
export type FloatingContext = Pick<UseFloatingReturn<ReferenceType>, 'context'>['context'];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Menu wrapper component
|
|
18
|
-
*/
|
|
19
|
-
export const ListMenuComponent = styled(Box).attrs({
|
|
20
|
-
p: 'space8',
|
|
21
|
-
})`
|
|
22
|
-
display: flex;
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
max-height: 300px;
|
|
25
|
-
min-width: 160px;
|
|
26
|
-
box-shadow: ${theme.shadow.shadow2};
|
|
27
|
-
background: ${theme.color.neutral.background};
|
|
28
|
-
border: 1px solid ${theme.color.neutral.separatorSubtle};
|
|
29
|
-
border-radius: ${theme.radius.radius8};
|
|
30
|
-
scrollbar-color: ${theme.color.neutral.separatorSubtle} ${theme.color.neutral.background};
|
|
31
|
-
outline: none;
|
|
32
|
-
overflow-y: auto;
|
|
33
|
-
z-index: 10;
|
|
34
|
-
`;
|
|
35
|
-
|
|
36
|
-
interface SelectableListMenuItemProps {
|
|
37
|
-
$isActive?: boolean,
|
|
38
|
-
$isSelected?: boolean,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Menu item component
|
|
43
|
-
*/
|
|
44
|
-
export const ListMenuItemComponent = styled(Box).attrs({
|
|
45
|
-
px: 'space8',
|
|
46
|
-
})<SelectableListMenuItemProps>`
|
|
47
|
-
border-radius: ${theme.radius.radius8};
|
|
48
|
-
outline: none;
|
|
49
|
-
cursor: pointer;
|
|
50
|
-
white-space: nowrap;
|
|
51
|
-
|
|
52
|
-
${({ $isActive }) => $isActive && css`
|
|
53
|
-
background-color: ${theme.color.neutral.hover};
|
|
54
|
-
`}
|
|
55
|
-
|
|
56
|
-
${({ $isSelected }) => $isSelected && css`
|
|
57
|
-
background-color: ${theme.color.neutral.backgroundSubtle};
|
|
58
|
-
color: ${theme.color.primary.text};
|
|
59
|
-
`}
|
|
60
|
-
`;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Menu base component WITHOUT dropdown icon
|
|
64
|
-
*/
|
|
65
|
-
export const PlainMenuBaseComponent = styled(Box)`
|
|
66
|
-
display: flex;
|
|
67
|
-
align-items: center;
|
|
68
|
-
gap: ${theme.space.space4};
|
|
69
|
-
padding: ${theme.space.space8};
|
|
70
|
-
border-radius: ${theme.radius.radius8};
|
|
71
|
-
border: 1px solid ${theme.color.neutral.separatorSubtle};
|
|
72
|
-
background-color: ${theme.color.neutral.backgroundMuted};
|
|
73
|
-
|
|
74
|
-
cursor: pointer;
|
|
75
|
-
transition: background-color 0.2s ease-in-out;
|
|
76
|
-
|
|
77
|
-
&:hover {
|
|
78
|
-
background-color: ${theme.color.neutral.backgroundSubtle};
|
|
79
|
-
}
|
|
80
|
-
`;
|
|
81
|
-
|
|
82
|
-
type DropdownMenuBaseComponentProps = {
|
|
83
|
-
children: React.ReactNode;
|
|
84
|
-
} & BoxProps;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Menu base component WITH dropdown icon
|
|
88
|
-
*/
|
|
89
|
-
export const DropdownMenuBaseComponent = forwardRef<HTMLElement, DropdownMenuBaseComponentProps>(({
|
|
90
|
-
children,
|
|
91
|
-
...props
|
|
92
|
-
}, ref) => {
|
|
93
|
-
return (
|
|
94
|
-
<PlainMenuBaseComponent {...props} ref={ref}>
|
|
95
|
-
{children}
|
|
96
|
-
<ChevronDownIcon size="16" color={theme.color.neutral.icon} />
|
|
97
|
-
</PlainMenuBaseComponent>
|
|
98
|
-
);
|
|
99
|
-
});
|
package/src/components/image.tsx
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { forwardRef } from 'react';
|
|
2
|
-
|
|
3
|
-
import type { ImageProxyOptions } from '../ui_dependency_provider.js';
|
|
4
|
-
import { useSharedUiDependencies } from '../ui_dependency_provider.js';
|
|
5
|
-
import { Box, type BoxProps } from './box.js';
|
|
6
|
-
|
|
7
|
-
type ImageProps = {
|
|
8
|
-
src: string,
|
|
9
|
-
alt?: string,
|
|
10
|
-
width?: number,
|
|
11
|
-
height?: number,
|
|
12
|
-
loading?: 'eager' | 'lazy' | undefined;
|
|
13
|
-
} & ImageProxyOptions
|
|
14
|
-
|
|
15
|
-
export const Image = forwardRef<HTMLImageElement, ImageProps & Omit<BoxProps, 'as'>>((props, ref) => {
|
|
16
|
-
const { InternalImage } = useSharedUiDependencies();
|
|
17
|
-
return (
|
|
18
|
-
<Box
|
|
19
|
-
ref={ref}
|
|
20
|
-
{...props}
|
|
21
|
-
as={InternalImage}
|
|
22
|
-
/>
|
|
23
|
-
);
|
|
24
|
-
});
|
package/src/components/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export * from './text/index.js';
|
|
2
|
-
export * from './box.js';
|
|
3
|
-
export * from './message.js';
|
|
4
|
-
export * from './floating/index.js';
|
|
5
|
-
export * from './button.js';
|
|
6
|
-
export * from './link.js';
|
|
7
|
-
export * from './action_link.js';
|
|
8
|
-
export * from './simple_markdown/index.js';
|
|
9
|
-
export * from './code/index.js';
|
|
10
|
-
export * from './color_wheel_gradient.js';
|
|
11
|
-
export * from './readme_renderer/index.js';
|
|
12
|
-
export * from './to_consolidate/index.js';
|
|
13
|
-
export * from './tile/index.js';
|
|
14
|
-
export * from './blog_article.js';
|
|
15
|
-
export * from './banner.js';
|
|
16
|
-
export * from './actor_template_card.js';
|
|
17
|
-
export * from './chip.js';
|
|
18
|
-
export * from './image.js';
|
|
19
|
-
export * from './rating.js';
|
|
20
|
-
export * from './badge.js';
|
|
21
|
-
export * from './tag.js';
|
|
22
|
-
export * from './tabs/index.js';
|
package/src/components/link.tsx
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx';
|
|
2
|
-
import { createPath, type Path } from 'history';
|
|
3
|
-
import React, { forwardRef } from 'react';
|
|
4
|
-
import styled from 'styled-components';
|
|
5
|
-
|
|
6
|
-
import { ExternalLinkIcon } from '@apify/ui-icons';
|
|
7
|
-
|
|
8
|
-
import { theme } from '../design_system/theme.js';
|
|
9
|
-
import { useSharedUiDependencies } from '../ui_dependency_provider.js';
|
|
10
|
-
import { Box, type BoxProps } from './box.js';
|
|
11
|
-
|
|
12
|
-
export type To = string | Partial<Path>;
|
|
13
|
-
export interface RegularLinkProps {
|
|
14
|
-
to: To,
|
|
15
|
-
hideExternalIcon?: boolean,
|
|
16
|
-
showExternalIcon?: boolean,
|
|
17
|
-
rel?: string,
|
|
18
|
-
target?: string,
|
|
19
|
-
trackingId?: string,
|
|
20
|
-
trackingData?: object,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// TODO: This function is copied from tools.client.js. We can remove it from there once this is deployed
|
|
24
|
-
/**
|
|
25
|
-
* Checks if passed url is external
|
|
26
|
-
*/
|
|
27
|
-
export const isUrlExternal = (url: To, windowLocationHost: string) => {
|
|
28
|
-
if (!url || typeof (url) !== 'string') return false;
|
|
29
|
-
const domainMatch = url.match(/^https?:\/\/([^/?#]+)(?:[/?#]|$)/i);
|
|
30
|
-
return !!(domainMatch && domainMatch[1] !== windowLocationHost);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// TODO: This function is copied from tools.client.js. We can remove it from there once this is deployed
|
|
34
|
-
/**
|
|
35
|
-
* Checks if passed url is email
|
|
36
|
-
*/
|
|
37
|
-
export const isUrlEmail = (url: To) => {
|
|
38
|
-
if (!url || typeof (url) !== 'string') return false;
|
|
39
|
-
return url.startsWith('mailto:');
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const StyledLink = styled(Box)`
|
|
43
|
-
/* Basic positioning */
|
|
44
|
-
display: inline-flex;
|
|
45
|
-
align-items: center;
|
|
46
|
-
gap: ${theme.space.space4};
|
|
47
|
-
|
|
48
|
-
/* Default behavior */
|
|
49
|
-
text-decoration: none;
|
|
50
|
-
transition: color ${theme.transition.fastEaseInOut};
|
|
51
|
-
|
|
52
|
-
&:hover {
|
|
53
|
-
text-decoration: none;
|
|
54
|
-
color: ${theme.color.primary.actionHover};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
&:active {
|
|
58
|
-
color: ${theme.color.primary.actionActive};
|
|
59
|
-
}
|
|
60
|
-
`;
|
|
61
|
-
|
|
62
|
-
export type LinkProps = RegularLinkProps & BoxProps;
|
|
63
|
-
|
|
64
|
-
export const Link = forwardRef<HTMLElement, LinkProps>(({
|
|
65
|
-
to,
|
|
66
|
-
children,
|
|
67
|
-
rel,
|
|
68
|
-
target,
|
|
69
|
-
hideExternalIcon,
|
|
70
|
-
showExternalIcon,
|
|
71
|
-
onClick,
|
|
72
|
-
trackingId,
|
|
73
|
-
trackingData,
|
|
74
|
-
...rest
|
|
75
|
-
}, ref) => {
|
|
76
|
-
const {
|
|
77
|
-
windowLocationHost,
|
|
78
|
-
isHrefTrusted,
|
|
79
|
-
trackClick,
|
|
80
|
-
InternalLink,
|
|
81
|
-
} = useSharedUiDependencies();
|
|
82
|
-
const href = typeof (to) === 'string' ? to : createPath(to);
|
|
83
|
-
const isExternal = isUrlExternal(to, windowLocationHost);
|
|
84
|
-
const isEmail = isUrlEmail(to);
|
|
85
|
-
const isTrusted = isHrefTrusted(href);
|
|
86
|
-
|
|
87
|
-
const trackedOnClick = (e: React.MouseEvent) => {
|
|
88
|
-
if (trackingId && trackClick) trackClick(trackingId, trackingData);
|
|
89
|
-
if (onClick) onClick(e);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const effectiveRel = clsx(
|
|
93
|
-
rel,
|
|
94
|
-
isExternal && 'external',
|
|
95
|
-
(isExternal || target === '_blank') && 'noopener',
|
|
96
|
-
(isExternal && !isTrusted) && 'nofollow',
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<StyledLink
|
|
101
|
-
// We use the InternalLink only for internal navigation
|
|
102
|
-
forwardedAs={(isEmail || isExternal) ? 'a' : InternalLink}
|
|
103
|
-
href={href}
|
|
104
|
-
rel={effectiveRel}
|
|
105
|
-
target={target || (isExternal ? '_blank' : '_self')}
|
|
106
|
-
onClick={trackedOnClick}
|
|
107
|
-
ref={ref}
|
|
108
|
-
{...rest}
|
|
109
|
-
>
|
|
110
|
-
{children}
|
|
111
|
-
{((isExternal && !hideExternalIcon) || showExternalIcon) && <ExternalLinkIcon size="16" />}
|
|
112
|
-
</StyledLink>
|
|
113
|
-
);
|
|
114
|
-
});
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import styled from 'styled-components';
|
|
4
|
-
|
|
5
|
-
import { CheckCircleIcon, CrossIcon, InfoIcon, WarningTriangleIcon } from '@apify/ui-icons';
|
|
6
|
-
|
|
7
|
-
import { theme } from '../design_system/theme.js';
|
|
8
|
-
import { Box, type BoxProps } from './box.js';
|
|
9
|
-
import { Button } from './button.js';
|
|
10
|
-
import { Heading } from './text/index.js';
|
|
11
|
-
|
|
12
|
-
export const messageClassNames = {
|
|
13
|
-
main: 'Message',
|
|
14
|
-
icon: 'icon',
|
|
15
|
-
content: 'content',
|
|
16
|
-
caption: 'caption',
|
|
17
|
-
dismiss: 'dismiss',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const StyledMessage = styled(Box)`
|
|
21
|
-
display: flex;
|
|
22
|
-
gap: ${theme.space.space8};
|
|
23
|
-
|
|
24
|
-
border-radius: ${theme.radius.radius8};
|
|
25
|
-
box-shadow: ${theme.shadow.shadow1};
|
|
26
|
-
|
|
27
|
-
.${messageClassNames.content} {
|
|
28
|
-
flex: 1;
|
|
29
|
-
margin-top: 1px; /* This is to align icon with text (align-items: center not possible - icon should be on top) */
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.${messageClassNames.caption} {
|
|
33
|
-
/* TODO: We should not override the default Heading that is rendered for caption but it doesn't look good without these */
|
|
34
|
-
line-height: 20px;
|
|
35
|
-
font-weight: 600;
|
|
36
|
-
margin-bottom: ${theme.space.space4};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.${messageClassNames.dismiss} {
|
|
40
|
-
background: transparent;
|
|
41
|
-
height: 20px;
|
|
42
|
-
|
|
43
|
-
svg {
|
|
44
|
-
color: ${theme.color.neutral.icon}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
&.borderless {
|
|
49
|
-
border: none !important;
|
|
50
|
-
background-color: transparent !important;
|
|
51
|
-
box-shadow: none !important;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
&.info {
|
|
55
|
-
background-color: ${theme.color.neutral.background};
|
|
56
|
-
border: 1px solid ${theme.color.neutral.border};
|
|
57
|
-
|
|
58
|
-
.${messageClassNames.icon} { color: ${theme.color.primary.icon}; }
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&.success {
|
|
62
|
-
background-color: ${theme.color.success.backgroundSubtle};
|
|
63
|
-
border: 1px solid ${theme.color.success.borderSubtle};
|
|
64
|
-
|
|
65
|
-
.${messageClassNames.icon} { color: ${theme.color.success.icon}; }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&.warning {
|
|
69
|
-
background-color: ${theme.color.warning.backgroundSubtle};
|
|
70
|
-
border: 1px solid ${theme.color.warning.borderSubtle};
|
|
71
|
-
|
|
72
|
-
.${messageClassNames.icon} { color: ${theme.color.warning.icon}; }
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
&.danger {
|
|
76
|
-
background-color: ${theme.color.danger.backgroundSubtle};
|
|
77
|
-
border: 1px solid ${theme.color.danger.borderSubtle};
|
|
78
|
-
|
|
79
|
-
.${messageClassNames.icon} { color: ${theme.color.danger.icon}; }
|
|
80
|
-
}
|
|
81
|
-
`;
|
|
82
|
-
|
|
83
|
-
export type MessageType = 'info' | 'warning' | 'success' | 'danger';
|
|
84
|
-
|
|
85
|
-
const typeToIcon: { [key in MessageType]: React.ElementType } = {
|
|
86
|
-
info: InfoIcon,
|
|
87
|
-
success: CheckCircleIcon,
|
|
88
|
-
warning: WarningTriangleIcon,
|
|
89
|
-
danger: WarningTriangleIcon,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
type MessageProps = BoxProps & {
|
|
93
|
-
type: MessageType,
|
|
94
|
-
caption?: string,
|
|
95
|
-
icon?: React.ElementType,
|
|
96
|
-
onDismissClick?: () => void,
|
|
97
|
-
borderless?: boolean,
|
|
98
|
-
boxless?: boolean,
|
|
99
|
-
as?: React.ElementType,
|
|
100
|
-
dismissTrackingId?: string,
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Component used to display larger messages that are part of the content of the application.
|
|
105
|
-
*/
|
|
106
|
-
export const Message: React.FC<MessageProps> = ({
|
|
107
|
-
className,
|
|
108
|
-
icon,
|
|
109
|
-
caption,
|
|
110
|
-
children,
|
|
111
|
-
onDismissClick,
|
|
112
|
-
type = 'warning',
|
|
113
|
-
borderless = false,
|
|
114
|
-
boxless = false,
|
|
115
|
-
dismissTrackingId,
|
|
116
|
-
as,
|
|
117
|
-
...rest
|
|
118
|
-
}) => {
|
|
119
|
-
const Icon = icon || typeToIcon[type];
|
|
120
|
-
return (
|
|
121
|
-
<StyledMessage
|
|
122
|
-
className={clsx(className, messageClassNames.main, type, borderless && 'borderless')}
|
|
123
|
-
mb={boxless ? 'space8' : 'space16'} // TODO: Export message without margin
|
|
124
|
-
p={boxless ? 'none' : 'space16'}
|
|
125
|
-
forwardedAs={as}
|
|
126
|
-
{...rest}
|
|
127
|
-
>
|
|
128
|
-
<Icon className={messageClassNames.icon} size="20" />
|
|
129
|
-
<div className={messageClassNames.content}>
|
|
130
|
-
{caption && (<Heading as='div' type='titleM' className={messageClassNames.caption}>{caption}</Heading>)}
|
|
131
|
-
{children}
|
|
132
|
-
</div>
|
|
133
|
-
{onDismissClick && (
|
|
134
|
-
<Button
|
|
135
|
-
size='small'
|
|
136
|
-
variant='text'
|
|
137
|
-
trackingId={dismissTrackingId}
|
|
138
|
-
onClick={onDismissClick}
|
|
139
|
-
className={messageClassNames.dismiss}
|
|
140
|
-
>
|
|
141
|
-
<CrossIcon size="16" />
|
|
142
|
-
</Button>
|
|
143
|
-
)}
|
|
144
|
-
</StyledMessage>
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
type SpecificMessageProps = Omit<MessageProps, 'type'>;
|
|
149
|
-
// Semantic classes for all the message types
|
|
150
|
-
export const InfoMessage = (props: SpecificMessageProps) => (<Message {...props} type='info' />);
|
|
151
|
-
export const WarningMessage = (props: SpecificMessageProps) => (<Message {...props} type='warning' />);
|
|
152
|
-
export const SuccessMessage = (props: SpecificMessageProps) => (<Message {...props} type='success' />);
|
|
153
|
-
export const DangerMessage = (props: SpecificMessageProps) => (<Message {...props} type='danger' />);
|