import Popups, { PopupPlacement } from "hoctable/services/popups"; import Viewport from "hoctable/services/window"; import * as React from "react"; const TARGET_TOP_BUFFER = 3; export type PopupCloseCallback = () => void; export interface MenuOpenEvent { currentTarget : HTMLElement; } export interface MenuState { popup : string | number; updated? : number; } export const CLASSES = { MENU : "hoctable__menu", MENU_DEFAULT_BUTTON : "hoctable__menu-default-button", MENU_BUTTON_CONTAINER : "hoctable__menu-button-container", }; function bottom(box : ClientRect) : number { return box.top + box.height; } export function DefaultButton(props : any) : React.ReactElement { const { text } = props; return ({text}); } function Factory

(Popup : React.ComponentClass, Button = DefaultButton) : React.ComponentClass

{ class Menu extends React.Component { constructor(props) { super(props); this.open = this.open.bind(this); this.state = { popup: null }; } componentWillUnmount() : void { const { state } = this; Popups.close(state.popup); } open(trigger : React.MouseEvent) : void { const button = this.refs["button"] as HTMLElement; const bounding = button.getBoundingClientRect(); /* Get the current top of the window, this will need to be added to the position that * we use to place the popup, which will go below the button that was clicked. */ const { y: win_top } = Viewport.scroll(); const { width: window_width } = Viewport.dimensions(); // Calculate the top. const top = bottom(bounding) + TARGET_TOP_BUFFER + win_top; // Create our placement object using the provided bounding box. const placement : PopupPlacement = { top, left: bounding.left }; // If we're on the right side of the screen, move the menu to be right aligned if(bounding.left > window_width * 0.5) { placement.right = window_width - (bounding.left + bounding.width); } let popup = null; const close = () : void => { Popups.close(popup); this.setState({ popup: null }); }; const redraw = () : void => { this.setState({ updated: Date.now() }); }; // Open the popup component with all of the props that were given to us popup = Popups.open(, placement); if(popup === -1) { throw new Error("unable to open popup, is service mounted?"); } // Update our state with the popup id so we may close it on unmount this.setState({ popup }); } render() : JSX.Element { return (

); } } return Menu; } export default Factory;