@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.1",
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}>With badge</Tab>
27
+ <Tab id="with-badge" badge={badge}>
28
+ With badge
29
+ </Tab>
28
30
  <Tab isDisabled>Disabled</Tab>
29
- <Tab rightIconName="ArrowForward">With right icon</Tab>
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
- return <ChakraTabs {...props} ref={ref} />;
9
- });
22
+ const { defaultIndex = 0, onChange, withHistory, ...rest } = props;
23
+ const { searchParams, replace } = useHistory();
24
+ const [actualIndex, setActualIndex] = useState(defaultIndex);
10
25
 
11
- export type { TabsProps };
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;
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';