Page MenuHomePhabricator

D3375.diff
No OneTemporary

D3375.diff

diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -28,6 +28,7 @@
import Chat from './chat/chat.react';
import InputStateContainer from './input/input-state-container.react';
import LoadingIndicator from './loading-indicator.react';
+import { MenuProvider } from './menu-provider.react';
import { ModalProvider, useModalContext } from './modals/modal-provider.react';
import DisconnectedBar from './redux/disconnected-bar';
import DisconnectedBarVisibilityHandler from './redux/disconnected-bar-visibility-handler';
@@ -129,10 +130,12 @@
}
return (
<DndProvider backend={HTML5Backend}>
- <FocusHandler />
- <VisibilityHandler />
- {content}
- {this.props.modal}
+ <MenuProvider>
+ <FocusHandler />
+ <VisibilityHandler />
+ {content}
+ {this.props.modal}
+ </MenuProvider>
</DndProvider>
);
}
diff --git a/web/menu-provider.react.js b/web/menu-provider.react.js
new file mode 100644
--- /dev/null
+++ b/web/menu-provider.react.js
@@ -0,0 +1,84 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import type { SetState } from 'lib/types/hook-types';
+
+import css from './menu.css';
+
+type MenuPosition = {
+ +top: number,
+ +left: number,
+};
+type Props = {
+ +children: React.Node,
+};
+type MenuContextType = {
+ +renderMenu: SetState<React.Node>,
+ +setMenuPosition: SetState<MenuPosition>,
+ +closeMenu: React.Node => void,
+ +currentOpenMenu: symbol,
+ +setCurrentOpenMenu: SetState<symbol>,
+};
+
+const MenuContext: React.Context<MenuContextType> = React.createContext<MenuContextType>(
+ {
+ renderMenu: () => {},
+ setMenuPosition: () => {},
+ closeMenu: () => {},
+ currentOpenMenu: Symbol(),
+ setCurrentOpenMenu: () => {},
+ },
+);
+
+function MenuProvider(props: Props): React.Node {
+ const { children } = props;
+ const [menu, setMenu] = React.useState(null);
+ const [currentOpenMenu, setCurrentOpenMenu] = React.useState<symbol>(
+ Symbol(),
+ );
+ const [position, setPosition] = React.useState<MenuPosition>({
+ top: 0,
+ left: 0,
+ });
+
+ const closeMenu = React.useCallback((menuToClose: React.Node) => {
+ setCurrentOpenMenu(Symbol());
+ setMenu(oldMenu => {
+ if (oldMenu === menuToClose) {
+ return null;
+ } else {
+ return oldMenu;
+ }
+ });
+ }, []);
+
+ const value = React.useMemo(
+ () => ({
+ renderMenu: setMenu,
+ setMenuPosition: setPosition,
+ closeMenu,
+ setCurrentOpenMenu,
+ currentOpenMenu,
+ }),
+ [closeMenu, currentOpenMenu],
+ );
+ return (
+ <>
+ <MenuContext.Provider value={value}>{children}</MenuContext.Provider>
+ <div style={position} className={css.container}>
+ {menu}
+ </div>
+ </>
+ );
+}
+
+function useRenderMenu(): MenuContextType {
+ const context = React.useContext(MenuContext);
+ invariant(context, 'MenuContext not found');
+
+ return context;
+}
+
+export { MenuProvider, useRenderMenu };
diff --git a/web/menu.css b/web/menu.css
new file mode 100644
--- /dev/null
+++ b/web/menu.css
@@ -0,0 +1,3 @@
+div.container {
+ position: absolute;
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 19, 4:46 AM (20 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2675335
Default Alt Text
D3375.diff (3 KB)

Event Timeline