@wener/console
Version:
Base console UI toolkit
129 lines (126 loc) • 4.54 kB
JavaScript
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