@bitrise/bitkit 9.17.0-alpha-chakra.1 → 9.17.0-alpha-chakra.2
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.
|
|
4
|
+
"version": "9.17.0-alpha-chakra.2",
|
|
5
5
|
"repository": "git@github.com:bitrise-io/bitkit.git",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"license": "UNLICENSED",
|
|
@@ -19,14 +19,18 @@ const badge = {
|
|
|
19
19
|
|
|
20
20
|
export const WithDefaults: ComponentStory<typeof Tabs> = () => {
|
|
21
21
|
return (
|
|
22
|
-
<Tabs defaultIndex={1} variant="unstyled">
|
|
22
|
+
<Tabs defaultIndex={1} variant="unstyled" withHistory>
|
|
23
23
|
<TabList>
|
|
24
|
-
<Tab>Default</Tab>
|
|
25
|
-
<Tab>Selected as default</Tab>
|
|
24
|
+
<Tab id="default">Default</Tab>
|
|
25
|
+
<Tab id="selected-as-default">Selected as default</Tab>
|
|
26
26
|
<Tab leftIconName="Bell">With left icon</Tab>
|
|
27
|
-
<Tab badge={badge}>
|
|
27
|
+
<Tab id="with-badge" badge={badge}>
|
|
28
|
+
With badge
|
|
29
|
+
</Tab>
|
|
28
30
|
<Tab isDisabled>Disabled</Tab>
|
|
29
|
-
<Tab rightIconName="ArrowForward">
|
|
31
|
+
<Tab id="with-right-icon" rightIconName="ArrowForward">
|
|
32
|
+
With right icon
|
|
33
|
+
</Tab>
|
|
30
34
|
</TabList>
|
|
31
35
|
|
|
32
36
|
<TabPanels>
|
|
@@ -1,13 +1,53 @@
|
|
|
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
|
+
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
|
+
};
|
|
3
17
|
|
|
4
18
|
/**
|
|
5
19
|
* An accessible tabs component that provides keyboard interactions and ARIA attributes described in the WAI-ARIA Tabs Design Pattern.
|
|
6
20
|
*/
|
|
7
21
|
const Tabs = forwardRef<TabsProps, 'div'>((props, ref) => {
|
|
8
|
-
|
|
9
|
-
});
|
|
22
|
+
const { defaultIndex = 0, onChange, withHistory, ...rest } = props;
|
|
23
|
+
const { searchParams, replace } = useHistory();
|
|
24
|
+
const [actualIndex, setActualIndex] = useState(defaultIndex);
|
|
10
25
|
|
|
11
|
-
|
|
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
|
+
});
|
|
12
52
|
|
|
13
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;
|