import React, { CSSProperties, ReactNode, useMemo, useState } from "react"; import classNames from "classnames"; import { Modifier } from "react-popper-2"; import { MenuListComponentProps } from "react-select"; import FocusLock from "react-focus-lock"; import { tokens } from "../../tokens"; import { useOutsideClick } from "../../hooks"; import { Box } from "../Box"; import { Flex } from "../Flex"; import { Stack } from "../Stack"; import { PopoverMenu } from "../PopoverMenu"; import { Icon, ICON_TYPE } from "../Icon"; import { CloseButton } from "../CloseButton"; import { Text } from "../Text"; import { Select, SelectProps } from "./Select"; import { Popover } from "../Popover"; import { PopperPlacement } from "../../types"; interface SelectPopoverProps { readView: ReactNode; cancelButton: ReactNode; onCancelEdit: () => void; selectProps: SelectProps; preventOutsideClick?: boolean; optionsMessage?: string; isCreatable?: boolean; className?: string; style?: CSSProperties; } export const SelectPopover = ({ readView, cancelButton, onCancelEdit, preventOutsideClick = false, optionsMessage, isCreatable, selectProps, className, style, }: SelectPopoverProps) => { const containerElement = React.useRef(null); const selectWrapperElement = React.useRef(null); const readViewWrapperElement = React.useRef(null); useOutsideClick( [containerElement, selectWrapperElement, readViewWrapperElement], () => { if (!preventOutsideClick) { onCancelEdit(); } }, ); const selectStyles = { control: (provided: any) => ({ ...provided, width: `calc(100% - ${tokens.margin[6]})`, margin: tokens.margin[3], }), menu: (provided: any) => ({ ...provided, boxShadow: "none !important", // override Arrow classname borderRadius: "0 !important", // override Arrow classname zIndex: "1 !important", // override Arrow classname backgroundColor: tokens.colors.white, position: "relative", marginTop: tokens.margin[3], marginBottom: 0, borderTop: `1px solid ${tokens.colors.gray[300]}`, maxHeight: "184px", overflowY: "auto", }), }; const components = { DropdownIndicator: () => , MenuList: (props: MenuListComponentProps) => { const { children, innerRef, options } = props; return ( {children} {options.length > 0 && optionsMessage && ( {optionsMessage} )} ); }, IndicatorSeparator: null, }; const sharedProps = { isCreatable, onBlur: () => {}, // prevent onBlur from closing popover; rely on useOutsideClick components, styles: selectStyles, tabSelectsValue: false, closeMenuOnSelect: false, menuInPortal: false, backspaceRemovesValue: false, controlShouldRenderValue: false, hideSelectedOptions: false, isClearable: false, menuIsOpen: true, autoFocus: true, className: classNames("w-full"), }; const initialPlacement = "bottom"; const [currentPlacement, setCurrentPlacement] = useState( initialPlacement, ); const popperModifiers: Modifier[] = useMemo( () => [ { name: "sameWidth", enabled: true, phase: "beforeWrite", requires: ["computeStyles"], fn({ state }) { setCurrentPlacement(state.placement); const newState = state; newState.styles.popper.width = `${state.rects.reference.width}px`; return newState; }, }, { name: "offset", options: { offset: [0, -1], }, }, ], [], ); return ( {readView} { if (selectProps.onChange) { if (selectProps.isMulti) { selectProps.onChange([], { action: "clear" }); } else { selectProps.onChange( { label: "", value: "" }, { action: "clear" }, ); } } }} /> {cancelButton} } > {isCreatable ? ( ) : (