@bitrise/bitkit 9.23.0 → 9.24.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/package.json +12 -11
- package/src/Components/CloseButton/CloseButton.theme.ts +35 -0
- package/src/Components/CloseButton/CloseButton.tsx +18 -0
- package/src/Components/ColorButton/ColorButton.theme.ts +1 -1
- package/src/Components/Notification/Notification.stories.tsx +40 -0
- package/src/Components/Notification/Notification.theme.tsx +33 -0
- package/src/Components/Notification/Notification.tsx +87 -0
- package/src/Components/Toast/Toast.stories.tsx +30 -0
- package/src/Components/Toast/Toast.tsx +50 -0
- package/src/index.ts +2 -0
- package/src/theme.ts +4 -0
- package/src/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitrise/bitkit",
|
|
3
3
|
"description": "Bitrise React component library",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.24.0",
|
|
5
5
|
"repository": "git@github.com:bitrise-io/bitkit.git",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"license": "UNLICENSED",
|
|
@@ -64,16 +64,16 @@
|
|
|
64
64
|
"@semantic-release/changelog": "^6.0.1",
|
|
65
65
|
"@semantic-release/commit-analyzer": "^9.0.2",
|
|
66
66
|
"@semantic-release/git": "^10.0.1",
|
|
67
|
-
"@storybook/addon-actions": "^6.5.
|
|
68
|
-
"@storybook/addon-essentials": "^6.5.
|
|
69
|
-
"@storybook/addon-interactions": "^6.5.
|
|
70
|
-
"@storybook/addon-links": "^6.5.
|
|
71
|
-
"@storybook/addons": "^6.5.
|
|
72
|
-
"@storybook/builder-webpack5": "^6.5.
|
|
73
|
-
"@storybook/manager-webpack5": "^6.5.
|
|
74
|
-
"@storybook/react": "^6.5.
|
|
75
|
-
"@storybook/testing-library": "^0.0.
|
|
76
|
-
"@storybook/theming": "^6.5.
|
|
67
|
+
"@storybook/addon-actions": "^6.5.9",
|
|
68
|
+
"@storybook/addon-essentials": "^6.5.9",
|
|
69
|
+
"@storybook/addon-interactions": "^6.5.9",
|
|
70
|
+
"@storybook/addon-links": "^6.5.9",
|
|
71
|
+
"@storybook/addons": "^6.5.9",
|
|
72
|
+
"@storybook/builder-webpack5": "^6.5.9",
|
|
73
|
+
"@storybook/manager-webpack5": "^6.5.9",
|
|
74
|
+
"@storybook/react": "^6.5.9",
|
|
75
|
+
"@storybook/testing-library": "^0.0.13",
|
|
76
|
+
"@storybook/theming": "^6.5.9",
|
|
77
77
|
"@svgr/cli": "^6.2.1",
|
|
78
78
|
"@svgr/core": "^6.2.1",
|
|
79
79
|
"@types/cheerio": "^0.22.31",
|
|
@@ -157,6 +157,7 @@
|
|
|
157
157
|
},
|
|
158
158
|
"resolutions": {
|
|
159
159
|
"**/ast-types": "npm:@gkz/ast-types",
|
|
160
|
+
"ts-node": "^10.8.0",
|
|
160
161
|
"@types/react": "17.0.40"
|
|
161
162
|
}
|
|
162
163
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const sizes = {
|
|
2
|
+
large: { w: '40', h: '40' },
|
|
3
|
+
medium: { w: '32', h: '32' },
|
|
4
|
+
small: { w: '24', h: '24' },
|
|
5
|
+
};
|
|
6
|
+
const CloseButtonTheme = {
|
|
7
|
+
baseStyle({
|
|
8
|
+
colorScheme,
|
|
9
|
+
size,
|
|
10
|
+
}: {
|
|
11
|
+
colorScheme: 'blue' | 'red' | 'green' | 'yellow' | 'purple' | 'neutral';
|
|
12
|
+
size: 'small' | 'medium' | 'large';
|
|
13
|
+
}) {
|
|
14
|
+
if (colorScheme === 'neutral') {
|
|
15
|
+
return {
|
|
16
|
+
borderRadius: '4',
|
|
17
|
+
bg: 'neutral.100',
|
|
18
|
+
color: 'purple.10',
|
|
19
|
+
_hover: { bg: 'neutral.95' },
|
|
20
|
+
_active: { bg: 'neutral.90' },
|
|
21
|
+
...sizes[size],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
borderRadius: '4',
|
|
26
|
+
bg: `${colorScheme}.95`,
|
|
27
|
+
color: `${colorScheme}.40`,
|
|
28
|
+
_hover: { bg: `${colorScheme}.93` },
|
|
29
|
+
_active: { bg: `${colorScheme}.90` },
|
|
30
|
+
...sizes[size],
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
defaultProps: { colorScheme: 'neutral', size: 'small' },
|
|
34
|
+
};
|
|
35
|
+
export default CloseButtonTheme;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
CloseButton as ChakraCloseButton,
|
|
4
|
+
CloseButtonProps as ChakraCloseButtonProps,
|
|
5
|
+
} from '@chakra-ui/react';
|
|
6
|
+
import CloseButtonTheme from './CloseButton.theme';
|
|
7
|
+
|
|
8
|
+
type ThemeArguments = Parameters<typeof CloseButtonTheme['baseStyle']>[0];
|
|
9
|
+
export interface CloseButtonProps extends ChakraCloseButtonProps {
|
|
10
|
+
size?: ThemeArguments['size'];
|
|
11
|
+
colorScheme: ThemeArguments['colorScheme'];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CloseButton = forwardRef<CloseButtonProps, 'button'>((props, ref) => (
|
|
15
|
+
<ChakraCloseButton ref={ref} {...CloseButtonTheme.defaultProps} {...props} />
|
|
16
|
+
));
|
|
17
|
+
|
|
18
|
+
export default CloseButton;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStoryFn } from '@storybook/react';
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
import Notification, { NotificationText, NotificationTitle } from './Notification';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Notification',
|
|
7
|
+
component: Notification,
|
|
8
|
+
argTypes: {
|
|
9
|
+
title: { type: 'string', defaultValue: 'title' },
|
|
10
|
+
description: { type: 'string', defaultValue: 'description' },
|
|
11
|
+
action: {
|
|
12
|
+
control: 'inline-radio',
|
|
13
|
+
defaultValue: 'unset',
|
|
14
|
+
options: ['unset', 'link', 'action'],
|
|
15
|
+
mapping: {
|
|
16
|
+
unset: undefined,
|
|
17
|
+
link: { label: 'link', href: '#' },
|
|
18
|
+
action: { label: 'action', onClick: action('action') },
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
onClose: {
|
|
22
|
+
control: 'inline-radio',
|
|
23
|
+
options: ['unset', 'action'],
|
|
24
|
+
mapping: {
|
|
25
|
+
unset: undefined,
|
|
26
|
+
action: action('onClose'),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
args: {
|
|
31
|
+
status: 'info',
|
|
32
|
+
},
|
|
33
|
+
} as ComponentMeta<typeof Notification>;
|
|
34
|
+
|
|
35
|
+
export const Default: ComponentStoryFn<typeof Notification> = ({ title, description, ...args }) => (
|
|
36
|
+
<Notification {...args}>
|
|
37
|
+
<NotificationTitle>{title}</NotificationTitle>
|
|
38
|
+
<NotificationText>{description}</NotificationText>
|
|
39
|
+
</Notification>
|
|
40
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const AlertTheme = {
|
|
2
|
+
parts: ['container', 'title', 'icon', 'body'],
|
|
3
|
+
baseStyle({ colorScheme }: { colorScheme: 'blue' | 'red' | 'green' | 'yellow' | 'purple' }) {
|
|
4
|
+
return {
|
|
5
|
+
container: {
|
|
6
|
+
display: 'flex',
|
|
7
|
+
alignItems: 'start',
|
|
8
|
+
gap: '8',
|
|
9
|
+
borderRadius: '8',
|
|
10
|
+
borderWidth: '1px',
|
|
11
|
+
padding: '12',
|
|
12
|
+
fontSize: '3',
|
|
13
|
+
lineHeight: '3',
|
|
14
|
+
bg: `${colorScheme}.95`,
|
|
15
|
+
color: `${colorScheme}.40`,
|
|
16
|
+
borderColor: `${colorScheme}.80`,
|
|
17
|
+
},
|
|
18
|
+
title: {
|
|
19
|
+
fontWeight: 'bold',
|
|
20
|
+
},
|
|
21
|
+
icon: {
|
|
22
|
+
w: 24,
|
|
23
|
+
h: 24,
|
|
24
|
+
marginEnd: 8,
|
|
25
|
+
},
|
|
26
|
+
body: { display: 'flex', flexDirection: 'column' },
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
defaultProps: {
|
|
30
|
+
colorScheme: 'blue',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export default AlertTheme;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Alert as ChakraAlert,
|
|
4
|
+
AlertTitle as NotificationTitle,
|
|
5
|
+
AlertProps,
|
|
6
|
+
forwardRef,
|
|
7
|
+
AlertDescription as NotificationText,
|
|
8
|
+
Spinner,
|
|
9
|
+
chakra,
|
|
10
|
+
} from '@chakra-ui/react';
|
|
11
|
+
|
|
12
|
+
import Box from '../Box/Box';
|
|
13
|
+
import CloseButton from '../CloseButton/CloseButton';
|
|
14
|
+
import ColorButton, { ColorButtonProps } from '../ColorButton/ColorButton';
|
|
15
|
+
import Icon from '../Icon/Icon';
|
|
16
|
+
|
|
17
|
+
const STATUSES = {
|
|
18
|
+
info: { colorScheme: 'blue', icon: <Icon flexShrink={0} name="Info" /> },
|
|
19
|
+
error: { colorScheme: 'red', icon: <Icon flexShrink={0} name="ErrorGeneral" /> },
|
|
20
|
+
success: { colorScheme: 'green', icon: <Icon flexShrink={0} name="Tick" /> },
|
|
21
|
+
warning: { colorScheme: 'yellow', icon: <Icon flexShrink={0} name="Warning" /> },
|
|
22
|
+
progress: {
|
|
23
|
+
colorScheme: 'purple',
|
|
24
|
+
icon: (
|
|
25
|
+
<chakra.span w="24" h="24" p="2" flexShrink={0}>
|
|
26
|
+
<Spinner w="100%" h="100%" />
|
|
27
|
+
</chakra.span>
|
|
28
|
+
),
|
|
29
|
+
},
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export type ActionProps = { label: string; href?: string; onClick?: () => void } & Omit<
|
|
33
|
+
ColorButtonProps,
|
|
34
|
+
'as' | 'onClick' | 'colorScheme'
|
|
35
|
+
>;
|
|
36
|
+
export interface NotificationProps extends Omit<AlertProps, 'status' | 'colorScheme' | 'onClose'> {
|
|
37
|
+
status: keyof typeof STATUSES;
|
|
38
|
+
onClose?: () => void;
|
|
39
|
+
action?: ActionProps;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ActionContext = createContext<{ colorScheme: ColorButtonProps['colorScheme'] }>({ colorScheme: 'blue' });
|
|
43
|
+
|
|
44
|
+
const NotificationAction = ({ label, href, ...rest }: ActionProps) => {
|
|
45
|
+
const actionContext = useContext(ActionContext);
|
|
46
|
+
return (
|
|
47
|
+
<ColorButton
|
|
48
|
+
flexGrow={0}
|
|
49
|
+
flexShrink={1}
|
|
50
|
+
as={(href ? 'a' : 'button') as any}
|
|
51
|
+
href={href}
|
|
52
|
+
{...actionContext}
|
|
53
|
+
{...rest}
|
|
54
|
+
>
|
|
55
|
+
{label}
|
|
56
|
+
</ColorButton>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const Notification = forwardRef<NotificationProps, 'div'>((props, ref) => {
|
|
61
|
+
const { status, action, children, onClose, ...rest } = props;
|
|
62
|
+
const { colorScheme, icon } = STATUSES[status];
|
|
63
|
+
let actionButton;
|
|
64
|
+
if (action) {
|
|
65
|
+
actionButton = <NotificationAction marginRight="12" {...action} alignSelf="center" />;
|
|
66
|
+
}
|
|
67
|
+
const actionContext = useMemo(() => ({ colorScheme }), [colorScheme]);
|
|
68
|
+
return (
|
|
69
|
+
<ChakraAlert ref={ref} {...rest} colorScheme={colorScheme}>
|
|
70
|
+
<ActionContext.Provider value={actionContext}>
|
|
71
|
+
{icon}
|
|
72
|
+
<Box wordBreak="break-word" display="flex" flexDirection="column" flexGrow={1}>
|
|
73
|
+
{children}
|
|
74
|
+
</Box>
|
|
75
|
+
{actionButton}
|
|
76
|
+
{onClose && (
|
|
77
|
+
<CloseButton flexShrink={0} colorScheme={colorScheme} onClick={onClose}>
|
|
78
|
+
<Icon name="CloseSmall" />
|
|
79
|
+
</CloseButton>
|
|
80
|
+
)}
|
|
81
|
+
</ActionContext.Provider>
|
|
82
|
+
</ChakraAlert>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export { NotificationTitle, NotificationText, NotificationAction };
|
|
87
|
+
export default Notification;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { Meta } from '@storybook/react';
|
|
3
|
+
import NotificationStories from '../Notification/Notification.stories';
|
|
4
|
+
import useToast, { ToastOptions } from './Toast';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/Toast',
|
|
8
|
+
argTypes: {
|
|
9
|
+
isClosable: { type: 'boolean', defaultValue: true },
|
|
10
|
+
showTimestamp: { type: 'boolean', defaultValue: true },
|
|
11
|
+
action: NotificationStories.argTypes?.action,
|
|
12
|
+
title: { type: 'string', defaultValue: 'the title' },
|
|
13
|
+
description: { type: 'string', defaultValue: 'some description' },
|
|
14
|
+
duration: { control: { type: 'range', min: 0, max: 10000, step: 1000 } },
|
|
15
|
+
status: {
|
|
16
|
+
control: 'inline-radio',
|
|
17
|
+
defaultValue: 'success',
|
|
18
|
+
options: ['success', 'info', 'error', 'warning', 'progress'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
} as Meta;
|
|
22
|
+
|
|
23
|
+
export const Default = ({ duration, ...props }: ToastOptions) => {
|
|
24
|
+
const toast = useToast();
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
toast({ duration: duration || null, ...props });
|
|
27
|
+
}, [duration, props]);
|
|
28
|
+
|
|
29
|
+
return <div />;
|
|
30
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useToast as useChakraToast, ToastOptions as ChakraToastOptions } from '@chakra-ui/react';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import Notification, {
|
|
4
|
+
ActionProps,
|
|
5
|
+
NotificationAction,
|
|
6
|
+
NotificationProps,
|
|
7
|
+
NotificationText,
|
|
8
|
+
NotificationTitle,
|
|
9
|
+
} from '../Notification/Notification';
|
|
10
|
+
|
|
11
|
+
export interface ToastOptions {
|
|
12
|
+
title: string;
|
|
13
|
+
description: React.ReactNode;
|
|
14
|
+
status: NotificationProps['status'];
|
|
15
|
+
action?: ActionProps;
|
|
16
|
+
duration?: ChakraToastOptions['duration'];
|
|
17
|
+
position?: ChakraToastOptions['position'];
|
|
18
|
+
isClosable?: boolean;
|
|
19
|
+
showTimestamp?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const useToast = () => {
|
|
23
|
+
const toast = useChakraToast();
|
|
24
|
+
return (opts: ToastOptions) => {
|
|
25
|
+
let timestamp: string | undefined;
|
|
26
|
+
if (opts.showTimestamp) {
|
|
27
|
+
timestamp = DateTime.now().toFormat('hh:mm:ssa');
|
|
28
|
+
}
|
|
29
|
+
toast({
|
|
30
|
+
isClosable: opts.isClosable,
|
|
31
|
+
duration: opts.duration,
|
|
32
|
+
position: opts.position,
|
|
33
|
+
render: ({ onClose }) => (
|
|
34
|
+
<Notification
|
|
35
|
+
boxShadow="large"
|
|
36
|
+
maxW="437px"
|
|
37
|
+
status={opts.status}
|
|
38
|
+
onClose={opts.isClosable ? onClose : undefined}
|
|
39
|
+
>
|
|
40
|
+
<NotificationTitle>{opts.title}</NotificationTitle>
|
|
41
|
+
<NotificationText>{opts.description}</NotificationText>
|
|
42
|
+
{!opts.action && timestamp && <NotificationText marginTop="8">{timestamp}</NotificationText>}
|
|
43
|
+
{opts.action && <NotificationAction alignSelf="start" marginTop="8" marginBottom="4" {...opts.action} />}
|
|
44
|
+
</Notification>
|
|
45
|
+
),
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default useToast;
|
package/src/index.ts
CHANGED
|
@@ -80,3 +80,5 @@ export { default as MenuItem } from './Components/Menu/MenuItem';
|
|
|
80
80
|
|
|
81
81
|
export type { MenuListProps } from './Components/Menu/MenuList';
|
|
82
82
|
export { default as MenuList } from './Components/Menu/MenuList';
|
|
83
|
+
|
|
84
|
+
export { default as useToast } from './Components/Toast/Toast';
|
package/src/theme.ts
CHANGED
|
@@ -8,7 +8,9 @@ import Menu from './Components/Menu/Menu.theme';
|
|
|
8
8
|
import Select from './Components/Select/Select.theme';
|
|
9
9
|
import Tabs from './Components/Tabs/Tabs.theme';
|
|
10
10
|
import Text from './Components/Text/Text.theme';
|
|
11
|
+
import Notification from './Components/Notification/Notification.theme';
|
|
11
12
|
import Tooltip from './Components/Tooltip/Tooltip.theme';
|
|
13
|
+
import CloseButton from './Components/CloseButton/CloseButton.theme';
|
|
12
14
|
|
|
13
15
|
import colors from './Foundations/Colors/Colors';
|
|
14
16
|
import radii from './Foundations/Radii/Radii';
|
|
@@ -61,6 +63,8 @@ const theme = {
|
|
|
61
63
|
Tabs,
|
|
62
64
|
Text,
|
|
63
65
|
Tooltip,
|
|
66
|
+
Alert: Notification,
|
|
67
|
+
CloseButton,
|
|
64
68
|
},
|
|
65
69
|
};
|
|
66
70
|
|