@1771technologies/lytenyte-pro
Version:
242 lines (241 loc) • 8.24 kB
JavaScript
import * as React from "react";
import { u as useLatestRef, s as shift, l as limitShift, a as size, b as arrow, h as hide, g as getSide, c as useFloating, d as useEnhancedEffect, e as autoUpdate, f as getAlignment, o as offset, i as flip } from "./proptypes-BjYr2nFr.js";
import { u as useDirection } from "./DirectionContext-DIPP5cAe.js";
function getLogicalSide(sideParam, renderedSide, isRtl) {
const isLogicalSideParam = sideParam === "inline-start" || sideParam === "inline-end";
const logicalRight = isRtl ? "inline-start" : "inline-end";
const logicalLeft = isRtl ? "inline-end" : "inline-start";
return {
top: "top",
right: isLogicalSideParam ? logicalRight : "right",
bottom: "bottom",
left: isLogicalSideParam ? logicalLeft : "left"
}[renderedSide];
}
function useAnchorPositioning(params) {
const {
// Public parameters
anchor,
positionMethod = "absolute",
side: sideParam = "bottom",
sideOffset = 0,
align = "center",
alignOffset = 0,
collisionBoundary,
collisionPadding = 5,
sticky = false,
arrowPadding = 5,
// Private parameters
keepMounted = false,
floatingRootContext,
mounted,
trackAnchor = true,
nodeId
} = params;
const direction = useDirection();
const isRtl = direction === "rtl";
const side = {
top: "top",
right: "right",
bottom: "bottom",
left: "left",
"inline-end": isRtl ? "left" : "right",
"inline-start": isRtl ? "right" : "left"
}[sideParam];
const placement = align === "center" ? side : `${side}-${align}`;
const commonCollisionProps = {
boundary: collisionBoundary === "clipping-ancestors" ? "clippingAncestors" : collisionBoundary,
padding: collisionPadding
};
const arrowRef = React.useRef(null);
const sideOffsetRef = useLatestRef(sideOffset);
const alignOffsetRef = useLatestRef(alignOffset);
const sideOffsetDep = typeof sideOffset !== "function" ? sideOffset : 0;
const alignOffsetDep = typeof alignOffset !== "function" ? alignOffset : 0;
const middleware = [offset(({
rects,
placement: currentPlacement
}) => {
const data = {
side: getLogicalSide(sideParam, getSide(currentPlacement), isRtl),
align: getAlignment(currentPlacement) || "center",
anchor: {
width: rects.reference.width,
height: rects.reference.height
},
positioner: {
width: rects.floating.width,
height: rects.floating.height
}
};
const sideAxis = typeof sideOffsetRef.current === "function" ? sideOffsetRef.current(data) : sideOffsetRef.current;
const alignAxis = typeof alignOffsetRef.current === "function" ? alignOffsetRef.current(data) : alignOffsetRef.current;
return {
mainAxis: sideAxis,
crossAxis: alignAxis,
alignmentAxis: alignAxis
};
}, [sideOffsetDep, alignOffsetDep, isRtl, sideParam])];
const flipMiddleware = flip(commonCollisionProps);
const shiftMiddleware = shift({
...commonCollisionProps,
crossAxis: sticky,
limiter: sticky ? void 0 : limitShift(() => {
if (!arrowRef.current) {
return {};
}
const {
height
} = arrowRef.current.getBoundingClientRect();
return {
offset: height / 2 + (typeof collisionPadding === "number" ? collisionPadding : 0)
};
})
});
if (align !== "center") {
middleware.push(flipMiddleware, shiftMiddleware);
} else {
middleware.push(shiftMiddleware, flipMiddleware);
}
middleware.push(size({
...commonCollisionProps,
apply({
elements: {
floating
},
rects: {
reference
},
availableWidth,
availableHeight
}) {
Object.entries({
"--available-width": `${availableWidth}px`,
"--available-height": `${availableHeight}px`,
"--anchor-width": `${reference.width}px`,
"--anchor-height": `${reference.height}px`
}).forEach(([key, value]) => {
floating.style.setProperty(key, value);
});
}
}), arrow(() => ({
// `transform-origin` calculations rely on an element existing. If the arrow hasn't been set,
// we'll create a fake element.
element: arrowRef.current || document.createElement("div"),
padding: arrowPadding
}), [arrowPadding]), hide(), {
name: "transformOrigin",
fn({
elements: elements2,
middlewareData: middlewareData2,
placement: renderedPlacement2
}) {
const currentRenderedSide = getSide(renderedPlacement2);
const arrowEl = arrowRef.current;
const arrowX = middlewareData2.arrow?.x ?? 0;
const arrowY = middlewareData2.arrow?.y ?? 0;
const arrowWidth = arrowEl?.clientWidth ?? 0;
const arrowHeight = arrowEl?.clientHeight ?? 0;
const transformX = arrowX + arrowWidth / 2;
const transformY = arrowY + arrowHeight / 2;
const transformOrigin = {
top: `${transformX}px calc(100% + ${sideOffset}px)`,
bottom: `${transformX}px ${-sideOffset}px`,
left: `calc(100% + ${sideOffset}px) ${transformY}px`,
right: `${-sideOffset}px ${transformY}px`
}[currentRenderedSide];
elements2.floating.style.setProperty("--transform-origin", transformOrigin);
return {};
}
});
let rootContext = floatingRootContext;
if (!mounted && floatingRootContext) {
rootContext = {
...floatingRootContext,
elements: {
reference: null,
floating: null,
domReference: null
}
};
}
const autoUpdateOptions = React.useMemo(() => ({
elementResize: trackAnchor && typeof ResizeObserver !== "undefined",
layoutShift: trackAnchor && typeof IntersectionObserver !== "undefined"
}), [trackAnchor]);
const {
refs,
elements,
floatingStyles,
middlewareData,
update,
placement: renderedPlacement,
context,
isPositioned
} = useFloating({
rootContext,
placement,
middleware,
strategy: positionMethod,
whileElementsMounted: keepMounted ? void 0 : (...args) => autoUpdate(...args, autoUpdateOptions),
nodeId
});
const registeredPositionReferenceRef = React.useRef(null);
useEnhancedEffect(() => {
if (!mounted) {
return;
}
const resolvedAnchor = typeof anchor === "function" ? anchor() : anchor;
if (resolvedAnchor) {
const unwrappedElement = isRef(resolvedAnchor) ? resolvedAnchor.current : resolvedAnchor;
refs.setPositionReference(unwrappedElement);
registeredPositionReferenceRef.current = unwrappedElement;
}
}, [mounted, refs, anchor]);
React.useEffect(() => {
if (!mounted) {
return;
}
if (typeof anchor === "function") {
return;
}
if (isRef(anchor) && anchor.current !== registeredPositionReferenceRef.current) {
refs.setPositionReference(anchor.current);
registeredPositionReferenceRef.current = anchor.current;
}
}, [mounted, refs, anchor]);
React.useEffect(() => {
if (keepMounted && mounted && elements.domReference && elements.floating) {
return autoUpdate(elements.domReference, elements.floating, update, autoUpdateOptions);
}
return void 0;
}, [keepMounted, mounted, elements, update, autoUpdateOptions]);
const renderedSide = getSide(renderedPlacement);
const logicalRenderedSide = getLogicalSide(sideParam, renderedSide, isRtl);
const renderedAlign = getAlignment(renderedPlacement) || "center";
const anchorHidden = Boolean(middlewareData.hide?.referenceHidden);
const arrowStyles = React.useMemo(() => ({
position: "absolute",
top: middlewareData.arrow?.y,
left: middlewareData.arrow?.x
}), [middlewareData.arrow]);
const arrowUncentered = middlewareData.arrow?.centerOffset !== 0;
return React.useMemo(() => ({
positionerStyles: floatingStyles,
arrowStyles,
arrowRef,
arrowUncentered,
side: logicalRenderedSide,
align: renderedAlign,
anchorHidden,
refs,
context,
isPositioned
}), [floatingStyles, arrowStyles, arrowRef, arrowUncentered, logicalRenderedSide, renderedAlign, anchorHidden, refs, context, isPositioned]);
}
function isRef(param) {
return param != null && "current" in param;
}
export {
useAnchorPositioning as u
};