Skip to content

Instantly share code, notes, and snippets.

@Nyrox
Created June 5, 2020 16:50
Show Gist options
  • Save Nyrox/007fdd6964fae153e6e145a9f6481c42 to your computer and use it in GitHub Desktop.
Save Nyrox/007fdd6964fae153e6e145a9f6481c42 to your computer and use it in GitHub Desktop.
module ContextMenu
open Fable
open Fable.Core
open Utils
open Fable.React
open Elmish
open Elmish.React
open Fable.React.Props
open Fable.React.HookBindings
open Fable.React.ReactDomBindings
open Browser.Dom
let createDisposable f =
{
new System.IDisposable with
member x.Dispose() = f()
}
type MenuItem = string * (unit -> unit)
type Menu = MenuItem list
let contextMenuItem (item: MenuItem) =
let itemName, cb = item
button [OnClick (fun _ -> cb ())] [str itemName]
let contextMenuPopup (menu: Menu) pos =
let (x, y) = pos
let menuItems =
menu
|> Seq.map contextMenuItem
div [ClassName "context-menu-popup"; Style [Left x; Top y]] menuItems
let contextMenu (menu: Menu) comp = React.FunctionComponent.Of ((fun (props: list<IHTMLProp>) ->
let expandedState = Hooks.useState false
let pos = Hooks.useState (0.0, 0.0)
let closePopup e =
expandedState.update false
let onContextMenu (e: Browser.Types.MouseEvent) =
Utils.preventDefault e
expandedState.update true
pos.update ((e.clientX, e.clientY))
Hooks.useEffectDisposable (fun () ->
document.addEventListener("click", closePopup)
createDisposable (fun () ->
document.removeEventListener("click", closePopup)
)
)
fragment [] [
comp <| ((OnContextMenu onContextMenu) :> IHTMLProp) :: props
ReactDom.createPortal ((if expandedState.current then contextMenuPopup menu pos.current else null), Browser.Dom.document.body)
]
), "ContextMenu", memoEqualsButFunctions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment