UNPKG

braid-design-system

Version:
197 lines (196 loc) • 6.57 kB
"use strict"; const react = require("react"); const entries_css_cjs = require("../../../css.cjs"); const lib_hooks_useIsomorphicLayoutEffect_cjs = require("../../hooks/useIsomorphicLayoutEffect.cjs"); const lib_utils_px_cjs = require("../../utils/px.cjs"); const lib_components_useToast_Toast_css_cjs = require("./Toast.css.cjs"); const animationTimeout = 200; const baseTransition = "opacity 0.2s ease, transform 0.2s ease, height 0.2s ease"; const exitTransition = "opacity 0.2s ease, height 0.2s ease"; const visibleStackedToasts = 3; const animate = (element, transforms, transition, done) => { const fallbackTimeout = setTimeout(() => { if (done) { done(); } }, animationTimeout); transforms.forEach(({ property, from = "" }) => { if (property === "className") { if (from) { element.classList.add(from); } } else { element.style.setProperty(property, from); } }); element.style.setProperty("transition", ""); const transitionEndHandler = (ev) => { if (ev.target !== element) { return; } element.style.setProperty("transition", ""); if (done) { done(); } element.removeEventListener("transitionend", transitionEndHandler); clearTimeout(fallbackTimeout); }; element.addEventListener("transitionend", transitionEndHandler); window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { element.style.setProperty("transition", transition); transforms.forEach(({ property, from = "", to = "" }) => { if (property === "className") { if (from) { element.classList.remove(from); } if (to) { element.classList.add(to); } } else { element.style.setProperty(property, to); } }); }); }); }; const useFlipList = (expanded) => { const refs = react.useMemo(() => /* @__PURE__ */ new Map(), []); const toastStates = react.useMemo(() => /* @__PURE__ */ new Map(), []); lib_hooks_useIsomorphicLayoutEffect_cjs.useIsomorphicLayoutEffect(() => { const animations = []; const getCurrentAndFullHeight = (element) => { const currentHeight = element.getBoundingClientRect().height; element.style.height = "auto"; const fullHeight = element.getBoundingClientRect().height; element.style.height = lib_utils_px_cjs.px(currentHeight); return { currentHeight, fullHeight }; }; const activeToasts = []; Array.from(refs.entries()).forEach(([toastKey, element]) => { if (element !== null) { if (toastStates.get(toastKey) === "exiting") { refs.delete(toastKey); } else { activeToasts.push([toastKey, element]); } } }); activeToasts.forEach(([toastKey, element], index) => { const position = activeToasts.length - index - 1; const { opacity, transform } = element.style; const { currentHeight, fullHeight } = getCurrentAndFullHeight(element); let animationState; if (position > 0) { animationState = expanded ? "expand" : "collapse"; } else if (toastStates.get(toastKey) !== "entered") { animationState = "enter"; } else { animationState = "become-first"; } switch (animationState) { case "expand": animations.push({ element, transition: baseTransition, transforms: [ { property: "height", from: lib_utils_px_cjs.px(currentHeight), to: lib_utils_px_cjs.px(fullHeight) }, { property: "transform", from: transform, to: void 0 }, { property: "opacity", from: opacity, to: "1" }, { property: "className", from: lib_components_useToast_Toast_css_cjs.collapsed, to: void 0 } ] }); break; case "collapse": const visible = position < visibleStackedToasts; const scale = position === 1 ? 0.9 : 0.8; animations.push({ element, transition: baseTransition, transforms: [ { property: "height", from: lib_utils_px_cjs.px(currentHeight), to: visible ? entries_css_cjs.vars.space.small : "0px" }, { property: "transform", from: transform, to: `scaleX(${scale})` }, { property: "opacity", from: opacity, to: visible ? "1" : "0" }, { property: "className", from: void 0, to: position > 0 ? lib_components_useToast_Toast_css_cjs.collapsed : void 0 } ] }); break; case "enter": animations.push({ element, transition: baseTransition, transforms: [ { property: "opacity", from: "0" }, { property: "height", from: "0px", to: lib_utils_px_cjs.px(fullHeight) } ] }); break; case "become-first": animations.push({ element, transition: baseTransition, transforms: [ { property: "height", from: lib_utils_px_cjs.px(currentHeight), to: lib_utils_px_cjs.px(fullHeight) }, { property: "transform", from: transform }, { property: "className", from: expanded ? lib_components_useToast_Toast_css_cjs.collapsed : void 0, to: void 0 } ] }); break; } toastStates.set(toastKey, "entered"); }); animations.forEach(({ element, transforms, transition }) => { animate(element, transforms, transition); }); }); const remove = react.useCallback( (toastKey, cb) => { const element = refs.get(toastKey); if (element) { toastStates.set(toastKey, "exiting"); animate( element, [ { property: "opacity", to: "0" }, { property: "height", from: element.style.height, to: "0px" } ], exitTransition, cb ); } }, [refs, toastStates] ); const itemRef = react.useCallback( (toastKey) => (ref) => { refs.set(toastKey, ref); }, [refs] ); return { itemRef, remove }; }; exports.useFlipList = useFlipList;