-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathtablist.tsx
95 lines (85 loc) · 2.53 KB
/
tablist.tsx
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
/**
* External dependencies
*/
import * as Ariakit from '@ariakit/react';
import { useStoreState } from '@ariakit/react';
/**
* WordPress dependencies
*/
import warning from '@wordpress/warning';
import { forwardRef, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import type { TabListProps } from './types';
import { useTabsContext } from './context';
import { TabListWrapper } from './styles';
import type { WordPressComponentProps } from '../context';
import clsx from 'clsx';
import { useTrackElementOffsetRect } from '../utils/element-rect';
import { useOnValueUpdate } from '../utils/hooks/use-on-value-update';
export const TabList = forwardRef<
HTMLDivElement,
WordPressComponentProps< TabListProps, 'div', false >
>( function TabList( { children, ...otherProps }, ref ) {
const context = useTabsContext();
const tabStoreState = useStoreState( context?.store );
const selectedId = tabStoreState?.selectedId;
const indicatorPosition = useTrackElementOffsetRect(
context?.store.item( selectedId )?.element
);
const [ animationEnabled, setAnimationEnabled ] = useState( false );
useOnValueUpdate(
selectedId,
( { previousValue } ) => previousValue && setAnimationEnabled( true )
);
if ( ! context || ! tabStoreState ) {
warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' );
return null;
}
const { store } = context;
const { activeId, selectOnMove } = tabStoreState;
const { setActiveId } = store;
const onBlur = () => {
if ( ! selectOnMove ) {
return;
}
// When automatic tab selection is on, make sure that the active tab is up
// to date with the selected tab when leaving the tablist. This makes sure
// that the selected tab will receive keyboard focus when tabbing back into
// the tablist.
if ( selectedId !== activeId ) {
setActiveId( selectedId );
}
};
return (
<Ariakit.TabList
ref={ ref }
store={ store }
render={
<TabListWrapper
onTransitionEnd={ ( event ) => {
if ( event.pseudoElement === '::after' ) {
setAnimationEnabled( false );
}
} }
/>
}
onBlur={ onBlur }
{ ...otherProps }
style={ {
'--indicator-left': `${ indicatorPosition.left }px`,
'--indicator-top': `${ indicatorPosition.top }px`,
'--indicator-width': `${ indicatorPosition.width }px`,
'--indicator-height': `${ indicatorPosition.height }px`,
...otherProps.style,
} }
className={ clsx(
animationEnabled ? 'is-animation-enabled' : '',
otherProps.className
) }
>
{ children }
</Ariakit.TabList>
);
} );