-
Notifications
You must be signed in to change notification settings - Fork 15
/
useTabs.ts
106 lines (92 loc) · 2.96 KB
/
useTabs.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* Copyright Zendesk, Inc.
*
* Use of this source code is governed under the Apache License, Version 2.0
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/
import { useState } from 'react';
import { useUIDSeed } from 'react-uid';
import {
useSelection,
IGetItemPropsOptions,
IUseSelectionState,
IUseSelectionProps
} from '@zendeskgarden/container-selection';
interface IGetTabProps<Item> extends IGetItemPropsOptions<Item> {
index: number;
}
interface IGetTabPanelProps<Item> extends React.HTMLProps<any> {
index: number;
item: Item;
}
export interface IUseTabsReturnValue<Item> extends IUseSelectionState<Item> {
getTabProps: <T extends IGetItemPropsOptions<Item>>(options?: T) => any;
getTabPanelProps: <T extends IGetTabPanelProps<Item>>(options?: T) => any;
getTabListProps: <T>(options?: T) => T & React.HTMLProps<any>;
}
export interface IUseTabsProps<Item> extends IUseSelectionProps<Item> {
vertical?: boolean;
idPrefix?: string;
}
function requiredArguments(arg: any, argStr: string, methodName: string) {
if (typeof arg === 'undefined' || arg === null) {
throw new Error(
`Accessibility Error: You must provide an "${argStr}" option to "${methodName}()"`
);
}
}
export function useTabs<Item = any>({
vertical,
idPrefix,
...options
}: IUseTabsProps<Item> = {}): IUseTabsReturnValue<Item> {
const { selectedItem, focusedItem, getContainerProps, getItemProps } = useSelection<Item>({
direction: vertical ? 'vertical' : 'horizontal',
defaultSelectedIndex: 0,
...options
});
const seed = useUIDSeed();
const [_id] = useState(idPrefix || seed(`tabs_${PACKAGE_VERSION}`));
const PANEL_ID = `${_id}--panel`;
const TAB_ID = `${_id}--tab`;
const getTabListProps = ({ role = 'tablist', ...other }: React.HTMLProps<any> = {}) => {
return {
role,
'aria-orientation': vertical ? 'vertical' : 'horizontal',
'data-garden-container-id': 'containers.tabs',
'data-garden-container-version': PACKAGE_VERSION,
...other
};
};
const getTabProps = ({ role = 'tab', index, ...other }: IGetTabProps<Item> = {} as any) => {
requiredArguments(index, 'index', 'getTabProps');
return {
id: `${TAB_ID}:${index}`,
'aria-controls': `${PANEL_ID}:${index}`,
role,
...other
};
};
const getTabPanelProps = (
{ role = 'tabpanel', index, item, ...other }: IGetTabPanelProps<Item> = {} as any
) => {
requiredArguments(index, 'index', 'getTabPanelProps');
requiredArguments(item, 'item', 'getTabPanelProps');
const isHidden = item !== selectedItem;
return {
role,
tabIndex: 0,
id: `${PANEL_ID}:${index}`,
hidden: isHidden,
'aria-labelledby': `${TAB_ID}:${index}`,
...other
};
};
return {
selectedItem,
focusedItem,
getTabPanelProps,
getTabListProps: props => getContainerProps(getTabListProps(props) as any),
getTabProps: props => getItemProps(getTabProps(props as any), 'getTabProps')
};
}