@bitrise/bitkit 9.16.5 → 9.17.0-alpha-chakra.3

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": "9.16.5",
4
+ "version": "9.17.0-alpha-chakra.3",
5
5
  "repository": "git@github.com:bitrise-io/bitkit.git",
6
6
  "main": "src/index.ts",
7
7
  "license": "UNLICENSED",
@@ -55,7 +55,7 @@
55
55
  "@babel/core": "^7.18.2",
56
56
  "@bitrise/eslint-plugin": "^2.1.0",
57
57
  "@chakra-ui/cli": "^1.9.0",
58
- "@chakra-ui/storybook-addon": "^3.0.2",
58
+ "@chakra-ui/storybook-addon": "^1.0.3",
59
59
  "@commitlint/cli": "^16.3.0",
60
60
  "@commitlint/config-conventional": "^16.2.4",
61
61
  "@google-cloud/storage": "^5.19.4",
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import {
3
+ Badge as ChakraBadge,
4
+ BadgeProps as ChakraBadgeProps,
5
+ Button,
6
+ Tab as ChakraTab,
7
+ TabProps as ChakraTabProps,
8
+ forwardRef,
9
+ useMultiStyleConfig,
10
+ useTab,
11
+ } from '@chakra-ui/react';
12
+ import Icon from '../../Old/Icon/Icon';
13
+ import { TypeIconName } from '../../Old/Icon/tsx';
14
+
15
+ // TODO: separated component
16
+ interface BadgeProps extends ChakraBadgeProps {
17
+ backgroundColor?: ChakraBadgeProps['backgroundColor'];
18
+ children?: number | string;
19
+ color?: ChakraBadgeProps['color'];
20
+ }
21
+
22
+ const Badge = (props: BadgeProps) => {
23
+ const properties: ChakraBadgeProps = {
24
+ ...props,
25
+ borderRadius: '4',
26
+ fontSize: '1',
27
+ lineHeight: '1',
28
+ paddingY: '3px',
29
+ paddingX: '8',
30
+ textTransform: 'uppercase',
31
+ };
32
+ return <ChakraBadge {...properties} />;
33
+ };
34
+
35
+ export interface TabProps extends ChakraTabProps {
36
+ badge?: BadgeProps;
37
+ leftIconName?: TypeIconName;
38
+ isDisabled?: boolean;
39
+ rightIconName?: TypeIconName;
40
+ }
41
+
42
+ const CustomTab = forwardRef((props, ref) => {
43
+ const { badge, leftIconName, rightIconName, ...rest } = props;
44
+ const tabProps = useTab({ ...rest, ref });
45
+ const styles = useMultiStyleConfig('Tabs', tabProps);
46
+
47
+ return (
48
+ <Button __css={styles.tab} {...tabProps}>
49
+ {leftIconName && <Icon name={leftIconName} />}
50
+ <span>{tabProps.children}</span>
51
+ {badge?.children && <Badge {...badge} />}
52
+ {rightIconName && <Icon name={rightIconName} />}
53
+ </Button>
54
+ );
55
+ });
56
+
57
+ const Tab = forwardRef<TabProps, 'div'>((props, ref) => {
58
+ const { badge, leftIconName, rightIconName, ...rest } = props;
59
+ const properties = rest;
60
+ if (badge?.children || leftIconName || rightIconName) {
61
+ return <CustomTab {...props} />;
62
+ }
63
+ return <ChakraTab {...properties} ref={ref} />;
64
+ });
65
+
66
+ export default Tab;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { TabList as ChakraTabList, TabListProps, forwardRef } from '@chakra-ui/react';
3
+
4
+ const TabList = forwardRef<TabListProps, 'div'>((props, ref) => {
5
+ return <ChakraTabList {...props} ref={ref} />;
6
+ });
7
+
8
+ export type { TabListProps };
9
+
10
+ export default TabList;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { TabPanel as ChakraTabPanel, TabPanelProps, forwardRef } from '@chakra-ui/react';
3
+
4
+ const TabPanel = forwardRef<TabPanelProps, 'div'>((props, ref) => {
5
+ return <ChakraTabPanel {...props} ref={ref} />;
6
+ });
7
+
8
+ export type { TabPanelProps };
9
+
10
+ export default TabPanel;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { TabPanels as ChakraTabPanels, TabPanelsProps, forwardRef } from '@chakra-ui/react';
3
+
4
+ const TabPanels = forwardRef<TabPanelsProps, 'div'>((props, ref) => {
5
+ return <ChakraTabPanels {...props} ref={ref} />;
6
+ });
7
+
8
+ export type { TabPanelsProps };
9
+
10
+ export default TabPanels;
@@ -0,0 +1,52 @@
1
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
2
+ import Tabs from './Tabs';
3
+ import TabList from './TabList';
4
+ import Tab from './Tab';
5
+ import TabPanels from './TabPanels';
6
+ import TabPanel from './TabPanel';
7
+
8
+ export default {
9
+ title: 'Components/Tabs',
10
+ component: Tabs,
11
+ subcomponents: { Tab },
12
+ } as ComponentMeta<typeof Tabs>;
13
+
14
+ const badge = {
15
+ backgroundColor: 'yellow.80',
16
+ children: 'new',
17
+ color: 'neutral.10',
18
+ };
19
+
20
+ export const WithDefaults: ComponentStory<typeof Tabs> = () => {
21
+ return (
22
+ <Tabs defaultIndex={1} variant="unstyled" withHistory>
23
+ <TabList>
24
+ <Tab id="default">Default</Tab>
25
+ <Tab id="selected-as-default">Selected as default</Tab>
26
+ <Tab leftIconName="Bell">With left icon</Tab>
27
+ <Tab id="with-badge" badge={badge}>
28
+ With badge
29
+ </Tab>
30
+ <Tab isDisabled>Disabled</Tab>
31
+ <Tab id="with-right-icon" rightIconName="ArrowForward">
32
+ With right icon
33
+ </Tab>
34
+ </TabList>
35
+
36
+ <TabPanels>
37
+ <TabPanel paddingTop="16">
38
+ <p>
39
+ You can add any style prop to <code>TabPanel</code>, like padding.
40
+ <br />
41
+ But doesn't have any default style.
42
+ </p>
43
+ </TabPanel>
44
+ <TabPanel paddingTop="16">You can use defaultIndex for this</TabPanel>
45
+ <TabPanel paddingTop="16">You can add icon to tab</TabPanel>
46
+ <TabPanel paddingTop="16">Or Badge</TabPanel>
47
+ <TabPanel paddingTop="16">This panel is disabled</TabPanel>
48
+ <TabPanel paddingTop="16">You can add icon to tab</TabPanel>
49
+ </TabPanels>
50
+ </Tabs>
51
+ );
52
+ };
@@ -0,0 +1,51 @@
1
+ const TextTheme = {
2
+ baseStyle: {
3
+ tab: {
4
+ display: 'flex',
5
+ alignItems: 'center',
6
+ fontSize: '3',
7
+ gap: '8',
8
+ lineHeight: '3',
9
+ paddingX: '16',
10
+ paddingTop: '12',
11
+ paddingBottom: '10px',
12
+ borderBottom: '2px solid',
13
+ borderBottomColor: 'transparent',
14
+ color: 'neutral.50',
15
+ fontWeight: 'bold',
16
+ _selected: {
17
+ borderBottomColor: 'purple.50',
18
+ color: 'purple.50',
19
+ },
20
+ _focusVisible: {
21
+ backgroundColor: 'purple.95',
22
+ boxShadow: 'none',
23
+ color: 'purple.50',
24
+ },
25
+ _hover: {
26
+ backgroundColor: 'neutral.95',
27
+ },
28
+ _active: {
29
+ backgroundColor: 'neutral.93',
30
+ },
31
+ _disabled: {
32
+ color: 'neutral.70',
33
+ cursor: 'not-allowed',
34
+ _hover: {
35
+ background: 'transparent',
36
+ },
37
+ },
38
+ },
39
+ tablist: {
40
+ borderBottom: '1px solid',
41
+ borderBottomColor: 'separator.primary',
42
+ },
43
+ tabpanel: {
44
+ _focusVisible: {
45
+ boxShadow: 'none',
46
+ },
47
+ },
48
+ },
49
+ };
50
+
51
+ export default TextTheme;
@@ -0,0 +1,53 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Tabs as ChakraTabs, TabsProps as ChakraTabsProps, forwardRef } from '@chakra-ui/react';
3
+ import { useHistory } from '../../hooks';
4
+
5
+ export interface TabsProps extends ChakraTabsProps {
6
+ withHistory?: boolean;
7
+ }
8
+
9
+ const getTabIds = (props: TabsProps) => {
10
+ const ids: string[] = [];
11
+ const tabs = React.Children.toArray(props.children)[0] as any;
12
+ React.Children.forEach(tabs.props.children, (c, index) => {
13
+ ids[index] = c?.props?.id;
14
+ });
15
+ return ids;
16
+ };
17
+
18
+ /**
19
+ * An accessible tabs component that provides keyboard interactions and ARIA attributes described in the WAI-ARIA Tabs Design Pattern.
20
+ */
21
+ const Tabs = forwardRef<TabsProps, 'div'>((props, ref) => {
22
+ const { defaultIndex = 0, onChange, withHistory, ...rest } = props;
23
+ const { searchParams, replace } = useHistory();
24
+ const [actualIndex, setActualIndex] = useState(defaultIndex);
25
+
26
+ const tabIds = getTabIds(props);
27
+
28
+ useEffect(() => {
29
+ if (withHistory && searchParams.get('tab')) {
30
+ const tabName = searchParams.get('tab') || '';
31
+ const index = tabIds.indexOf(tabName) > -1 ? tabIds.indexOf(tabName) : defaultIndex;
32
+ setActualIndex(index);
33
+ }
34
+ }, []);
35
+
36
+ const onTabChange = (index: number) => {
37
+ setActualIndex(index);
38
+ if (withHistory) {
39
+ if (tabIds[index]) {
40
+ searchParams.set('tab', tabIds[index]);
41
+ } else {
42
+ searchParams.delete('tab');
43
+ }
44
+ replace(`?${searchParams.toString()}`);
45
+ }
46
+ if (onChange) {
47
+ onChange(index);
48
+ }
49
+ };
50
+ return <ChakraTabs {...rest} ref={ref} onChange={onTabChange} index={actualIndex} />;
51
+ });
52
+
53
+ export default Tabs;
@@ -0,0 +1 @@
1
+ export { default as useHistory } from './useHistory';
@@ -0,0 +1,67 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ type UseLocation = {
4
+ pathname: string;
5
+ push: (url: string) => void;
6
+ replace: (url: string) => void;
7
+ search: string;
8
+ searchParams: URLSearchParams;
9
+ };
10
+
11
+ const getCurrentLocation = () => ({
12
+ pathname: window.location.pathname,
13
+ search: window.location.search,
14
+ });
15
+
16
+ const listeners: Array<() => void> = [];
17
+
18
+ const notify = () => {
19
+ listeners.forEach((listener) => listener());
20
+ };
21
+
22
+ const getSearchParams = (search: string): URLSearchParams => {
23
+ const searchParams = new URLSearchParams(search);
24
+ return searchParams;
25
+ };
26
+
27
+ const useLocation = (): UseLocation => {
28
+ const [{ pathname, search }, setLocation] = useState(getCurrentLocation());
29
+
30
+ const handleChange = () => {
31
+ setLocation(getCurrentLocation());
32
+ };
33
+
34
+ const push = (url: string) => {
35
+ window.history.pushState(null, '', url);
36
+ notify();
37
+ };
38
+
39
+ const replace = (url: string) => {
40
+ window.history.replaceState(null, '', url);
41
+ notify();
42
+ };
43
+
44
+ useEffect(() => {
45
+ window.addEventListener('popstate', handleChange);
46
+ return () => {
47
+ window.removeEventListener('popstate', handleChange);
48
+ };
49
+ }, []);
50
+
51
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
52
+ // @ts-ignore
53
+ useEffect(() => {
54
+ listeners.push(handleChange);
55
+ return () => listeners.splice(listeners.indexOf(handleChange), 1);
56
+ }, []);
57
+
58
+ return {
59
+ pathname,
60
+ push,
61
+ replace,
62
+ search,
63
+ searchParams: getSearchParams(search),
64
+ };
65
+ };
66
+
67
+ export default useLocation;
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './old';
2
2
  export * from './types/chakra';
3
3
  export * from './utils/chakra';
4
+ export * from './hooks';
4
5
 
5
6
  export type { LinkProps } from './Components/Link/Link';
6
7
  export { default as Link } from './Components/Link/Link';
@@ -37,3 +38,18 @@ export { default as Box } from './Components/Box/Box';
37
38
 
38
39
  export type { ColorButtonProps } from './Components/ColorButton/ColorButton';
39
40
  export { default as ColorButton } from './Components/ColorButton/ColorButton';
41
+
42
+ export type { TabsProps } from './Components/Tabs/Tabs';
43
+ export { default as Tabs } from './Components/Tabs/Tabs';
44
+
45
+ export type { TabListProps } from './Components/Tabs/TabList';
46
+ export { default as TabList } from './Components/Tabs/TabList';
47
+
48
+ export type { TabProps } from './Components/Tabs/Tab';
49
+ export { default as Tab } from './Components/Tabs/Tab';
50
+
51
+ export type { TabPanelsProps } from './Components/Tabs/TabPanels';
52
+ export { default as TabPanels } from './Components/Tabs/TabPanels';
53
+
54
+ export type { TabPanelProps } from './Components/Tabs/TabPanel';
55
+ export { default as TabPanel } from './Components/Tabs/TabPanel';
package/src/old.ts CHANGED
@@ -226,12 +226,6 @@ export { default as TableHeaderRow } from './Old/Table/TableHeaderRow';
226
226
  export type { Props as TableRowProps } from './Old/Table/TableRow';
227
227
  export { default as TableRow } from './Old/Table/TableRow';
228
228
 
229
- export type { Props as TabProps } from './Old/Tabs/Tab';
230
- export { default as Tab } from './Old/Tabs/Tab';
231
-
232
- export type { Props as TabsProps } from './Old/Tabs/Tabs';
233
- export { default as Tabs } from './Old/Tabs/Tabs';
234
-
235
229
  export type { Props as TextareaProps } from './Old/Textarea/Textarea';
236
230
  export { default as Textarea } from './Old/Textarea/Textarea';
237
231
 
package/src/theme.ts CHANGED
@@ -4,6 +4,7 @@ import ColorButton from './Components/ColorButton/ColorButton.theme';
4
4
  import Divider from './Components/Divider/Divider.theme';
5
5
  import Link from './Components/Link/Link.theme';
6
6
  import Menu from './Components/Menu/Menu.theme';
7
+ import Tabs from './Components/Tabs/Tabs.theme';
7
8
  import Text from './Components/Text/Text.theme';
8
9
 
9
10
  import colors from './Foundations/Colors/Colors';
@@ -52,6 +53,7 @@ const theme = {
52
53
  Divider,
53
54
  Link,
54
55
  Menu,
56
+ Tabs,
55
57
  Text,
56
58
  },
57
59
  };