UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

299 lines (298 loc) 7.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true, }); function _export(target, all) { for (var name in all) Object.defineProperty(target, name, { enumerable: true, get: all[name], }); } _export(exports, { Toast: function () { return Toast; }, ToastPresentation: function () { return ToastPresentation; }, }); const _interop_require_default = require('@swc/helpers/_/_interop_require_default'); const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard'); const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react')); const _classnames = /*#__PURE__*/ _interop_require_default._( require('classnames'), ); const _index = require('../../utils/index.js'); const _IconButton = require('../Buttons/IconButton.js'); const _Toaster = require('./Toaster.js'); const Toast = (props) => { let { content, category, type = 'temporary', isVisible: isVisibleProp, link, duration = 7000, hasCloseButton, onRemove, animateOutTo, domProps, } = props; let closeTimeout = _react.useRef(0); let { placement } = (0, _index.useSafeContext)( _Toaster.ToasterStateContext, ).settings; let placementPosition = placement.startsWith('top') ? 'top' : 'bottom'; let [visible, setVisible] = _react.useState(isVisibleProp ?? true); let isVisible = isVisibleProp ?? visible; let [height, setHeight] = _react.useState(0); let thisElement = _react.useRef(null); let [margin, setMargin] = _react.useState(0); let marginStyle = () => { if ('top' === placementPosition) return { marginBlockEnd: margin, }; return { marginBlockStart: margin, }; }; _react.useEffect(() => { if ('temporary' === type) setCloseTimeout(duration); return () => { clearCloseTimeout(); }; }, [duration, type]); _react.useEffect(() => { if (!isVisible && !animateOutTo) setMargin(-height); }, [isVisible, animateOutTo, setMargin, height]); let close = () => { clearCloseTimeout(); setMargin(-height); setVisible(false); }; let setCloseTimeout = (timeout) => { let definedWindow = (0, _index.getWindow)(); if (!definedWindow) return; closeTimeout.current = definedWindow.setTimeout(() => { close(); }, timeout); }; let clearCloseTimeout = () => { (0, _index.getWindow)()?.clearTimeout(closeTimeout.current); }; let onRef = (ref) => { if (ref) { let { height } = ref.getBoundingClientRect(); setHeight(height); } }; let shouldBeMounted = useAnimateToastBasedOnVisibility(isVisible, { thisElement, animateOutTo, onRemove, }); return shouldBeMounted ? _react.createElement( _index.Box, { ref: thisElement, className: 'iui-toast-all', style: { height, ...marginStyle(), }, }, _react.createElement( 'div', { ref: onRef, }, _react.createElement(ToastPresentation, { as: 'div', category: category, content: content, link: link, type: type, hasCloseButton: hasCloseButton, onClose: close, ...domProps?.toastProps, contentProps: domProps?.contentProps, }), ), ) : null; }; const ToastPresentation = _react.forwardRef((props, forwardedRef) => { let { content, category, type = 'temporary', link, hasCloseButton, onClose, className, contentProps, ...rest } = props; let StatusIcon = _index.StatusIconMap[category]; return _react.createElement( _index.Box, { className: (0, _classnames.default)( `iui-toast iui-${category}`, className, ), ref: forwardedRef, ...rest, }, _react.createElement( _index.Box, { className: 'iui-status-area', }, _react.createElement(StatusIcon, { className: 'iui-icon', }), ), _react.createElement( _index.Box, { as: 'div', ...contentProps, className: (0, _classnames.default)( 'iui-message', contentProps?.className, ), }, content, ), link && _react.createElement( _index.ButtonBase, { ...link, className: (0, _classnames.default)( 'iui-anchor', 'iui-toast-anchor', link.className, ), title: void 0, 'data-iui-status': category, 'data-iui-underline': true, }, link.title, ), ('persisting' === type || hasCloseButton) && _react.createElement( _IconButton.IconButton, { size: 'small', styleType: 'borderless', onClick: onClose, 'aria-label': 'Close', }, _react.createElement(_index.SvgCloseSmall, null), ), ); }); const useAnimateToastBasedOnVisibility = (isVisible, args) => { let { thisElement, animateOutTo, onRemove } = args; let [shouldBeMounted, setShouldBeMounted] = _react.useState(isVisible); let motionOk = (0, _index.useMediaQuery)( '(prefers-reduced-motion: no-preference)', ); let onRemoveRef = (0, _index.useLatestRef)(onRemove); let [prevIsVisible, setPrevIsVisible] = _react.useState(void 0); _react.useEffect(() => { if (prevIsVisible !== isVisible) { setPrevIsVisible(isVisible); if (isVisible) safeAnimateIn(); else safeAnimateOut(); } function calculateOutAnimation(node) { let translateX = 0; let translateY = 0; if (animateOutTo && node) { let { x: startX, y: startY } = node.getBoundingClientRect(); let { x: endX, y: endY } = animateOutTo.getBoundingClientRect(); translateX = endX - startX; translateY = endY - startY; } return { translateX, translateY, }; } function safeAnimateIn() { setShouldBeMounted(true); queueMicrotask(() => { animateIn(); }); } function safeAnimateOut() { if (motionOk) { let animation = animateOut(); animation?.addEventListener('finish', () => { setShouldBeMounted(false); onRemoveRef.current?.(); }); } else { setShouldBeMounted(false); onRemoveRef.current?.(); } } function animateIn() { if (!motionOk) return; thisElement.current?.animate?.( [ { transform: 'translateY(15%)', }, { transform: 'translateY(0)', }, ], { duration: 240, fill: 'forwards', }, ); } function animateOut() { if (null == thisElement.current || !motionOk) return; let { translateX, translateY } = calculateOutAnimation( thisElement.current, ); let animationDuration = animateOutTo ? 400 : 120; let animation = thisElement.current?.animate?.( [ { transform: animateOutTo ? `scale(0.9) translate(${translateX}px,${translateY}px)` : 'scale(0.9)', opacity: 0, transitionDuration: `${animationDuration}ms`, transitionTimingFunction: 'cubic-bezier(0.4, 0, 1, 1)', }, ], { duration: animationDuration, iterations: 1, fill: 'forwards', }, ); return animation; } }, [ isVisible, prevIsVisible, animateOutTo, motionOk, thisElement, setShouldBeMounted, onRemoveRef, ]); return shouldBeMounted; };