UNPKG

@wener/console

Version:

Base console UI toolkit

129 lines (126 loc) 4.54 kB
import React, { cloneElement, isValidElement, useMemo, useState } from "react"; import { autoUpdate } from "@floating-ui/dom"; import { flip, FloatingFocusManager, FloatingNode, FloatingPortal, offset, shift, useClick, useDismiss, useFloating, useFloatingNodeId, useId, useInteractions, useRole } from "@floating-ui/react"; import { flexRender, mergeRefs, useControllable } from "@wener/reaction"; import { clsx } from "clsx"; import { useFloatingInteractions } from "./useFloatingInteractions.js"; export const Popover = ({ children, placement, content, portal, className, style, click = true, dismiss = true, hover = false, role = "dialog", focus, modal, offset: _offset = 5, shift: _shift, ...props }) => { const [open, setOpen] = useControllable(props.open, props.onOpenChange, false); const { x, y, refs, strategy, context } = useFloating({ open, onOpenChange: setOpen, middleware: [ offset(_offset), flip(), shift(_shift) ], placement, whileElementsMounted: autoUpdate }); const id = useId(); const labelId = `${id}-label`; const descriptionId = `${id}-description`; const { getReferenceProps, getFloatingProps } = useFloatingInteractions(context, { click, dismiss, hover, focus, role }); // Preserve the consumer's ref const ref = useMemo(() => mergeRefs(refs.setReference, children.ref), [ refs.setReference, children ]); const pop = open && /*#__PURE__*/ React.createElement(FloatingFocusManager, { context: context, modal: modal, order: [ "reference", "content" ], returnFocus: true }, /*#__PURE__*/ React.createElement("div", { ref: refs.setFloating, className: clsx("Popover", className), style: { ...style, position: strategy, top: y ?? 0, left: x ?? 0 }, "aria-labelledby": labelId, "aria-describedby": descriptionId, ...getFloatingProps() }, !open ? null : flexRender(content, { close: () => { setOpen(false); }, labelId, descriptionId }))); return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ cloneElement(children, getReferenceProps({ ref, ...children.props })), open && !portal && pop, /*#__PURE__*/ React.createElement(FloatingPortal, null, open && portal && pop)); }; function PopoverComponent({ children, render, placement, modal = true, bubbles = true }) { const [open, setOpen] = useState(false); const nodeId = useFloatingNodeId(); const { floatingStyles, refs, context } = useFloating({ nodeId, open, placement, onOpenChange: setOpen, middleware: [ offset(10), flip(), shift() ], whileElementsMounted: autoUpdate }); const id = useId(); const labelId = `${id}-label`; const descriptionId = `${id}-description`; const { getReferenceProps, getFloatingProps } = useInteractions([ useClick(context), useRole(context), useDismiss(context, { bubbles }) ]); return /*#__PURE__*/ React.createElement(FloatingNode, { id: nodeId }, /*#__PURE__*/ isValidElement(children) && /*#__PURE__*/ cloneElement(children, getReferenceProps({ ref: refs.setReference, "data-open": open ? "" : undefined })), /*#__PURE__*/ React.createElement(FloatingPortal, null, open && /*#__PURE__*/ React.createElement(FloatingFocusManager, { context: context, modal: modal }, /*#__PURE__*/ React.createElement("div", { className: "rounded border border-slate-900/10 bg-white bg-clip-padding px-4 py-6 shadow-md", ref: refs.setFloating, style: floatingStyles, "aria-labelledby": labelId, "aria-describedby": descriptionId, ...getFloatingProps() }, render({ labelId, descriptionId, close: () => setOpen(false) }))))); } /* export function Popover(props: Props) { const parentId = useFloatingParentNodeId(); // This is a root, so we wrap it with the tree if (parentId === null) { return ( <FloatingTree> <PopoverComponent {...props} /> </FloatingTree> ); } return <PopoverComponent {...props} />; } */ //# sourceMappingURL=Popover.js.map