import React from "react"; import ReactDOM from "react-dom"; import { action, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { closest } from "eez-studio-shared/dom"; import { EnumItem } from "project-editor/core/object"; import { humanize } from "eez-studio-shared/string"; //////////////////////////////////////////////////////////////////////////////// export const IconEnumDropdown = observer( class IconEnumDropdown extends React.Component<{ enumItems: EnumItem[]; value: any; onChange: (value: any) => void; }> { buttonRef = React.createRef(); dropDownRef = React.createRef(); dropDownOpen = false; dropDownRight = 0; dropDownTop = 0; hoveredItemId: string | undefined = undefined; constructor(props: any) { super(props); makeObservable(this, { dropDownOpen: observable, dropDownRight: observable, dropDownTop: observable, hoveredItemId: observable, setDropDownOpen: action }); } setDropDownOpen(open: boolean) { if (!open) { document.removeEventListener( "pointerdown", this.onDocumentPointerDown, true ); } this.dropDownOpen = open; if (this.dropDownOpen) { document.addEventListener( "pointerdown", this.onDocumentPointerDown, true ); } } openDropdown = action(() => { const buttonEl = this.buttonRef.current; if (!buttonEl) { return; } this.setDropDownOpen(!this.dropDownOpen); if (this.dropDownOpen) { this.hoveredItemId = undefined; const rect = buttonEl.getBoundingClientRect(); this.dropDownRight = window.innerWidth - rect.right; this.dropDownTop = rect.bottom; const DROP_DOWN_HEIGHT = 200; if ( this.dropDownTop + DROP_DOWN_HEIGHT + 20 > window.innerHeight ) { this.dropDownTop = rect.top - DROP_DOWN_HEIGHT; } } }); onDocumentPointerDown = action((event: MouseEvent) => { if (this.dropDownOpen) { if ( !closest( event.target, el => this.buttonRef.current == el || this.dropDownRef.current == el ) ) { //event.preventDefault(); //event.stopPropagation(); this.setDropDownOpen(false); } } }); componentWillUnmount() { document.removeEventListener( "pointerdown", this.onDocumentPointerDown, true ); } render() { const { enumItems, value } = this.props; const selectedItem = enumItems.find( item => item.id.toString() === value?.toString() ); const portal = ReactDOM.createPortal(
    {enumItems.map(item => { const id = item.id.toString(); const label = item.label || humanize(id); const isSelected = id === value?.toString(); const isHighlighted = this.hoveredItemId !== undefined ? this.hoveredItemId === id : isSelected; return (
  • { this.hoveredItemId = id; } )} onClick={action(() => { this.props.onChange(item.id); this.setDropDownOpen(false); })} > {item.icon} {label}
  • ); })}
, document.body ); return (
{portal}
); } } );