@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
208 lines (204 loc) • 6.37 kB
JavaScript
"use client";
import { useUpdateEffect } from "../../utils/effect.js";
import { utils_exports } from "../../utils/index.js";
import { varAttr } from "../../core/system/var.js";
import { createSlotComponent } from "../../core/components/create-component.js";
import { motion as motion$1 } from "../motion/factory.js";
import { createTransition } from "../motion/transition.js";
import { useTimeout } from "../../hooks/use-timeout/index.js";
import { AlertDescription, AlertIcon, AlertLoading, AlertRoot, AlertTitle } from "../alert/alert.js";
import { CloseButton } from "../close-button/close-button.js";
import { snacksStyle } from "./snacks.style.js";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
import { AnimatePresence, useIsPresent } from "motion/react";
//#region src/components/snacks/snacks.tsx
const { ComponentContext, PropsContext: SnacksPropsContext, useComponentContext, usePropsContext: useSnacksPropsContext, withContext, withProvider } = createSlotComponent("snacks", snacksStyle);
const Snacks = withProvider(({ snacks: { direction = "start", items, startIndex = 0 }, listProps,...rest }) => {
const count = items.length;
const elMapRef = useRef(/* @__PURE__ */ new Map());
const [height, setHeight] = useState(0);
const [exist, setExist] = useState(!!count);
const show = !!count || exist;
const context = useMemo(() => ({
direction,
elMapRef,
setExist,
startIndex
}), [direction, startIndex]);
const onExitComplete = useCallback(() => {
if (!count) setExist(false);
}, [count]);
useEffect(() => {
let height$1 = 0;
if (!count) return;
const els = [...elMapRef.current.values()].slice(0, count);
for (const el of els) {
if (!el) continue;
let { offsetHeight, offsetTop } = el;
offsetHeight += offsetTop;
if (offsetHeight > height$1) height$1 = offsetHeight;
}
setHeight(height$1);
}, [count, direction]);
useUpdateEffect(() => {
if (!!count) setExist(true);
}, [count]);
return /* @__PURE__ */ jsx(ComponentContext, {
value: context,
children: /* @__PURE__ */ jsx(AnimatePresence, {
initial: false,
children: show ? /* @__PURE__ */ jsx(motion$1.div, {
...rest,
children: /* @__PURE__ */ jsx(SnackList, {
custom: { height },
...listProps,
children: /* @__PURE__ */ jsx(AnimatePresence, {
onExitComplete,
children: items.map((props, index) => {
return /* @__PURE__ */ jsx(Snack, {
index,
lastIndex: count - index - 1,
...props
}, props.id);
})
})
})
}) : null
})
});
}, "root")({
animate: "animate",
exit: "exit",
initial: "initial",
variants: {
animate: {
padding: "var(--top) 0 var(--bottom)",
transition: { duration: .4 }
},
exit: { padding: 0 },
initial: { padding: 0 }
}
}, ({ gap, gutter = [0, "lg"], negativeMargins = true,...rest }) => ({
"data-negative": (0, utils_exports.dataAttr)(negativeMargins),
"--bottom": varAttr(gutter[1], "spaces", "0px"),
"--gap": varAttr(gap, "spaces"),
"--top": varAttr(gutter[0], "spaces", "0px"),
...rest
}));
const SnackList = withContext(motion$1.div, "list")({
animate: "animate",
exit: "exit",
initial: "initial",
role: "list",
variants: {
animate: ({ height }) => ({
height,
opacity: 1,
transition: { duration: .4 }
}),
exit: {
height: 0,
opacity: 0
},
initial: {
height: 0,
opacity: 1
}
}
});
const Snack = withContext(({ variant = "plain", closable = true, description, duration: durationProp = null, loadingScheme, status, title, withIcon = true, closeButtonProps, contentProps, descriptionProps, iconProps, loadingProps, titleProps, onClose: onCloseProp, onCloseComplete,...rest }) => {
const [duration, setDuration] = useState(durationProp);
const present = useIsPresent();
const onClose = present ? onCloseProp : utils_exports.noop;
const onMouseEnter = useCallback(() => {
setDuration(null);
}, []);
const onMouseLeave = useCallback(() => {
setDuration(durationProp);
}, [durationProp]);
useUpdateEffect(() => {
if (!present) onCloseComplete?.();
}, [present]);
useUpdateEffect(() => {
setDuration(durationProp);
}, [durationProp]);
useTimeout(onClose, duration);
return /* @__PURE__ */ jsxs(AlertRoot, {
as: motion$1.div,
variant,
status,
...rest,
onMouseEnter: (0, utils_exports.handlerAll)(rest.onMouseEnter, onMouseEnter),
onMouseLeave: (0, utils_exports.handlerAll)(rest.onMouseLeave, onMouseLeave),
children: [
withIcon ? loadingScheme ? /* @__PURE__ */ jsx(AlertLoading, {
loadingScheme,
...loadingProps
}) : /* @__PURE__ */ jsx(AlertIcon, { ...iconProps }) : null,
/* @__PURE__ */ jsxs(SnackContent, {
"data-close-button": (0, utils_exports.dataAttr)(closable),
...contentProps,
children: [title ? /* @__PURE__ */ jsx(AlertTitle, {
me: "0",
...titleProps,
children: title
}) : null, description ? /* @__PURE__ */ jsx(AlertDescription, {
...descriptionProps,
children: description
}) : null]
}),
closable ? /* @__PURE__ */ jsx(SnackCloseButton, {
"data-variant": variant,
...closeButtonProps,
onClick: (0, utils_exports.handlerAll)(closeButtonProps?.onClick, onClose)
}) : null
]
});
}, "item")({
animate: "animate",
exit: "exit",
initial: "initial",
layout: true,
role: "listitem",
variants: {
animate: ({ index }) => ({
opacity: 1,
transition: createTransition.enter()(!index ? .2 : 0, .4),
y: 0
}),
exit: {
opacity: 0,
transition: createTransition.exit()(void 0, .2)
},
initial: ({ direction, index }) => ({
opacity: 0,
...index ? { y: (direction === "start" ? -1 : 1) * 16 } : {}
})
}
}, ({ index, lastIndex,...rest }) => {
const ref = useRef(null);
const { direction, elMapRef, startIndex } = useComponentContext();
useEffect(() => {
const elMap = elMapRef.current;
elMap.set(index, ref.current);
return () => {
elMap.delete(index);
};
}, [elMapRef, index]);
return {
ref,
"--index": direction === "start" ? lastIndex : index,
"--z-index": startIndex + index,
custom: {
direction,
index
},
...rest
};
});
const SnackContent = withContext("div", "content")();
const SnackCloseButton = withContext(CloseButton, "closeButton")();
//#endregion
export { Snacks };
//# sourceMappingURL=snacks.js.map