-
-
Notifications
You must be signed in to change notification settings - Fork 65
/
Copy pathOverflowMenuContext.tsx
114 lines (100 loc) · 2.91 KB
/
OverflowMenuContext.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { Dimensions } from 'react-native';
import { getDefaultSpaceAboveMenu } from './statusBarUtils';
import { Menu } from './vendor/Menu';
import { useTheme } from '@react-navigation/native';
import {
createContext,
ReactElement,
ReactNode,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import * as React from 'react';
import { ButtonsExtraMarginContext } from '../ButtonsWrapper';
export type ToggleMenuParam = {
elements: React.ReactNode;
x: number;
y: number;
};
export const OVERFLOW_TOP = 15;
const warn = () => {
// the noop value will be replaced by HeaderButtonsProvider rendered in app root
console.warn(
'It seems like you tried to open the overflow menu using the overflowMenuPressHandlerDropdownMenu' +
' - which is the default handler on android - but you forgot to wrap your root component in <HeaderButtonsProvider />.' +
'Please check the installation instructions in the react-navigation-header-buttons readme :)'
);
};
const OverflowMenuContext = createContext<{
toggleMenu: (params?: ToggleMenuParam) => void;
}>({
toggleMenu: warn,
});
export const useOverflowMenu = () => useContext(OverflowMenuContext);
type Props = {
children: ReactElement;
stackType: 'native' | 'js';
spaceAboveMenu?: number;
};
export const HeaderButtonsProvider = ({
children,
spaceAboveMenu,
stackType,
}: Props) => {
const [menuState, setMenuState] = useState({
visible: false,
position: {
x: Dimensions.get('window').width - 10,
y: 40,
},
elements: null as ReactNode | null,
});
const {
colors: { card },
} = useTheme();
const hideMenu = useCallback(() => {
setMenuState((prevState) => ({
...prevState,
visible: false,
}));
}, []);
const toggleMenu = useCallback(
(params?: ToggleMenuParam) => {
const extraDelta = spaceAboveMenu ?? getDefaultSpaceAboveMenu();
setMenuState((prevState) => {
const position = params
? { x: params.x, y: params.y + extraDelta }
: prevState.position;
const elements = params ? params.elements : prevState.elements;
return {
...prevState,
position,
elements,
visible: !prevState.visible,
};
});
},
[spaceAboveMenu]
);
const { visible, position, elements } = menuState;
const value = useMemo(() => ({ toggleMenu }), [toggleMenu]);
const extraMarginValue =
stackType === 'native' ? 'alreadyHandled' : 'toBeHandled';
return (
<OverflowMenuContext.Provider value={value}>
<ButtonsExtraMarginContext.Provider value={extraMarginValue}>
{React.Children.only(children)}
<Menu
visible={visible}
onDismiss={hideMenu}
anchor={position}
contentStyle={{ backgroundColor: card }}
>
{elements}
</Menu>
</ButtonsExtraMarginContext.Provider>
</OverflowMenuContext.Provider>
);
};