react-floater
Version:
Floaters everywhere!
1,079 lines (1,063 loc) • 33.6 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.tsx
var src_exports = {};
__export(src_exports, {
default: () => ReactFloater
});
module.exports = __toCommonJS(src_exports);
var React8 = __toESM(require("react"));
var import_core = require("@popperjs/core");
var import_is_lite5 = __toESM(require("is-lite"));
var import_tree_changes_hook = __toESM(require("tree-changes-hook"));
// src/components/Floater/index.tsx
var React5 = __toESM(require("react"));
// src/components/Floater/Arrow.tsx
var React = __toESM(require("react"));
function FloaterArrow(props) {
const { arrowRef, placement, styles } = props;
const {
arrow: { color, display, length, position, spread }
} = styles;
const arrowStyles = { display, position };
let points;
let x = spread;
let y = length;
if (placement.startsWith("top")) {
points = `0,0 ${x / 2},${y} ${x},0`;
} else if (placement.startsWith("bottom")) {
points = `${x},${y} ${x / 2},0 0,${y}`;
} else if (placement.startsWith("left")) {
y = spread;
x = length;
points = `0,0 ${x},${y / 2} 0,${y}`;
} else if (placement.startsWith("right")) {
y = spread;
x = length;
points = `${x},${y} ${x},0 0,${y / 2}`;
}
return /* @__PURE__ */ React.createElement("span", { ref: arrowRef, className: "__floater__arrow", style: arrowStyles }, /* @__PURE__ */ React.createElement("svg", { height: y, version: "1.1", width: x, xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React.createElement("polygon", { fill: color, points })));
}
// src/components/Floater/Container.tsx
var React3 = __toESM(require("react"));
var import_is_lite = __toESM(require("is-lite"));
// src/components/Floater/CloseButton.tsx
var React2 = __toESM(require("react"));
function FloaterCloseButton({ onClick, styles }) {
const { color, height, width, ...style } = styles;
return /* @__PURE__ */ React2.createElement("button", { "aria-label": "close", onClick, style, type: "button" }, /* @__PURE__ */ React2.createElement(
"svg",
{
height: `${height}px`,
preserveAspectRatio: "xMidYMid",
version: "1.1",
viewBox: "0 0 18 18",
width: `${width}px`,
xmlns: "http://www.w3.org/2000/svg"
},
/* @__PURE__ */ React2.createElement("g", null, /* @__PURE__ */ React2.createElement(
"path",
{
d: "M8.13911129,9.00268191 L0.171521827,17.0258467 C-0.0498027049,17.248715 -0.0498027049,17.6098394 0.171521827,17.8327545 C0.28204354,17.9443526 0.427188206,17.9998706 0.572051765,17.9998706 C0.71714958,17.9998706 0.862013139,17.9443526 0.972581703,17.8327545 L9.0000937,9.74924618 L17.0276057,17.8327545 C17.1384085,17.9443526 17.2832721,17.9998706 17.4281356,17.9998706 C17.5729992,17.9998706 17.718097,17.9443526 17.8286656,17.8327545 C18.0499901,17.6098862 18.0499901,17.2487618 17.8286656,17.0258467 L9.86135722,9.00268191 L17.8340066,0.973848225 C18.0553311,0.750979934 18.0553311,0.389855532 17.8340066,0.16694039 C17.6126821,-0.0556467968 17.254037,-0.0556467968 17.0329467,0.16694039 L9.00042166,8.25611765 L0.967006424,0.167268345 C0.745681892,-0.0553188426 0.387317931,-0.0553188426 0.165993399,0.167268345 C-0.0553311331,0.390136635 -0.0553311331,0.751261038 0.165993399,0.974176179 L8.13920499,9.00268191 L8.13911129,9.00268191 Z",
fill: color
}
))
));
}
// src/components/Floater/Container.tsx
function FloaterContainer(props) {
const { content, footer, onClick, open, positionWrapper, showCloseButton, styles, title } = props;
const output = {
content: React3.isValidElement(content) ? content : /* @__PURE__ */ React3.createElement("div", { className: "__floater__content", style: styles.content }, content)
};
if (title) {
output.title = React3.isValidElement(title) ? title : /* @__PURE__ */ React3.createElement("div", { className: "__floater__title", style: styles.title }, title);
}
if (footer) {
output.footer = React3.isValidElement(footer) ? footer : /* @__PURE__ */ React3.createElement("div", { className: "__floater__footer", style: styles.footer }, footer);
}
if ((showCloseButton || positionWrapper) && !import_is_lite.default.boolean(open)) {
output.close = /* @__PURE__ */ React3.createElement(FloaterCloseButton, { onClick, styles: styles.close });
}
return /* @__PURE__ */ React3.createElement("div", { className: "__floater__container", style: styles.container }, output.close, output.title, output.content, output.footer);
}
// src/literals.ts
var POSITIONING_PROPS = ["position", "top", "right", "bottom", "left"];
var STATUS = {
INIT: "init",
IDLE: "idle",
RENDER: "render",
OPENING: "opening",
OPEN: "open",
CLOSING: "closing",
ERROR: "error"
};
// src/modules/helpers.ts
var React4 = __toESM(require("react"));
var import_deepmerge_ts = require("deepmerge-ts");
var import_is_lite2 = __toESM(require("is-lite"));
var portalId = "react-floater-portal";
function canUseDOM() {
return !!(typeof window !== "undefined" && window.document?.createElement);
}
function enhanceProps(props) {
return {
autoOpen: false,
debug: false,
disableFlip: false,
disableHoverToClick: false,
event: "click",
eventDelay: 0.4,
hideArrow: false,
offset: 15,
placement: "bottom",
showCloseButton: false,
styles: {},
target: null,
wrapperOptions: {
position: false
},
...props
};
}
function getFallbackPlacements(placement) {
if (placement.startsWith("left")) {
return ["top", "bottom"];
}
if (placement.startsWith("right")) {
return ["bottom", "top"];
}
return void 0;
}
function getModifiers(modifiers) {
const defaultOptions2 = {
flip: {
name: "flip",
enabled: true,
options: {
padding: 20
}
},
preventOverflow: {
name: "preventOverflow",
enabled: true,
options: {
padding: 10
}
}
};
return (0, import_deepmerge_ts.deepmerge)(defaultOptions2, modifiers ?? {});
}
function isFixed(el) {
if (!el) {
return false;
}
const { nodeName } = el;
if (nodeName === "BODY" || nodeName === "HTML") {
return false;
}
if (getComputedStyle(el).position === "fixed") {
return true;
}
return el.parentNode instanceof HTMLElement ? isFixed(el.parentNode) : false;
}
function isMobile() {
return "ontouchstart" in window && /Mobi/.test(navigator.userAgent);
}
function isValidElement3(object) {
return React4.isValidElement(object);
}
function log({ data, debug = false, title }) {
const logFn = console.log;
if (debug && title && data) {
console.groupCollapsed(
`%creact-floater: ${title}`,
"color: #9b00ff; font-weight: bold; font-size: 12px;"
);
if (Array.isArray(data)) {
data.forEach((d) => {
if (import_is_lite2.default.plainObject(d) && d.key) {
logFn.apply(console, [d.key, d.value]);
} else {
logFn.apply(console, [d]);
}
});
} else {
logFn.apply(console, [data]);
}
console.groupEnd();
}
}
function mergeModifier(modifier, customModifier) {
return (0, import_deepmerge_ts.deepmerge)(modifier, customModifier ?? {});
}
function off(element, eventType, handler, options = false) {
element.removeEventListener(eventType, handler, options);
}
function on(element, eventType, handler, options = false) {
element.addEventListener(eventType, handler, options);
}
function once(element, eventType, handler, options = false) {
let nextCB;
nextCB = (event) => {
handler(event);
off(element, eventType, nextCB);
};
on(element, eventType, nextCB, options);
}
function randomId() {
return `rf-${Math.round(Math.random() * 1e5)}`;
}
// src/components/Floater/index.tsx
function Floater(props) {
const {
component,
content,
floaterRef,
hideArrow,
id,
onClick: closeFn,
placement,
status,
styles
} = props;
const style = React5.useMemo(() => {
const {
arrow: { length },
floater,
floaterCentered,
floaterClosing,
floaterOpening,
floaterWithComponent
} = styles;
let element = { ...floater };
if (!hideArrow) {
if (placement.startsWith("top")) {
element.padding = `0 0 ${length}px`;
} else if (placement.startsWith("bottom")) {
element.padding = `${length}px 0 0`;
} else if (placement.startsWith("left")) {
element.padding = `0 ${length}px 0 0`;
} else if (placement.startsWith("right")) {
element.padding = `0 0 0 ${length}px`;
}
}
if (status === STATUS.CLOSING) {
element = { ...element, ...floaterClosing };
}
if (status === STATUS.OPENING || status === STATUS.OPEN) {
element = { ...element, ...floaterOpening };
}
if (placement === "center") {
element = { ...element, ...floaterCentered };
}
if (component) {
element = { ...element, ...floaterWithComponent };
}
return element;
}, [component, hideArrow, placement, status, styles]);
const shouldRender = ["render", "open", "opening", "closing"].includes(status);
const output = {};
const classes = ["__floater"];
const baseProps = { id, role: "tooltip" };
if (component) {
const componentProps = { closeFn, ...baseProps };
output.content = isValidElement3(component) ? React5.cloneElement(component, componentProps) : component(componentProps);
} else {
output.content = /* @__PURE__ */ React5.createElement(FloaterContainer, { ...props, content });
}
if (status === STATUS.OPEN) {
classes.push("__floater__open");
}
if (!hideArrow) {
output.arrow = /* @__PURE__ */ React5.createElement(FloaterArrow, { ...props });
}
if (!shouldRender) {
return null;
}
return /* @__PURE__ */ React5.createElement("div", { ref: floaterRef, style: { zIndex: styles.options.zIndex } }, /* @__PURE__ */ React5.createElement("div", { className: classes.join(" "), style, ...baseProps }, /* @__PURE__ */ React5.createElement("div", { className: "__floater__body" }, output.content, output.arrow)));
}
var Floater_default = React5.memo(Floater);
// src/components/Portal.tsx
var React6 = __toESM(require("react"));
var import_react_dom = require("react-dom");
var import_is_lite3 = __toESM(require("is-lite"));
// src/modules/hooks.ts
var import_react = require("react");
function useEffectOnce(effect) {
(0, import_react.useEffect)(effect, []);
}
function useMount(effect) {
useEffectOnce(effect);
}
function useSingleton(callback) {
const hasBeenCalled = (0, import_react.useRef)(false);
if (hasBeenCalled.current) {
return;
}
callback();
hasBeenCalled.current = true;
}
function useUnmount(fn) {
const fnRef = (0, import_react.useRef)(fn);
fnRef.current = fn;
useEffectOnce(() => () => fnRef.current());
}
function useUpdateEffect(effect, deps) {
const isFirst = (0, import_react.useRef)(true);
(0, import_react.useEffect)(() => {
if (!isFirst.current) {
effect();
}
}, deps);
if (isFirst.current) {
isFirst.current = false;
}
}
// src/components/Portal.tsx
function ReactFloaterPortal(props) {
const { children, hasChildren, internalId, placement, portalElement, target, zIndex } = props;
const node = React6.useRef(null);
const initialize = React6.useCallback(() => {
if (!canUseDOM()) {
return;
}
if (portalElement) {
node.current = import_is_lite3.default.string(portalElement) ? document.querySelector(portalElement) : portalElement;
}
if (!portalElement || !node.current) {
const portal = document.getElementById(portalId);
if (portal) {
const ids = portal.dataset.ids?.split(",").filter(Boolean) ?? [];
if (!ids.includes(internalId) && internalId) {
ids.push(internalId);
}
portal.dataset.ids = ids.join(",");
node.current = portal;
} else {
node.current = document.createElement("div");
node.current.id = portalId;
node.current.dataset.ids = internalId;
node.current.style.zIndex = `${zIndex}`;
document.body.appendChild(node.current);
}
}
if (!portalElement && !document.getElementById(portalId)) {
if (node.current) {
document.body.appendChild(node.current);
}
}
}, [internalId, portalElement, zIndex]);
useMount(() => {
if (!canUseDOM) {
return;
}
initialize();
});
React6.useEffect(() => {
initialize();
}, [initialize]);
useUnmount(() => {
if (!canUseDOM() || !node.current) {
return;
}
try {
if (node.current.id === portalId) {
const ids = node.current.dataset.ids?.split(",") ?? [];
if (ids.includes(internalId)) {
node.current.dataset.ids = ids.filter((id) => id !== internalId).join(",");
}
if (ids.length <= 1) {
document.body.removeChild(node.current);
node.current = null;
}
}
} catch {
node.current = null;
}
});
if (node.current) {
if (!hasChildren && !target && placement !== "center") {
return null;
}
return (0, import_react_dom.createPortal)(children, node.current);
}
return null;
}
// src/components/Wrapper.tsx
var React7 = __toESM(require("react"));
var import_is_lite4 = __toESM(require("is-lite"));
function FloaterWrapper(props) {
const {
childRef,
children,
id,
isControlled,
onClick,
onMount,
onMouseEnter,
onMouseLeave,
status,
style,
styles,
wrapperRef
} = props;
useMount(() => {
onMount();
});
let element;
const mergedStyles = {
...styles,
...style,
...React7.isValidElement(children) ? children.props.style : void 0
};
let wrapperProps = {
"aria-describedby": [STATUS.OPENING, STATUS.OPEN, STATUS.CLOSING].includes(
status
) ? id : void 0,
"data-id": id,
style: mergedStyles
};
if (!isControlled) {
wrapperProps = {
...wrapperProps,
onClick,
onMouseEnter,
onMouseLeave
};
}
if (children) {
if (React7.Children.count(children) === 1 && React7.isValidElement(children) && children.type !== React7.Fragment) {
if (import_is_lite4.default.function(children.type)) {
element = /* @__PURE__ */ React7.createElement("span", { ref: wrapperRef }, React7.cloneElement(React7.Children.only(children), {
innerRef: childRef,
...wrapperProps
}));
} else {
element = React7.cloneElement(React7.Children.only(children), {
ref: wrapperRef,
...wrapperProps
});
}
} else {
element = /* @__PURE__ */ React7.createElement("span", { ref: wrapperRef, ...wrapperProps }, children);
}
}
return element ?? null;
}
var Wrapper_default = React7.memo(FloaterWrapper);
// src/modules/styles.ts
var import_deepmerge_ts2 = require("deepmerge-ts");
var defaultOptions = {
zIndex: 100
};
function getStyles(styles) {
const { options = {}, ...rest } = styles ?? {};
return (0, import_deepmerge_ts2.deepmerge)(
{
arrow: {
color: "#fff",
display: "inline-flex",
length: 16,
position: "absolute",
spread: 32
},
close: {
backgroundColor: "transparent",
border: 0,
borderRadius: 0,
color: "#555",
fontSize: 0,
height: 15,
outline: "none",
padding: 10,
position: "absolute",
right: 0,
top: 0,
width: 15,
WebkitAppearance: "none"
},
container: {
backgroundColor: "#fff",
color: "#666",
minHeight: 60,
minWidth: 200,
padding: 20,
position: "relative",
zIndex: 10
},
content: {
fontSize: 15
},
footer: {
borderTop: "1px solid #ccc",
fontSize: 13,
marginTop: 10,
paddingTop: 5
},
floater: {
display: "inline-block",
filter: "drop-shadow(0 0 3px rgba(0, 0, 0, 0.3))",
maxWidth: 300,
opacity: 0,
position: "relative",
transition: "opacity 0.3s",
visibility: "hidden",
zIndex: options.zIndex
},
floaterCentered: {
left: "50%",
position: "fixed",
top: "50%",
transform: "translate(-50%, -50%)"
},
floaterClosing: {
opacity: 0,
visibility: "visible"
},
floaterOpening: {
opacity: 1,
visibility: "visible"
},
floaterWithComponent: {
maxWidth: "100%"
},
title: {
borderBottom: "1px solid #555",
color: "#555",
fontSize: 18,
marginBottom: 5,
paddingBottom: 6,
paddingRight: 18
},
wrapper: {
cursor: "help",
zIndex: options.zIndex
},
wrapperPosition: {
left: -1e3,
position: "absolute",
top: -1e3,
visibility: "hidden"
},
options: (0, import_deepmerge_ts2.deepmerge)(defaultOptions, options)
},
rest
);
}
// src/index.tsx
function ReactFloater(props) {
const {
autoOpen = false,
callback,
children,
component,
content,
debug = false,
disableFlip = false,
disableHoverToClick = false,
event = "click",
eventDelay = 0.4,
footer,
getPopper,
hideArrow = false,
id,
modifiers,
offset = 15,
open,
placement = "bottom",
portalElement,
showCloseButton = false,
style,
styles,
target,
title,
wrapperOptions
} = enhanceProps(props);
const [state, setState] = React8.useReducer(
(previousState, nextState) => ({
...previousState,
...nextState
}),
{
currentPlacement: placement,
positionWrapper: !!wrapperOptions?.position && !!target,
status: STATUS.INIT,
statusWrapper: STATUS.INIT
}
);
const arrowRef = React8.useRef(null);
const childRef = React8.useRef(null);
const eventDelayTimer = React8.useRef();
const floaterRef = React8.useRef(null);
const internalId = React8.useRef(randomId());
const isMounted = React8.useRef(false);
const popperRef = React8.useRef();
const stateRef = React8.useRef(state);
const wrapperPopper = React8.useRef();
const wrapperRef = React8.useRef(null);
const wrapperStyles = React8.useRef({});
const { currentPlacement, positionWrapper, status, statusWrapper } = state;
const { changed } = (0, import_tree_changes_hook.default)(state);
const { changed: changedProps } = (0, import_tree_changes_hook.default)(props);
const updateState = React8.useCallback(
(nextState, callback_) => {
if (isMounted.current) {
setState(nextState);
stateRef.current = { ...state, ...nextState };
if (callback_) {
callback_();
}
}
},
[setState, state]
);
const toggle = React8.useCallback(
(forceStatus) => {
let nextStatus = stateRef.current.status === STATUS.OPEN ? STATUS.CLOSING : STATUS.RENDER;
if (!import_is_lite5.default.undefined(forceStatus)) {
nextStatus = forceStatus;
}
updateState({
status: nextStatus,
statusWrapper: nextStatus === STATUS.CLOSING ? STATUS.RENDER : STATUS.IDLE
});
},
[updateState]
);
const targetElement = React8.useRef(() => {
if (!canUseDOM()) {
return null;
}
if (target) {
if (import_is_lite5.default.domElement(target)) {
return target;
}
return document.querySelector(target);
}
return childRef.current ?? wrapperRef.current;
});
const currentDebug = React8.useMemo(() => {
return canUseDOM() && (debug || !!window.ReactFloaterDebug);
}, [debug]);
const currentEvent = React8.useMemo(() => {
if (event === "hover" && isMobile() && !disableHoverToClick) {
return "click";
}
return event;
}, [disableHoverToClick, event]);
const currentStyles = React8.useMemo(() => {
const nextStyles = getStyles(styles);
const element = targetElement.current();
if (positionWrapper) {
let wrapperCurrentStyles;
if (status !== STATUS.IDLE) {
wrapperCurrentStyles = nextStyles.wrapperPosition;
} else if (statusWrapper === STATUS.RENDER) {
wrapperCurrentStyles = wrapperPopper.current?.state.styles;
}
nextStyles.wrapper = {
...nextStyles.wrapper,
...wrapperCurrentStyles
};
}
if (element) {
const targetStyles = window.getComputedStyle(element);
if (wrapperStyles.current) {
nextStyles.wrapper = {
...nextStyles.wrapper,
...wrapperStyles.current
};
} else if (!["relative", "static"].includes(targetStyles.position)) {
wrapperStyles.current = {};
if (!positionWrapper) {
POSITIONING_PROPS.forEach((d) => {
if (d === "position") {
wrapperStyles.current[d] = targetStyles[d];
} else {
wrapperStyles.current[d] = targetStyles[d];
}
});
nextStyles.wrapper = {
...nextStyles.wrapper,
...wrapperStyles.current
};
}
}
}
return nextStyles;
}, [positionWrapper, status, statusWrapper, styles]);
const initPopper = React8.useRef(() => {
const nextStatus = stateRef.current.status === STATUS.RENDER ? STATUS.OPENING : STATUS.IDLE;
const element = targetElement.current();
if (placement === "center") {
setTimeout(() => {
updateState({ status: nextStatus });
}, 100);
} else if (element) {
if (floaterRef.current) {
const { arrow, flip, offset: offsetModifier, ...rest } = getModifiers(modifiers);
popperRef.current = (0, import_core.createPopper)(element, floaterRef.current, {
placement,
strategy: isFixed(targetElement.current()) ? "fixed" : "absolute",
modifiers: [
mergeModifier(
{
name: "arrow",
enabled: !hideArrow,
options: {
element: arrowRef.current,
padding: 8
}
},
arrow
),
mergeModifier(
{
name: "flip",
enabled: !disableFlip,
options: {
altAxis: false,
fallbackPlacements: getFallbackPlacements(placement || "bottom")
}
},
flip
),
mergeModifier(
{
name: "offset",
enabled: true,
options: {
offset: [0, offset]
}
},
offsetModifier
),
{
name: "updatePlacement",
enabled: true,
phase: "afterWrite",
fn: ({ instance, state: popperState }) => {
if (popperState.placement !== stateRef.current.currentPlacement) {
popperRef.current = instance;
updateState({ currentPlacement: popperState.placement });
}
}
},
{
name: "applyArrowStyle",
enabled: true,
phase: "write",
fn: ({ state: popperState }) => {
const {
elements: { arrow: stateArrow },
placement: statePlacement
} = popperState;
if (stateArrow) {
if (statePlacement.startsWith("top")) {
stateArrow.style.bottom = "0px";
stateArrow.style.right = "";
} else if (statePlacement.startsWith("bottom")) {
stateArrow.style.top = "0px";
stateArrow.style.right = "";
} else if (statePlacement.startsWith("left")) {
stateArrow.style.right = "0px";
stateArrow.style.bottom = "";
} else if (statePlacement.startsWith("right")) {
stateArrow.style.left = "0px";
stateArrow.style.bottom = "";
}
}
}
},
...Object.values(rest)
],
onFirstUpdate: (popperState) => {
updateState({
currentPlacement: popperState.placement,
status: nextStatus
});
if (placement !== popperState.placement) {
setTimeout(() => {
popperRef.current?.forceUpdate();
});
}
}
});
if (getPopper && popperRef.current) {
getPopper(popperRef.current, "floater");
}
} else {
updateState({
status: STATUS.IDLE
});
}
if (wrapperRef.current && !wrapperPopper.current && stateRef.current.positionWrapper) {
const wrapperOffset = wrapperOptions?.offset ? wrapperOptions.offset : 0;
wrapperPopper.current = (0, import_core.createPopper)(element, wrapperRef.current, {
placement: wrapperOptions?.placement ?? placement,
modifiers: [
{
name: "arrow",
enabled: false
},
{
name: "offset",
options: {
offset: [0, wrapperOffset]
}
},
{
name: "flip",
enabled: false
}
],
onFirstUpdate: (popperState) => {
updateState({ statusWrapper: STATUS.RENDER });
if (placement !== popperState.placement) {
setTimeout(() => {
wrapperPopper.current?.forceUpdate();
});
}
}
});
if (getPopper) {
getPopper(wrapperPopper.current, "wrapper");
}
}
}
});
const handleLoad = React8.useRef(() => {
if (popperRef.current) {
popperRef.current.forceUpdate();
}
if (wrapperPopper.current) {
wrapperPopper.current.forceUpdate();
}
});
const handleTransitionEnd = React8.useRef(() => {
if (wrapperPopper.current) {
wrapperPopper.current.forceUpdate();
}
updateState(
{
status: stateRef.current.status === STATUS.OPENING ? STATUS.OPEN : STATUS.IDLE
},
() => {
if (callback) {
callback(stateRef.current.status === STATUS.OPEN ? "open" : "close", enhanceProps(props));
}
}
);
});
const handleClick = React8.useCallback(() => {
if (import_is_lite5.default.boolean(open)) {
return;
}
if (currentEvent === "click" || currentEvent === "hover" && positionWrapper) {
log({
title: "click",
data: [{ event, status: status === STATUS.OPEN ? "closing" : "opening" }],
debug: currentDebug
});
toggle(status === "idle" ? STATUS.RENDER : void 0);
}
}, [currentDebug, currentEvent, event, open, positionWrapper, status, toggle]);
const handleMouseEnter = React8.useCallback(() => {
if (import_is_lite5.default.boolean(open) || isMobile() || currentEvent !== "hover") {
return;
}
log({
title: "mouseEnter",
data: [{ key: "originalEvent", value: event }],
debug: currentDebug
});
if (status === STATUS.IDLE) {
clearTimeout(eventDelayTimer.current);
eventDelayTimer.current = void 0;
toggle(STATUS.RENDER);
}
}, [currentDebug, currentEvent, event, open, status, toggle]);
const handleMouseLeave = React8.useCallback(() => {
if (import_is_lite5.default.boolean(open) || isMobile()) {
return;
}
if (currentEvent === "hover") {
log({
title: "mouseLeave",
data: [{ key: "originalEvent", value: event }],
debug: currentDebug
});
const hasOpenStatus = [STATUS.OPENING, STATUS.OPEN].includes(status);
if (!eventDelay) {
toggle(status === STATUS.CLOSING ? STATUS.IDLE : STATUS.CLOSING);
} else if (!positionWrapper) {
if (hasOpenStatus) {
clearTimeout(eventDelayTimer.current);
eventDelayTimer.current = window.setTimeout(() => {
toggle();
eventDelayTimer.current = void 0;
}, eventDelay * 1e3);
}
}
}
}, [currentDebug, currentEvent, event, eventDelay, open, positionWrapper, status, toggle]);
const handleWrapperMount = React8.useCallback(() => {
if (positionWrapper) {
initPopper.current();
}
}, [positionWrapper]);
const cleanUp = () => {
if (popperRef.current) {
popperRef.current.destroy();
popperRef.current = void 0;
}
if (wrapperPopper.current) {
wrapperPopper.current.destroy();
wrapperPopper.current = void 0;
}
};
useSingleton(() => {
if (canUseDOM()) {
window.addEventListener("load", handleLoad.current);
}
});
useMount(() => {
isMounted.current = true;
log({
title: "init",
data: {
hasChildren: !!children,
hasTarget: !!target,
isControlled: import_is_lite5.default.boolean(open),
positionWrapper,
target: targetElement.current(),
floater: floaterRef.current
},
debug: currentDebug
});
initPopper.current();
});
useUnmount(() => {
isMounted.current = false;
cleanUp();
window.removeEventListener("load", handleLoad.current);
});
useUpdateEffect(() => {
if (!canUseDOM()) {
return;
}
if (changedProps("open")) {
let forceStatus;
if (import_is_lite5.default.boolean(open)) {
forceStatus = open ? STATUS.RENDER : STATUS.CLOSING;
}
toggle(forceStatus);
}
if (changedProps("wrapperOptions.position") || changedProps("target")) {
updateState({
positionWrapper: !!wrapperOptions?.position && !!target
});
}
if (changed("status", STATUS.IDLE) && open || changed("status", STATUS.IDLE, STATUS.INIT) && autoOpen) {
toggle(STATUS.RENDER);
}
if (changed("status", STATUS.RENDER)) {
if (popperRef.current) {
popperRef.current.destroy();
}
initPopper.current();
}
if (floaterRef.current && changed("status", [STATUS.RENDER, STATUS.CLOSING])) {
once(floaterRef.current, "transitionend", handleTransitionEnd.current);
}
if (changed("status", STATUS.IDLE, STATUS.CLOSING) && popperRef.current) {
popperRef.current.destroy();
popperRef.current = void 0;
if (wrapperPopper.current) {
wrapperPopper.current.forceUpdate();
}
}
});
const wrapper = /* @__PURE__ */ React8.createElement(
Wrapper_default,
{
childRef,
id: id ?? internalId.current,
isControlled: import_is_lite5.default.boolean(open),
onClick: handleClick,
onMount: handleWrapperMount,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
status,
style,
styles: currentStyles.wrapper,
wrapperRef
},
children
);
return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(
ReactFloaterPortal,
{
hasChildren: !!children,
internalId: internalId.current,
placement: currentPlacement,
portalElement,
target,
zIndex: currentStyles.options.zIndex
},
/* @__PURE__ */ React8.createElement(
Floater_default,
{
arrowRef,
component,
content,
floaterRef,
footer,
hideArrow: hideArrow || currentPlacement === "center",
id: id ?? internalId.current,
onClick: handleClick,
placement: currentPlacement,
positionWrapper,
showCloseButton,
status,
styles: currentStyles,
title
}
),
positionWrapper && wrapper
), !positionWrapper && wrapper);
}
//# sourceMappingURL=index.js.map
// fix-cjs-exports
if (module.exports.default) {
Object.assign(module.exports.default, module.exports);
module.exports = module.exports.default;
delete module.exports.default;
}