@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
117 lines • 5.08 kB
JavaScript
/**
*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { autoUpdate, flip, offset, shift, size, useClick, useClientPoint, useDismiss, useFloating, useInteractions, useRole, useTransitionStyles, } from '@floating-ui/react';
import { tokens } from '@neo4j-ndl/base';
import { useMemo, useState } from 'react';
export function usePopover({ isInitialOpen = false, placement = 'bottom', isOpen: controlledOpen, onOpenChange: setControlledOpen, offsetOption = 10, anchorElement, anchorPosition, anchorElementAsPortalAnchor, shouldCaptureFocus, initialFocus, role: roleProp, closeOnClickOutside, closeOnReferencePress, returnFocus, strategy = 'absolute', isPortaled = true, shouldConstrainSize = false, } = {}) {
var _a;
// Internal state for uncontrolled mode (no `isOpen` prop provided).
const [isOpenUncontrolled, setIsOpenUncontrolled] = useState(isInitialOpen);
const [labelId, setLabelId] = useState();
const [descriptionId, setDescriptionId] = useState();
// Controlled/uncontrolled pattern: prefer the consumer-provided `isOpen`,
// falling back to internal state when not provided.
const isOpen = controlledOpen !== null && controlledOpen !== void 0 ? controlledOpen : isOpenUncontrolled;
const data = useFloating({
elements: {
reference: anchorElement,
},
middleware: [
offset(offsetOption),
flip({
crossAxis: placement.includes('-'),
fallbackAxisSideDirection: 'end',
padding: 5,
}),
shift(),
...(shouldConstrainSize
? [
size({
apply({ availableHeight, availableWidth, elements }) {
Object.assign(elements.floating.style, {
maxHeight: `${availableHeight}px`,
maxWidth: `${availableWidth}px`,
});
},
padding: 5,
}),
]
: []),
],
// Floating UI calls this when interactions (useClick, useDismiss, etc.)
// trigger an open/close. We always sync internal state so uncontrolled
// mode works, and notify the consumer callback exactly once if provided.
onOpenChange: (open, event) => {
setIsOpenUncontrolled(open);
setControlledOpen === null || setControlledOpen === void 0 ? void 0 : setControlledOpen(open, event);
},
open: isOpen,
placement: placement,
strategy,
whileElementsMounted: autoUpdate,
});
const context = data.context;
// Only enable built-in click-to-toggle in uncontrolled mode. In controlled
// mode the consumer owns the open state and wires up their own trigger.
const click = useClick(context, {
enabled: controlledOpen === undefined,
});
const dismiss = useDismiss(context, {
outsidePress: closeOnClickOutside,
referencePress: closeOnReferencePress,
});
const role = useRole(context, {
role: roleProp,
});
const clientPoint = useClientPoint(context, {
enabled: anchorPosition !== undefined,
x: anchorPosition === null || anchorPosition === void 0 ? void 0 : anchorPosition.x,
y: anchorPosition === null || anchorPosition === void 0 ? void 0 : anchorPosition.y,
});
const interactions = useInteractions([click, dismiss, role, clientPoint]);
const { styles: transitionStyles } = useTransitionStyles(context, {
duration: (_a = Number.parseInt(tokens.motion.duration.quick)) !== null && _a !== void 0 ? _a : 0,
});
return useMemo(() => (Object.assign(Object.assign(Object.assign({}, data), interactions), { anchorElementAsPortalAnchor,
descriptionId,
initialFocus,
isOpen,
isPortaled,
labelId,
returnFocus,
setDescriptionId,
setLabelId,
shouldCaptureFocus,
transitionStyles })), [
isOpen,
interactions,
data,
transitionStyles,
labelId,
descriptionId,
anchorElementAsPortalAnchor,
shouldCaptureFocus,
initialFocus,
isPortaled,
returnFocus,
]);
}
//# sourceMappingURL=use-popover.js.map