@ariakit/react-core
Version:
Ariakit React core
390 lines (357 loc) • 12.8 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true});
var _5XOEJL7Acjs = require('./5XOEJL7A.cjs');
var _ZVJRPAXYcjs = require('./ZVJRPAXY.cjs');
var _WULEED4Qcjs = require('./WULEED4Q.cjs');
var _OZM4QA2Vcjs = require('./OZM4QA2V.cjs');
var _7EQBAZ46cjs = require('./7EQBAZ46.cjs');
// src/popover/popover.tsx
var _misc = require('@ariakit/core/utils/misc');
var _dom = require('@floating-ui/dom');
var _react = require('react');
var _jsxruntime = require('react/jsx-runtime');
var TagName = "div";
function createDOMRect(x = 0, y = 0, width = 0, height = 0) {
if (typeof DOMRect === "function") {
return new DOMRect(x, y, width, height);
}
const rect = {
x,
y,
width,
height,
top: y,
right: x + width,
bottom: y + height,
left: x
};
return _7EQBAZ46cjs.__spreadProps.call(void 0, _7EQBAZ46cjs.__spreadValues.call(void 0, {}, rect), { toJSON: () => rect });
}
function getDOMRect(anchorRect) {
if (!anchorRect) return createDOMRect();
const { x, y, width, height } = anchorRect;
return createDOMRect(x, y, width, height);
}
function getAnchorElement(anchorElement, getAnchorRect) {
const contextElement = anchorElement || void 0;
return {
contextElement,
getBoundingClientRect: () => {
const anchor = anchorElement;
const anchorRect = getAnchorRect == null ? void 0 : getAnchorRect(anchor);
if (anchorRect || !anchor) {
return getDOMRect(anchorRect);
}
return anchor.getBoundingClientRect();
}
};
}
function isValidPlacement(flip2) {
return /^(?:top|bottom|left|right)(?:-(?:start|end))?$/.test(flip2);
}
function roundByDPR(value) {
const dpr = window.devicePixelRatio || 1;
return Math.round(value * dpr) / dpr;
}
function getOffsetMiddleware(arrowElement, props) {
return _dom.offset.call(void 0, ({ placement }) => {
var _a;
const arrowOffset = ((arrowElement == null ? void 0 : arrowElement.clientHeight) || 0) / 2;
const finalGutter = typeof props.gutter === "number" ? props.gutter + arrowOffset : (_a = props.gutter) != null ? _a : arrowOffset;
const hasAlignment = !!placement.split("-")[1];
return {
crossAxis: !hasAlignment ? props.shift : void 0,
mainAxis: finalGutter,
alignmentAxis: props.shift
};
});
}
function getFlipMiddleware(props) {
if (props.flip === false) return;
const fallbackPlacements = typeof props.flip === "string" ? props.flip.split(" ") : void 0;
_misc.invariant.call(void 0,
!fallbackPlacements || fallbackPlacements.every(isValidPlacement),
process.env.NODE_ENV !== "production" && "`flip` expects a spaced-delimited list of placements"
);
return _dom.flip.call(void 0, {
padding: props.overflowPadding,
fallbackPlacements
});
}
function getShiftMiddleware(props) {
if (!props.slide && !props.overlap) return;
return _dom.shift.call(void 0, {
mainAxis: props.slide,
crossAxis: props.overlap,
padding: props.overflowPadding,
limiter: _dom.limitShift.call(void 0, )
});
}
function getSizeMiddleware(props) {
return _dom.size.call(void 0, {
padding: props.overflowPadding,
apply({ elements, availableWidth, availableHeight, rects }) {
const wrapper = elements.floating;
const referenceWidth = Math.round(rects.reference.width);
availableWidth = Math.floor(availableWidth);
availableHeight = Math.floor(availableHeight);
wrapper.style.setProperty(
"--popover-anchor-width",
`${referenceWidth}px`
);
wrapper.style.setProperty(
"--popover-available-width",
`${availableWidth}px`
);
wrapper.style.setProperty(
"--popover-available-height",
`${availableHeight}px`
);
if (props.sameWidth) {
wrapper.style.width = `${referenceWidth}px`;
}
if (props.fitViewport) {
wrapper.style.maxWidth = `${availableWidth}px`;
wrapper.style.maxHeight = `${availableHeight}px`;
}
}
});
}
function getArrowMiddleware(arrowElement, props) {
if (!arrowElement) return;
return _dom.arrow.call(void 0, {
element: arrowElement,
padding: props.arrowPadding
});
}
var usePopover = _WULEED4Qcjs.createHook.call(void 0,
function usePopover2(_a) {
var _b = _a, {
store,
modal = false,
portal = !!modal,
preserveTabOrder = true,
autoFocusOnShow = true,
wrapperProps,
fixed = false,
flip: flip2 = true,
shift: shift2 = 0,
slide = true,
overlap = false,
sameWidth = false,
fitViewport = false,
gutter,
arrowPadding = 4,
overflowPadding = 8,
getAnchorRect,
updatePosition
} = _b, props = _7EQBAZ46cjs.__objRest.call(void 0, _b, [
"store",
"modal",
"portal",
"preserveTabOrder",
"autoFocusOnShow",
"wrapperProps",
"fixed",
"flip",
"shift",
"slide",
"overlap",
"sameWidth",
"fitViewport",
"gutter",
"arrowPadding",
"overflowPadding",
"getAnchorRect",
"updatePosition"
]);
const context = _ZVJRPAXYcjs.usePopoverProviderContext.call(void 0, );
store = store || context;
_misc.invariant.call(void 0,
store,
process.env.NODE_ENV !== "production" && "Popover must receive a `store` prop or be wrapped in a PopoverProvider component."
);
const arrowElement = store.useState("arrowElement");
const anchorElement = store.useState("anchorElement");
const disclosureElement = store.useState("disclosureElement");
const popoverElement = store.useState("popoverElement");
const contentElement = store.useState("contentElement");
const placement = store.useState("placement");
const mounted = store.useState("mounted");
const rendered = store.useState("rendered");
const defaultArrowElementRef = _react.useRef.call(void 0, null);
const [positioned, setPositioned] = _react.useState.call(void 0, false);
const { portalRef, domReady } = _OZM4QA2Vcjs.usePortalRef.call(void 0, portal, props.portalRef);
const getAnchorRectProp = _OZM4QA2Vcjs.useEvent.call(void 0, getAnchorRect);
const updatePositionProp = _OZM4QA2Vcjs.useEvent.call(void 0, updatePosition);
const hasCustomUpdatePosition = !!updatePosition;
_OZM4QA2Vcjs.useSafeLayoutEffect.call(void 0, () => {
if (!(popoverElement == null ? void 0 : popoverElement.isConnected)) return;
popoverElement.style.setProperty(
"--popover-overflow-padding",
`${overflowPadding}px`
);
const anchor = getAnchorElement(anchorElement, getAnchorRectProp);
const updatePosition2 = async () => {
if (!mounted) return;
if (!arrowElement) {
defaultArrowElementRef.current = defaultArrowElementRef.current || document.createElement("div");
}
const arrow2 = arrowElement || defaultArrowElementRef.current;
const middleware = [
getOffsetMiddleware(arrow2, { gutter, shift: shift2 }),
getFlipMiddleware({ flip: flip2, overflowPadding }),
getShiftMiddleware({ slide, shift: shift2, overlap, overflowPadding }),
getArrowMiddleware(arrow2, { arrowPadding }),
getSizeMiddleware({
sameWidth,
fitViewport,
overflowPadding
})
];
const pos = await _dom.computePosition.call(void 0, anchor, popoverElement, {
placement,
strategy: fixed ? "fixed" : "absolute",
middleware
});
store == null ? void 0 : store.setState("currentPlacement", pos.placement);
setPositioned(true);
const x = roundByDPR(pos.x);
const y = roundByDPR(pos.y);
Object.assign(popoverElement.style, {
top: "0",
left: "0",
transform: `translate3d(${x}px,${y}px,0)`
});
if (arrow2 && pos.middlewareData.arrow) {
const { x: arrowX, y: arrowY } = pos.middlewareData.arrow;
const side = pos.placement.split("-")[0];
const centerX = arrow2.clientWidth / 2;
const centerY = arrow2.clientHeight / 2;
const originX = arrowX != null ? arrowX + centerX : -centerX;
const originY = arrowY != null ? arrowY + centerY : -centerY;
popoverElement.style.setProperty(
"--popover-transform-origin",
{
top: `${originX}px calc(100% + ${centerY}px)`,
bottom: `${originX}px ${-centerY}px`,
left: `calc(100% + ${centerX}px) ${originY}px`,
right: `${-centerX}px ${originY}px`
}[side]
);
Object.assign(arrow2.style, {
left: arrowX != null ? `${arrowX}px` : "",
top: arrowY != null ? `${arrowY}px` : "",
[side]: "100%"
});
}
};
const update = async () => {
if (hasCustomUpdatePosition) {
await updatePositionProp({ updatePosition: updatePosition2 });
setPositioned(true);
} else {
await updatePosition2();
}
};
const cancelAutoUpdate = _dom.autoUpdate.call(void 0, anchor, popoverElement, update, {
// JSDOM doesn't support ResizeObserver
elementResize: typeof ResizeObserver === "function"
});
return () => {
setPositioned(false);
cancelAutoUpdate();
};
}, [
store,
rendered,
popoverElement,
arrowElement,
anchorElement,
popoverElement,
placement,
mounted,
domReady,
fixed,
flip2,
shift2,
slide,
overlap,
sameWidth,
fitViewport,
gutter,
arrowPadding,
overflowPadding,
getAnchorRectProp,
hasCustomUpdatePosition,
updatePositionProp
]);
_OZM4QA2Vcjs.useSafeLayoutEffect.call(void 0, () => {
if (!mounted) return;
if (!domReady) return;
if (!(popoverElement == null ? void 0 : popoverElement.isConnected)) return;
if (!(contentElement == null ? void 0 : contentElement.isConnected)) return;
const applyZIndex = () => {
popoverElement.style.zIndex = getComputedStyle(contentElement).zIndex;
};
applyZIndex();
let raf = requestAnimationFrame(() => {
raf = requestAnimationFrame(applyZIndex);
});
return () => cancelAnimationFrame(raf);
}, [mounted, domReady, popoverElement, contentElement]);
const position = fixed ? "fixed" : "absolute";
props = _OZM4QA2Vcjs.useWrapElement.call(void 0,
props,
(element) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
"div",
_7EQBAZ46cjs.__spreadProps.call(void 0, _7EQBAZ46cjs.__spreadValues.call(void 0, {}, wrapperProps), {
style: _7EQBAZ46cjs.__spreadValues.call(void 0, {
// https://floating-ui.com/docs/computeposition#initial-layout
position,
top: 0,
left: 0,
width: "max-content"
}, wrapperProps == null ? void 0 : wrapperProps.style),
ref: store == null ? void 0 : store.setPopoverElement,
children: element
})
),
[store, position, wrapperProps]
);
props = _OZM4QA2Vcjs.useWrapElement.call(void 0,
props,
(element) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _ZVJRPAXYcjs.PopoverScopedContextProvider, { value: store, children: element }),
[store]
);
props = _7EQBAZ46cjs.__spreadProps.call(void 0, _7EQBAZ46cjs.__spreadValues.call(void 0, {
// data-placing is not part of the public API. We're setting this here so
// we can wait for the popover to be positioned before other components
// move focus into it. For example, this attribute is observed by the
// Combobox component with the autoSelect behavior.
"data-placing": !positioned || void 0
}, props), {
style: _7EQBAZ46cjs.__spreadValues.call(void 0, {
position: "relative"
}, props.style)
});
props = _5XOEJL7Acjs.useDialog.call(void 0, _7EQBAZ46cjs.__spreadProps.call(void 0, _7EQBAZ46cjs.__spreadValues.call(void 0, {
store,
modal,
portal,
preserveTabOrder,
preserveTabOrderAnchor: disclosureElement || anchorElement,
autoFocusOnShow: positioned && autoFocusOnShow
}, props), {
portalRef
}));
return props;
}
);
var Popover = _5XOEJL7Acjs.createDialogComponent.call(void 0,
_WULEED4Qcjs.forwardRef.call(void 0, function Popover2(props) {
const htmlProps = usePopover(props);
return _WULEED4Qcjs.createElement.call(void 0, TagName, htmlProps);
}),
_ZVJRPAXYcjs.usePopoverProviderContext
);
exports.usePopover = usePopover; exports.Popover = Popover;