1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {ReactContext} from 'shared/ReactTypes';
    
  11. 
    
  12. import {createContext} from 'react';
    
  13. 
    
  14. export type ShowFn = ({data: Object, pageX: number, pageY: number}) => void;
    
  15. export type HideFn = () => void;
    
  16. export type OnChangeFn = boolean => void;
    
  17. 
    
  18. const idToShowFnMap = new Map<string, ShowFn>();
    
  19. const idToHideFnMap = new Map<string, HideFn>();
    
  20. 
    
  21. let currentHide: ?HideFn = null;
    
  22. let currentOnChange: ?OnChangeFn = null;
    
  23. 
    
  24. function hideMenu() {
    
  25.   if (typeof currentHide === 'function') {
    
  26.     currentHide();
    
  27. 
    
  28.     if (typeof currentOnChange === 'function') {
    
  29.       currentOnChange(false);
    
  30.     }
    
  31.   }
    
  32. 
    
  33.   currentHide = null;
    
  34.   currentOnChange = null;
    
  35. }
    
  36. 
    
  37. function showMenu({
    
  38.   data,
    
  39.   id,
    
  40.   onChange,
    
  41.   pageX,
    
  42.   pageY,
    
  43. }: {
    
  44.   data: Object,
    
  45.   id: string,
    
  46.   onChange?: OnChangeFn,
    
  47.   pageX: number,
    
  48.   pageY: number,
    
  49. }) {
    
  50.   const showFn = idToShowFnMap.get(id);
    
  51.   if (typeof showFn === 'function') {
    
  52.     // Prevent open menus from being left hanging.
    
  53.     hideMenu();
    
  54. 
    
  55.     currentHide = idToHideFnMap.get(id);
    
  56. 
    
  57.     showFn({data, pageX, pageY});
    
  58. 
    
  59.     if (typeof onChange === 'function') {
    
  60.       currentOnChange = onChange;
    
  61.       onChange(true);
    
  62.     }
    
  63.   }
    
  64. }
    
  65. 
    
  66. function registerMenu(id: string, showFn: ShowFn, hideFn: HideFn): () => void {
    
  67.   if (idToShowFnMap.has(id)) {
    
  68.     throw Error(`Context menu with id "${id}" already registered.`);
    
  69.   }
    
  70. 
    
  71.   idToShowFnMap.set(id, showFn);
    
  72.   idToHideFnMap.set(id, hideFn);
    
  73. 
    
  74.   return function unregisterMenu() {
    
  75.     idToShowFnMap.delete(id);
    
  76.     idToHideFnMap.delete(id);
    
  77.   };
    
  78. }
    
  79. 
    
  80. export type RegistryContextType = {
    
  81.   hideMenu: typeof hideMenu,
    
  82.   showMenu: typeof showMenu,
    
  83.   registerMenu: typeof registerMenu,
    
  84. };
    
  85. 
    
  86. export const RegistryContext: ReactContext<RegistryContextType> =
    
  87.   createContext<RegistryContextType>({
    
  88.     hideMenu,
    
  89.     showMenu,
    
  90.     registerMenu,
    
  91.   });