233 lines
10 KiB
JavaScript
233 lines
10 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
Object.defineProperty(exports, "usePositioning", {
|
||
|
enumerable: true,
|
||
|
get: function() {
|
||
|
return usePositioning;
|
||
|
}
|
||
|
});
|
||
|
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
||
|
const _dom = require("@floating-ui/dom");
|
||
|
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
|
||
|
const _reactutilities = require("@fluentui/react-utilities");
|
||
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
||
|
const _utils = require("./utils");
|
||
|
const _middleware = require("./middleware");
|
||
|
const _createPositionManager = require("./createPositionManager");
|
||
|
const _devtools = require("@floating-ui/devtools");
|
||
|
const _devtools1 = require("./utils/devtools");
|
||
|
const _constants = require("./constants");
|
||
|
function usePositioning(options) {
|
||
|
'use no memo';
|
||
|
const managerRef = _react.useRef(null);
|
||
|
const targetRef = _react.useRef(null);
|
||
|
const overrideTargetRef = _react.useRef(null);
|
||
|
const containerRef = _react.useRef(null);
|
||
|
const arrowRef = _react.useRef(null);
|
||
|
const { enabled = true } = options;
|
||
|
const resolvePositioningOptions = usePositioningOptions(options);
|
||
|
const updatePositionManager = _react.useCallback(()=>{
|
||
|
if (managerRef.current) {
|
||
|
managerRef.current.dispose();
|
||
|
}
|
||
|
managerRef.current = null;
|
||
|
var _overrideTargetRef_current;
|
||
|
const target = (_overrideTargetRef_current = overrideTargetRef.current) !== null && _overrideTargetRef_current !== void 0 ? _overrideTargetRef_current : targetRef.current;
|
||
|
if (enabled && (0, _reactutilities.canUseDOM)() && target && containerRef.current) {
|
||
|
managerRef.current = (0, _createPositionManager.createPositionManager)({
|
||
|
container: containerRef.current,
|
||
|
target,
|
||
|
arrow: arrowRef.current,
|
||
|
...resolvePositioningOptions(containerRef.current, arrowRef.current)
|
||
|
});
|
||
|
}
|
||
|
}, [
|
||
|
enabled,
|
||
|
resolvePositioningOptions
|
||
|
]);
|
||
|
const setOverrideTarget = (0, _reactutilities.useEventCallback)((target)=>{
|
||
|
overrideTargetRef.current = target;
|
||
|
updatePositionManager();
|
||
|
});
|
||
|
_react.useImperativeHandle(options.positioningRef, ()=>({
|
||
|
updatePosition: ()=>{
|
||
|
var _managerRef_current;
|
||
|
return (_managerRef_current = managerRef.current) === null || _managerRef_current === void 0 ? void 0 : _managerRef_current.updatePosition();
|
||
|
},
|
||
|
setTarget: (target)=>{
|
||
|
if (options.target && process.env.NODE_ENV !== 'production') {
|
||
|
const err = new Error();
|
||
|
// eslint-disable-next-line no-console
|
||
|
console.warn('Imperative setTarget should not be used at the same time as target option');
|
||
|
// eslint-disable-next-line no-console
|
||
|
console.warn(err.stack);
|
||
|
}
|
||
|
setOverrideTarget(target);
|
||
|
}
|
||
|
}), [
|
||
|
options.target,
|
||
|
setOverrideTarget
|
||
|
]);
|
||
|
(0, _reactutilities.useIsomorphicLayoutEffect)(()=>{
|
||
|
var _options_target;
|
||
|
setOverrideTarget((_options_target = options.target) !== null && _options_target !== void 0 ? _options_target : null);
|
||
|
}, [
|
||
|
options.target,
|
||
|
setOverrideTarget
|
||
|
]);
|
||
|
(0, _reactutilities.useIsomorphicLayoutEffect)(()=>{
|
||
|
updatePositionManager();
|
||
|
}, [
|
||
|
updatePositionManager
|
||
|
]);
|
||
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
// This checked should run only in development mode
|
||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||
|
_react.useEffect(()=>{
|
||
|
if (containerRef.current) {
|
||
|
var _contentNode_ownerDocument;
|
||
|
const contentNode = containerRef.current;
|
||
|
const treeWalker = (_contentNode_ownerDocument = contentNode.ownerDocument) === null || _contentNode_ownerDocument === void 0 ? void 0 : _contentNode_ownerDocument.createTreeWalker(contentNode, NodeFilter.SHOW_ELEMENT, {
|
||
|
acceptNode: _utils.hasAutofocusFilter
|
||
|
});
|
||
|
while(treeWalker.nextNode()){
|
||
|
const node = treeWalker.currentNode;
|
||
|
// eslint-disable-next-line no-console
|
||
|
console.warn('<Popper>:', node);
|
||
|
// eslint-disable-next-line no-console
|
||
|
console.warn([
|
||
|
'<Popper>: ^ this node contains "autoFocus" prop on a React element. This can break the initial',
|
||
|
'positioning of an element and cause a window jump effect. This issue occurs because React polyfills',
|
||
|
'"autoFocus" behavior to solve inconsistencies between different browsers:',
|
||
|
'https://github.com/facebook/react/issues/11851#issuecomment-351787078',
|
||
|
'\n',
|
||
|
'However, ".focus()" in this case occurs before any other React effects will be executed',
|
||
|
'(React.useEffect(), componentDidMount(), etc.) and we can not prevent this behavior. If you really',
|
||
|
'want to use "autoFocus" please add "position: fixed" to styles of the element that is wrapped by',
|
||
|
'"Popper".',
|
||
|
`In general, it's not recommended to use "autoFocus" as it may break accessibility aspects:`,
|
||
|
'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md',
|
||
|
'\n',
|
||
|
'We suggest to use the "trapFocus" prop on Fluent components or a catch "ref" and then use',
|
||
|
'"ref.current.focus" in React.useEffect():',
|
||
|
'https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-dom-element'
|
||
|
].join(' '));
|
||
|
}
|
||
|
}
|
||
|
// We run this check once, no need to add deps here
|
||
|
// TODO: Should be rework to handle options.enabled and contentRef updates
|
||
|
}, []);
|
||
|
}
|
||
|
const setTarget = (0, _utils.useCallbackRef)(null, (target)=>{
|
||
|
if (targetRef.current !== target) {
|
||
|
targetRef.current = target;
|
||
|
updatePositionManager();
|
||
|
}
|
||
|
});
|
||
|
const onPositioningEnd = (0, _reactutilities.useEventCallback)(()=>{
|
||
|
var _options_onPositioningEnd;
|
||
|
return (_options_onPositioningEnd = options.onPositioningEnd) === null || _options_onPositioningEnd === void 0 ? void 0 : _options_onPositioningEnd.call(options);
|
||
|
});
|
||
|
const setContainer = (0, _utils.useCallbackRef)(null, (container)=>{
|
||
|
if (containerRef.current !== container) {
|
||
|
var _containerRef_current;
|
||
|
(_containerRef_current = containerRef.current) === null || _containerRef_current === void 0 ? void 0 : _containerRef_current.removeEventListener(_constants.POSITIONING_END_EVENT, onPositioningEnd);
|
||
|
container === null || container === void 0 ? void 0 : container.addEventListener(_constants.POSITIONING_END_EVENT, onPositioningEnd);
|
||
|
containerRef.current = container;
|
||
|
updatePositionManager();
|
||
|
}
|
||
|
});
|
||
|
const setArrow = (0, _utils.useCallbackRef)(null, (arrow)=>{
|
||
|
if (arrowRef.current !== arrow) {
|
||
|
arrowRef.current = arrow;
|
||
|
updatePositionManager();
|
||
|
}
|
||
|
});
|
||
|
// Let users use callback refs so they feel like 'normal' DOM refs
|
||
|
return {
|
||
|
targetRef: setTarget,
|
||
|
containerRef: setContainer,
|
||
|
arrowRef: setArrow
|
||
|
};
|
||
|
}
|
||
|
function usePositioningOptions(options) {
|
||
|
'use no memo';
|
||
|
const { align, arrowPadding, autoSize: rawAutoSize, coverTarget, flipBoundary, offset, overflowBoundary, pinned, position, unstable_disableTether: disableTether, positionFixed, strategy, overflowBoundaryPadding, fallbackPositions, useTransform, matchTargetSize, disableUpdateOnResize = false } = options;
|
||
|
const { dir, targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
|
||
|
const isRtl = dir === 'rtl';
|
||
|
const positionStrategy = (strategy !== null && strategy !== void 0 ? strategy : positionFixed) ? 'fixed' : 'absolute';
|
||
|
const autoSize = (0, _utils.normalizeAutoSize)(rawAutoSize);
|
||
|
return _react.useCallback((container, arrow)=>{
|
||
|
const hasScrollableElement = (0, _utils.hasScrollParent)(container);
|
||
|
const middleware = [
|
||
|
autoSize && (0, _middleware.resetMaxSize)(autoSize),
|
||
|
matchTargetSize && (0, _middleware.matchTargetSize)(),
|
||
|
offset && (0, _middleware.offset)(offset),
|
||
|
coverTarget && (0, _middleware.coverTarget)(),
|
||
|
!pinned && (0, _middleware.flip)({
|
||
|
container,
|
||
|
flipBoundary,
|
||
|
hasScrollableElement,
|
||
|
isRtl,
|
||
|
fallbackPositions
|
||
|
}),
|
||
|
(0, _middleware.shift)({
|
||
|
container,
|
||
|
hasScrollableElement,
|
||
|
overflowBoundary,
|
||
|
disableTether,
|
||
|
overflowBoundaryPadding,
|
||
|
isRtl
|
||
|
}),
|
||
|
autoSize && (0, _middleware.maxSize)(autoSize, {
|
||
|
container,
|
||
|
overflowBoundary,
|
||
|
overflowBoundaryPadding,
|
||
|
isRtl
|
||
|
}),
|
||
|
(0, _middleware.intersecting)(),
|
||
|
arrow && (0, _dom.arrow)({
|
||
|
element: arrow,
|
||
|
padding: arrowPadding
|
||
|
}),
|
||
|
(0, _dom.hide)({
|
||
|
strategy: 'referenceHidden'
|
||
|
}),
|
||
|
(0, _dom.hide)({
|
||
|
strategy: 'escaped'
|
||
|
}),
|
||
|
process.env.NODE_ENV !== 'production' && targetDocument && (0, _devtools.devtools)(targetDocument, (0, _devtools1.devtoolsCallback)(options))
|
||
|
].filter(Boolean);
|
||
|
const placement = (0, _utils.toFloatingUIPlacement)(align, position, isRtl);
|
||
|
return {
|
||
|
placement,
|
||
|
middleware,
|
||
|
strategy: positionStrategy,
|
||
|
useTransform,
|
||
|
disableUpdateOnResize
|
||
|
};
|
||
|
}, // eslint-disable-next-line react-hooks/exhaustive-deps
|
||
|
[
|
||
|
align,
|
||
|
arrowPadding,
|
||
|
autoSize,
|
||
|
coverTarget,
|
||
|
disableTether,
|
||
|
flipBoundary,
|
||
|
isRtl,
|
||
|
offset,
|
||
|
overflowBoundary,
|
||
|
pinned,
|
||
|
position,
|
||
|
positionStrategy,
|
||
|
overflowBoundaryPadding,
|
||
|
fallbackPositions,
|
||
|
useTransform,
|
||
|
matchTargetSize,
|
||
|
targetDocument,
|
||
|
disableUpdateOnResize
|
||
|
]);
|
||
|
}
|