@wonderflow/react-components
Version:
UI components from Wonderflow's Wanda design system
66 lines (65 loc) • 5.68 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/*
* Copyright 2022-2023 Wonderflow Design Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import tkns from '@wonderflow/tokens/platforms/web/tokens.json';
import clsx from 'clsx';
import { domMax, LazyMotion, m } from 'framer-motion';
import { cloneElement, forwardRef, isValidElement, useMemo, } from 'react';
import { FocusOn } from 'react-focus-on';
import { Elevator, OverlayContainer, Spinner, Stack, Text, useResponsiveContext, } from '../..';
import { ModalContent } from './content/modal-content';
import { ModalFooter } from './footer/modal-footer';
import { ModalHeader } from './header/modal-header';
import * as styles from './modal.module.css';
const cssEasingToArray = (cssEasing) => {
const [x1, y1, x2, y2] = cssEasing.replace(/[^0-9.,]+/g, '').split(',').map(i => parseFloat(i));
return [x1, y1, x2, y2];
};
export const Modal = forwardRef(({ children, className, size = 'medium', theme = 'light', title, subtitle, hideCloseButton, hideHeaderBorder, hideFooterBorder, content, primaryAction, secondaryAction, tertiaryAction, alignActionCenter, alignContentCenter, isVisible, preventCloseOnClickOutside, isLoading, onCloseModal, ...otherProps }, forwardedRef) => {
const { matches } = useResponsiveContext();
const hasActions = tertiaryAction ?? secondaryAction ?? primaryAction;
const ModalAnimation = useMemo(() => ({
visible: {
scale: 1,
opacity: 1,
y: 0,
transition: {
ease: cssEasingToArray(tkns.easing.entrance),
duration: parseFloat(tkns.duration[300].replace('s', '')),
},
},
hidden: {
scale: matches.small ? 0.98 : 1,
opacity: matches.small ? 0 : 1,
y: matches.small ? 0 : '100%',
transition: {
ease: cssEasingToArray(tkns.easing.exit),
duration: matches.small ? parseFloat(tkns.duration[200].replace('s', '')) : parseFloat(tkns.duration[500].replace('s', '')),
},
},
}), [matches]);
return (_jsx(_Fragment, { children: isVisible && (_jsx(OverlayContainer, { onClose: onCloseModal, overlayColor: otherProps.overlayColor, root: otherProps.root, index: otherProps.index, obfuscate: otherProps.obfuscate, children: _jsx("div", { "aria-modal": "true", "aria-labelledby": (typeof title === 'string') ? title : 'modal-label', className: clsx(styles.Modal, className), ref: forwardedRef, ...otherProps, children: _jsx(FocusOn, { onClickOutside: preventCloseOnClickOutside ? undefined : onCloseModal, onEscapeKey: onCloseModal, children: _jsx(LazyMotion, { features: domMax, children: _jsx(m.div, { role: "dialog", variants: ModalAnimation, initial: "hidden", animate: "visible", exit: "hidden", className: styles.Container, children: _jsx(Elevator, { resting: 4, children: _jsx("div", { className: clsx(styles.Main, className), ref: forwardedRef, "data-theme": theme, "data-size": size, ...otherProps, children: children ?? (_jsxs(_Fragment, { children: [_jsxs(Modal.Header, { hideCloseButton: hideCloseButton, theme: theme, hideBorder: (!title ?? !subtitle) || hideHeaderBorder, children: [title && _jsx(Text, { variant: "heading-6", children: title }), (title && subtitle) && _jsx(Text, { variant: "subtitle-2", children: subtitle })] }), content && (_jsx(Modal.Content, { theme: theme, alignContentCenter: isLoading ? true : alignContentCenter, children: isLoading
? (_jsx(Stack, { fill: true, hAlign: "center", vPadding: 64, children: _jsxs(Stack, { hAlign: "center", vAlign: "center", rowGap: 16, children: [_jsx(Spinner, { dimension: "big" }), _jsx(Text, { variant: "body-1", children: "Loading..." })] }) }))
: content })), hasActions && (_jsx(Modal.Footer, { theme: theme, hideBorder: hideFooterBorder, children: _jsxs(Stack, { direction: matches.small ? 'row' : 'column-reverse', rowGap: matches.small ? undefined : '16', fill: false, hAlign: (alignActionCenter && matches.small) ? 'center' : 'space-between', vAlign: "center", columnGap: 16, children: [_jsx(Stack, { direction: "row", fill: true, children: tertiaryAction }), _jsxs(Stack, { direction: matches.small ? 'row' : 'column-reverse', rowGap: matches.small ? undefined : '16', columnGap: 16, children: [secondaryAction
&& isValidElement(secondaryAction)
&& cloneElement(secondaryAction, { ...secondaryAction.props, kind: 'secondary', dimension: 'regular' }), primaryAction
&& isValidElement(primaryAction)
&& cloneElement(primaryAction, { ...primaryAction.props, kind: 'primary', dimension: 'regular' })] })] }) }))] })) }) }) }) }) }) }) })) }));
});
Modal.displayName = 'Modal';
Modal.Header = ModalHeader;
Modal.Content = ModalContent;
Modal.Footer = ModalFooter;