@bitrise/bitkit 10.17.0-alpha-export-new-notification.1 → 10.18.0-alpha-chakra.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitrise/bitkit",
3
3
  "description": "Bitrise React component library",
4
- "version": "10.17.0-alpha-export-new-notification.1",
4
+ "version": "10.18.0-alpha-chakra.1",
5
5
  "repository": "git@github.com:bitrise-io/bitkit.git",
6
6
  "main": "src/index.ts",
7
7
  "license": "UNLICENSED",
@@ -56,5 +56,8 @@ export const DefaultVariant: ComponentStory<typeof Accordion> = (props) => (
56
56
  Content - you can use any style prop on AccordionItem
57
57
  </AccordionItem>
58
58
  <AccordionItem buttonContent={<ButtonContentElement title="Without children" />} id="third" />
59
+ <AccordionItem buttonContent="Fourth, enabled element" fontSize="2" id="fourth">
60
+ Fourth, enabled element
61
+ </AccordionItem>
59
62
  </Accordion>
60
63
  );
@@ -1,5 +1,22 @@
1
1
  import type { ComponentStyleConfig } from '@chakra-ui/theme';
2
2
 
3
+ const buttonStyle = {
4
+ display: 'flex',
5
+ alignItems: 'center',
6
+ justifyContent: 'space-between',
7
+ width: '100%',
8
+ padding: '16',
9
+ borderBottom: '1px solid',
10
+ borderColor: 'neutral.93',
11
+ borderRadius: '8',
12
+ };
13
+
14
+ const iconStyle = {
15
+ width: '24',
16
+ height: '24',
17
+ marginLeft: '16',
18
+ };
19
+
3
20
  const AccordionTheme: ComponentStyleConfig = {
4
21
  baseStyle: ({ colorScheme }) => ({
5
22
  item: {
@@ -9,28 +26,29 @@ const AccordionTheme: ComponentStyleConfig = {
9
26
  boxShadow: 'small',
10
27
  marginBottom: '16',
11
28
  },
12
- button: {
13
- display: 'flex',
14
- alignItems: 'center',
15
- justifyContent: 'space-between',
16
- width: '100%',
17
- padding: '16',
29
+ enabledButton: {
30
+ ...buttonStyle,
18
31
  background: colorScheme === 'gray' ? 'neutral.95' : 'neutral.100',
19
- borderBottom: '1px solid',
20
- borderColor: 'neutral.93',
21
- borderRadius: '8',
22
- '&[type="button"]:hover': {
32
+ _hover: {
23
33
  background: 'purple.95',
24
34
  },
25
- '&[aria-expanded="true"]': {
35
+ _expanded: {
26
36
  borderBottomLeftRadius: '0',
27
37
  borderBottomRightRadius: '0',
28
38
  },
29
39
  },
30
- icon: {
31
- width: '24',
32
- height: '24',
33
- marginLeft: '16',
40
+ disabledButton: {
41
+ ...buttonStyle,
42
+ background: colorScheme === 'gray' ? 'neutral.95' : 'neutral.100',
43
+ cursor: 'default',
44
+ },
45
+ enabledIcon: {
46
+ ...iconStyle,
47
+ },
48
+ disabledIcon: {
49
+ ...iconStyle,
50
+ opacity: '0.4',
51
+ transform: 'none',
34
52
  },
35
53
  panel: {
36
54
  padding: '16',
@@ -8,7 +8,6 @@ import {
8
8
  AccordionIcon,
9
9
  useAccordionStyles,
10
10
  } from '@chakra-ui/react';
11
- import Box from '../Box/Box';
12
11
  import Text from '../Text/Text';
13
12
 
14
13
  export interface AccordionItemProps extends AccordionPanelProps {
@@ -21,14 +20,12 @@ const AccordionItem = (props: AccordionItemProps) => {
21
20
  const { buttonContent, children, id, ...rest } = props;
22
21
  const styles = useAccordionStyles();
23
22
 
24
- const ButtonComponent = children ? AccordionButton : Box;
25
-
26
23
  return (
27
24
  <ChakraAccordionItem sx={styles.item} id={id}>
28
- <ButtonComponent sx={styles.button}>
25
+ <AccordionButton sx={children ? styles.enabledButton : styles.disabledButton}>
29
26
  {isValidElement(buttonContent) ? buttonContent : <Text as="span">{buttonContent}</Text>}
30
- <AccordionIcon opacity={children ? 1 : 0.4} />
31
- </ButtonComponent>
27
+ <AccordionIcon sx={children ? styles.enabledIcon : styles.disabledIcon} />
28
+ </AccordionButton>
32
29
  {!!children && <AccordionPanel {...rest}>{children}</AccordionPanel>}
33
30
  </ChakraAccordionItem>
34
31
  );
@@ -1,13 +1,13 @@
1
1
  import { ComponentMeta, ComponentStoryFn } from '@storybook/react';
2
2
  import { action } from '@storybook/addon-actions';
3
- import Notification, { NotificationText, NotificationTitle } from './Notification';
3
+ import Link from '../Link/Link';
4
+ import Notification from './Notification';
4
5
 
5
6
  export default {
6
7
  title: 'Components/Notification',
7
8
  component: Notification,
8
9
  argTypes: {
9
- title: { type: 'string', defaultValue: 'title' },
10
- description: { type: 'string', defaultValue: 'description' },
10
+ children: { type: 'string', defaultValue: 'text' },
11
11
  action: {
12
12
  control: 'inline-radio',
13
13
  options: ['unset', 'link', 'action'],
@@ -31,12 +31,7 @@ export default {
31
31
  },
32
32
  } as ComponentMeta<typeof Notification>;
33
33
 
34
- const Template: ComponentStoryFn<typeof Notification> = ({ title, description, ...props }) => (
35
- <Notification {...props}>
36
- <NotificationTitle>{title}</NotificationTitle>
37
- <NotificationText>{description}</NotificationText>
38
- </Notification>
39
- );
34
+ const Template: ComponentStoryFn<typeof Notification> = (props) => <Notification {...props} />;
40
35
 
41
36
  export const Default: ComponentStoryFn<typeof Notification> = (props) => <Template {...props} />;
42
37
  Default.args = {
@@ -64,3 +59,26 @@ WithAction.args = {
64
59
  label: 'Upgrade',
65
60
  },
66
61
  };
62
+
63
+ export const WithActionAfterContent: ComponentStoryFn<typeof Notification> = (props) => <Template {...props} />;
64
+ WithActionAfterContent.storyName = 'With action after content';
65
+ WithActionAfterContent.args = {
66
+ action: {
67
+ label: 'Upgrade',
68
+ placement: 'after-content',
69
+ },
70
+ };
71
+
72
+ export const WithLink: ComponentStoryFn<typeof Notification> = (props) => <Template {...props} />;
73
+ WithLink.storyName = 'With link';
74
+ WithLink.args = {
75
+ children: (
76
+ <>
77
+ Unable to send build status back to your git host. Please check{' '}
78
+ <Link href="#/" isUnderlined>
79
+ our guide
80
+ </Link>
81
+ .
82
+ </>
83
+ ),
84
+ };
@@ -1,13 +1,5 @@
1
1
  import { cloneElement, createContext, ReactElement, 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';
2
+ import { Alert as ChakraAlert, AlertProps, forwardRef, Spinner } from '@chakra-ui/react';
11
3
 
12
4
  import { ColorScheme } from '../../Foundations/Colors/Colors';
13
5
  import Box from '../Box/Box';
@@ -25,9 +17,9 @@ const STATUSES: Record<NotificationStatus, { colorScheme: ColorScheme; defaultIc
25
17
  progress: {
26
18
  colorScheme: 'purple',
27
19
  defaultIcon: (
28
- <chakra.span w="24" h="24" p="2">
29
- <Spinner w="100" h="100" />
30
- </chakra.span>
20
+ <Box width={24} height={24} padding={2}>
21
+ <Spinner width={20} height={20} />
22
+ </Box>
31
23
  ),
32
24
  },
33
25
  } as const;
@@ -36,6 +28,7 @@ export type ActionProps = {
36
28
  label: string;
37
29
  href?: string;
38
30
  onClick?: () => void;
31
+ placement?: 'end' | 'after-content';
39
32
  } & Omit<ColorButtonProps, 'as' | 'onClick' | 'colorScheme'>;
40
33
  export interface NotificationProps extends Omit<AlertProps, 'status' | 'colorScheme' | 'onClose'> {
41
34
  status: NotificationStatus;
@@ -70,6 +63,7 @@ const Notification = forwardRef<NotificationProps, 'div'>((props, ref) => {
70
63
  const { colorScheme, defaultIcon } = STATUSES[status];
71
64
  const icon = iconName ? <Icon name={iconName} /> : defaultIcon;
72
65
  let actionButton;
66
+ const actionPlacement = action?.placement ?? 'end';
73
67
  if (action) {
74
68
  actionButton = <NotificationAction marginRight="12" {...action} alignSelf="center" />;
75
69
  }
@@ -81,12 +75,18 @@ const Notification = forwardRef<NotificationProps, 'div'>((props, ref) => {
81
75
  <ChakraAlert ref={ref} {...rest} colorScheme={colorScheme}>
82
76
  <ActionContext.Provider value={actionContext}>
83
77
  {showIcon && cloneElement(icon, { flexShrink: 0, marginTop })}
84
- <Box wordBreak="break-word" display="flex" flexDirection="column" flexGrow={1} marginTop={marginTop}>
78
+ <Box wordBreak="break-word" flexGrow={actionPlacement === 'end' ? 1 : undefined} marginTop={marginTop}>
85
79
  {children}
86
80
  </Box>
87
81
  {actionButton}
88
82
  {onClose && (
89
- <CloseButton flexShrink={0} colorScheme={colorScheme} onClick={onClose}>
83
+ <CloseButton
84
+ flexShrink={0}
85
+ marginLeft="auto"
86
+ marginTop={marginTop}
87
+ colorScheme={colorScheme}
88
+ onClick={onClose}
89
+ >
90
90
  <Icon name="CloseSmall" />
91
91
  </CloseButton>
92
92
  )}
@@ -95,5 +95,5 @@ const Notification = forwardRef<NotificationProps, 'div'>((props, ref) => {
95
95
  );
96
96
  });
97
97
 
98
- export { NotificationTitle, NotificationText, NotificationAction };
98
+ export { NotificationAction };
99
99
  export default Notification;
@@ -1,4 +1,4 @@
1
- import React, { isValidElement, ReactElement, useEffect, useState } from 'react';
1
+ import React, { isValidElement, ReactElement, useState } from 'react';
2
2
  import { Tabs as ChakraTabs, TabsProps as ChakraTabsProps, forwardRef } from '@chakra-ui/react';
3
3
  import { useHistory } from '../../hooks';
4
4
 
@@ -15,6 +15,25 @@ const getTabIds = (props: TabsProps): string[] => {
15
15
  return tabs.filter((item) => isValidElement(item)).map((item) => item.props.id);
16
16
  };
17
17
 
18
+ const getTabIndexFromSearchParams = (tabIds: string[], defaultIndex?: number) => {
19
+ if (typeof window === 'undefined') {
20
+ return undefined;
21
+ }
22
+
23
+ const searchParams = new URLSearchParams(window.location.search);
24
+ const tabName = searchParams.get('tab');
25
+ if (!tabName) {
26
+ return undefined;
27
+ }
28
+
29
+ const index = tabIds.indexOf(tabName);
30
+ if (index === -1) {
31
+ return defaultIndex;
32
+ }
33
+
34
+ return index;
35
+ };
36
+
18
37
  /**
19
38
  * An accessible tabs component that provides keyboard interactions and ARIA attributes described in the WAI-ARIA Tabs Design Pattern.
20
39
  */
@@ -23,21 +42,16 @@ const Tabs = forwardRef<TabsProps, 'div'>((props, ref) => {
23
42
  const tabIds = getTabIds(props);
24
43
  const defaultIndex = tabIds.indexOf(defaultTab) > -1 ? tabIds.indexOf(defaultTab) : 0;
25
44
 
26
- const { searchParams, replace } = useHistory();
27
- const [actualIndex, setActualIndex] = useState(defaultIndex);
28
-
29
- useEffect(() => {
30
- if (withHistory && searchParams.get('tab')) {
31
- const tabName = searchParams.get('tab') || '';
32
- const index = tabIds.indexOf(tabName) > -1 ? tabIds.indexOf(tabName) : defaultIndex;
33
- setActualIndex(index);
34
- }
35
- }, []);
45
+ const { replace } = useHistory();
46
+ const [actualIndex, setActualIndex] = useState(
47
+ withHistory ? getTabIndexFromSearchParams(tabIds, defaultIndex) : defaultIndex,
48
+ );
36
49
 
37
50
  const onTabChange = (index: number) => {
38
51
  const tabId = tabIds[index];
39
52
  setActualIndex(index);
40
53
  if (withHistory) {
54
+ const searchParams = new URLSearchParams(window.location.search);
41
55
  if (tabId) {
42
56
  searchParams.set('tab', tabId);
43
57
  } else {
@@ -1,12 +1,7 @@
1
- import { useToast as useChakraToast, UseToastOptions } from '@chakra-ui/react';
1
+ import { useToast as useChakraToast, UseToastOptions, AlertTitle, AlertDescription } from '@chakra-ui/react';
2
2
  import { DateTime } from 'luxon';
3
- import Notification, {
4
- ActionProps,
5
- NotificationAction,
6
- NotificationProps,
7
- NotificationText,
8
- NotificationTitle,
9
- } from '../Notification/Notification';
3
+ import Box from '../Box/Box';
4
+ import Notification, { ActionProps, NotificationAction, NotificationProps } from '../Notification/Notification';
10
5
 
11
6
  export interface ToastOptions {
12
7
  title: string;
@@ -37,10 +32,12 @@ const useToast = () => {
37
32
  status={opts.status}
38
33
  onClose={opts.isClosable ? onClose : undefined}
39
34
  >
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} />}
35
+ <Box display="flex" flexDirection="column">
36
+ <AlertTitle>{opts.title}</AlertTitle>
37
+ <AlertDescription>{opts.description}</AlertDescription>
38
+ {!opts.action && timestamp && <AlertDescription marginTop="8">{timestamp}</AlertDescription>}
39
+ {opts.action && <NotificationAction alignSelf="start" marginTop="8" marginBottom="4" {...opts.action} />}
40
+ </Box>
44
41
  </Notification>
45
42
  ),
46
43
  });
@@ -0,0 +1,18 @@
1
+ import { ComponentMeta } from '@storybook/react';
2
+ import Toggle from './Toggle';
3
+
4
+ export default {
5
+ title: 'Components/Toggle',
6
+ component: Toggle,
7
+ } as ComponentMeta<typeof Toggle>;
8
+
9
+ export const WithProps = {
10
+ args: {
11
+ children: 'Toggle the toggle',
12
+ defaultChecked: false,
13
+ helpherText:
14
+ 'Inline help. Maecenas a turpis tortor. Nunc vitae libero tempor, ullamcorper purus quis, mattis tellus.',
15
+ isDisabled: false,
16
+ isLoading: false,
17
+ },
18
+ };
@@ -0,0 +1,77 @@
1
+ import type { ComponentStyleConfig } from '@chakra-ui/theme';
2
+
3
+ const ToggleTheme: ComponentStyleConfig = {
4
+ baseStyle: {
5
+ formControl: {
6
+ display: 'flex',
7
+ alignItems: 'center',
8
+ flexWrap: 'wrap',
9
+ gap: '8',
10
+ },
11
+ track: {
12
+ boxSizing: 'border-box',
13
+ width: '48',
14
+ height: '24',
15
+ padding: '0.125rem',
16
+ backgroundColor: 'neutral.50',
17
+ borderRadius: '12',
18
+ transition: '100ms',
19
+ _disabled: {
20
+ backgroundColor: 'neutral.93',
21
+ cursor: 'not-allowed',
22
+ },
23
+ _checked: {
24
+ backgroundColor: 'turquoise.70',
25
+ _disabled: {
26
+ backgroundColor: 'turquoise.80',
27
+ },
28
+ },
29
+ _before: {
30
+ content: '""',
31
+ backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10.213 13.915 17.234 7l1.49 1.49L10.212 17 5 11.68l1.49-1.489 3.723 3.724Z' fill='white' /%3E%3C/svg%3E")`,
32
+ backgroundPositionX: '0.125rem',
33
+ position: 'absolute',
34
+ left: 0,
35
+ right: '50%',
36
+ top: 0,
37
+ bottom: 0,
38
+ },
39
+ _after: {
40
+ content: '""',
41
+ backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12.01 10.608 16.618 6l1.402 1.402-4.608 4.608 4.608 4.608-1.402 1.402-4.608-4.608-4.608 4.608L6 16.618l4.608-4.608L6 7.402 7.402 6l4.608 4.608Z' fill='white' /%3E%3C/svg%3E")`,
42
+ backgroundPositionX: '-0.125rem',
43
+ position: 'absolute',
44
+ left: '50%',
45
+ right: 0,
46
+ top: 0,
47
+ bottom: 0,
48
+ },
49
+ },
50
+ thumb: {
51
+ position: 'relative',
52
+ zIndex: '1',
53
+ width: '1.25rem',
54
+ height: '1.25rem',
55
+ borderRadius: '24',
56
+ bgGradient: 'linear(to-b, neutral.93 3.43%, neutral.100 100%)',
57
+ transition: '100ms',
58
+ _checked: {
59
+ transform: 'translate(24px)',
60
+ },
61
+ },
62
+ spinner: {
63
+ width: '16',
64
+ height: '16',
65
+ color: 'neutral.70',
66
+ },
67
+ helpherText: {
68
+ fontSize: '2',
69
+ lineHeight: '2',
70
+ width: '100%',
71
+ marginTop: '-4px',
72
+ color: 'neutral.40',
73
+ },
74
+ },
75
+ };
76
+
77
+ export default ToggleTheme;
@@ -0,0 +1,51 @@
1
+ import { ReactNode } from 'react';
2
+ import {
3
+ FormControl,
4
+ FormControlProps,
5
+ FormLabel,
6
+ Spinner,
7
+ Switch,
8
+ SwitchProps,
9
+ forwardRef,
10
+ useMultiStyleConfig,
11
+ } from '@chakra-ui/react';
12
+ import Text from '../Text/Text';
13
+
14
+ export interface ToggleProps extends FormControlProps {
15
+ children?: ReactNode;
16
+ defaultChecked?: SwitchProps['defaultChecked'];
17
+ id?: SwitchProps['id'];
18
+ isChecked?: SwitchProps['isChecked'];
19
+ isDisabled?: SwitchProps['isDisabled'];
20
+ isLoading?: boolean;
21
+ helpherText?: string;
22
+ onChange?: SwitchProps['onChange'];
23
+ value?: SwitchProps['value'];
24
+ }
25
+
26
+ /**
27
+ * The Toggle component is used as an alternative for the checkbox component.
28
+ */
29
+ const Toggle = forwardRef<ToggleProps, 'div'>((props, ref) => {
30
+ const { children, defaultChecked, helpherText, id, isChecked, isDisabled, isLoading, onChange, value, ...rest } =
31
+ props;
32
+ const switchProps = {
33
+ defaultChecked,
34
+ id,
35
+ isChecked,
36
+ isDisabled: isDisabled || isLoading,
37
+ onChange,
38
+ value,
39
+ };
40
+ const css = useMultiStyleConfig('Switch');
41
+ return (
42
+ <FormControl sx={css.formControl} {...rest} ref={ref}>
43
+ <Switch {...switchProps} />
44
+ <FormLabel htmlFor={id}>{children}</FormLabel>
45
+ {isLoading && <Spinner sx={css.spinner} />}
46
+ {helpherText && <Text sx={css.helpherText}>{helpherText}</Text>}
47
+ </FormControl>
48
+ );
49
+ });
50
+
51
+ export default Toggle;
package/src/index.ts CHANGED
@@ -192,3 +192,6 @@ export { default as Thead } from './Components/Table/Thead';
192
192
 
193
193
  export type { TableRowProps } from './Components/Table/Tr';
194
194
  export { default as Tr } from './Components/Table/Tr';
195
+
196
+ export type { ToggleProps } from './Components/Toggle/Toggle';
197
+ export { default as Toggle } from './Components/Toggle/Toggle';
package/src/old.ts CHANGED
@@ -94,9 +94,6 @@ export { default as OldTableRow } from './Old/Table/TableRow';
94
94
  export type { Props as TextareaProps } from './Old/Textarea/Textarea';
95
95
  export { default as Textarea } from './Old/Textarea/Textarea';
96
96
 
97
- export type { Props as ToggleProps } from './Old/Toggle/Toggle';
98
- export { default as Toggle } from './Old/Toggle/Toggle';
99
-
100
97
  export type { Props as VisibilityProps } from './Old/Visibility/Visibility';
101
98
  export { default as Visibility } from './Old/Visibility/Visibility';
102
99
 
package/src/theme.ts CHANGED
@@ -23,6 +23,7 @@ import Alert from './Foundations/Themes/Alert.theme';
23
23
  import Tooltip from './Components/Tooltip/Tooltip.theme';
24
24
  import CloseButton from './Components/CloseButton/CloseButton.theme';
25
25
  import Popover from './Components/Popover/Popover.theme';
26
+ import Toggle from './Components/Toggle/Toggle.theme';
26
27
 
27
28
  import breakpoints from './Foundations/Breakpoints/Breakpoints';
28
29
  import colors from './Foundations/Colors/Colors';
@@ -93,6 +94,7 @@ const theme = {
93
94
  CloseButton,
94
95
  Input,
95
96
  Popover,
97
+ Switch: Toggle,
96
98
  },
97
99
  };
98
100