@bitrise/bitkit 9.17.0-alpha-chakra.1 → 9.17.0-alpha-chakra.4

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.17.0-alpha-chakra.1",
4
+ "version": "9.17.0-alpha-chakra.4",
5
5
  "repository": "git@github.com:bitrise-io/bitkit.git",
6
6
  "main": "src/index.ts",
7
7
  "license": "UNLICENSED",
@@ -9,6 +9,11 @@ export default {
9
9
  title: 'Components/Tabs',
10
10
  component: Tabs,
11
11
  subcomponents: { Tab },
12
+ argTypes: {
13
+ onChange: {
14
+ action: 'onChange event',
15
+ },
16
+ },
12
17
  } as ComponentMeta<typeof Tabs>;
13
18
 
14
19
  const badge = {
@@ -17,16 +22,20 @@ const badge = {
17
22
  color: 'neutral.10',
18
23
  };
19
24
 
20
- export const WithDefaults: ComponentStory<typeof Tabs> = () => {
25
+ export const WithDefaults: ComponentStory<typeof Tabs> = (props) => {
21
26
  return (
22
- <Tabs defaultIndex={1} variant="unstyled">
27
+ <Tabs defaultIndex={1} variant="unstyled" {...props}>
23
28
  <TabList>
24
- <Tab>Default</Tab>
25
- <Tab>Selected as default</Tab>
29
+ <Tab id="basic">Basic</Tab>
30
+ <Tab id="selected-as-default">Selected as default</Tab>
26
31
  <Tab leftIconName="Bell">With left icon</Tab>
27
- <Tab badge={badge}>With badge</Tab>
32
+ <Tab id="with-badge" badge={badge}>
33
+ With badge
34
+ </Tab>
28
35
  <Tab isDisabled>Disabled</Tab>
29
- <Tab rightIconName="ArrowForward">With right icon</Tab>
36
+ <Tab id="with-right-icon" rightIconName="ArrowForward">
37
+ With right icon
38
+ </Tab>
30
39
  </TabList>
31
40
 
32
41
  <TabPanels>
@@ -46,3 +55,7 @@ export const WithDefaults: ComponentStory<typeof Tabs> = () => {
46
55
  </Tabs>
47
56
  );
48
57
  };
58
+
59
+ WithDefaults.args = {
60
+ withHistory: true,
61
+ };
@@ -1,13 +1,55 @@
1
- import React from 'react';
2
- import { Tabs as ChakraTabs, TabsProps, forwardRef } from '@chakra-ui/react';
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
+ onChange?: (index: number, tabId?: string) => void;
7
+ withHistory?: boolean;
8
+ }
9
+
10
+ const getTabIds = (props: TabsProps) => {
11
+ const ids: string[] = [];
12
+ const tabs = React.Children.toArray(props.children)[0] as any;
13
+ React.Children.forEach(tabs.props.children, (c, index) => {
14
+ ids[index] = c?.props?.id;
15
+ });
16
+ return ids;
17
+ };
3
18
 
4
19
  /**
5
20
  * An accessible tabs component that provides keyboard interactions and ARIA attributes described in the WAI-ARIA Tabs Design Pattern.
6
21
  */
7
22
  const Tabs = forwardRef<TabsProps, 'div'>((props, ref) => {
8
- return <ChakraTabs {...props} ref={ref} />;
9
- });
23
+ const { defaultIndex = 0, onChange, withHistory, ...rest } = props;
24
+ const { searchParams, replace } = useHistory();
25
+ const [actualIndex, setActualIndex] = useState(defaultIndex);
10
26
 
11
- export type { TabsProps };
27
+ const tabIds = getTabIds(props);
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
+ }, []);
36
+
37
+ const onTabChange = (index: number) => {
38
+ const tabId = tabIds[index];
39
+ setActualIndex(index);
40
+ if (withHistory) {
41
+ if (tabId) {
42
+ searchParams.set('tab', tabId);
43
+ } else {
44
+ searchParams.delete('tab');
45
+ }
46
+ replace(`?${searchParams.toString()}`);
47
+ }
48
+ if (onChange) {
49
+ onChange(index, tabId);
50
+ }
51
+ };
52
+ return <ChakraTabs {...rest} ref={ref} onChange={onTabChange} index={actualIndex} />;
53
+ });
12
54
 
13
55
  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';