UNPKG

@appbuckets/react-ui

Version:
295 lines (292 loc) 8.19 kB
import { __rest, __read, __assign } from 'tslib'; import * as React from 'react'; import clsx from 'clsx'; import { useAutoControlledValue, useElementType, childrenUtils, MountNode, } from '@appbuckets/react-ui-core'; import { useSharedClassName } from '../utils/customHook.js'; import '../BucketTheme/BucketTheme.js'; import { useWithDefaultProps } from '../BucketTheme/BucketContext.js'; import Backdrop from '../Backdrop/Backdrop.js'; import Button from '../Button/Button.js'; import Icon from '../Icon/Icon.js'; import { ModalProvider } from './Modal.context.js'; import ModalActions from './ModalActions.js'; import ModalContent from './ModalContent.js'; import ModalHeader from './ModalHeader.js'; /* -------- * Component Render * -------- */ var Modal = function (receivedProps) { var props = useWithDefaultProps('modal', receivedProps); // ---- // Get Modal Props // ---- var _a = useSharedClassName(props), className = _a.className, _b = _a.rest, /** Modal Props */ actions = _b.actions, basic = _b.basic, children = _b.children, closeIcon = _b.closeIcon, closeOnBackdropClick = _b.closeOnBackdropClick, content = _b.content, header = _b.header, icon = _b.icon, userDefinedMountNode = _b.mountNode, size = _b.size, /** Modal handlers */ onActionClick = _b.onActionClick, onClose = _b.onClose, onOpen = _b.onOpen, /** Modal state Prop */ defaultOpen = _b.defaultOpen, openProp = _b.open, /** Handled Backdrop Props */ loading = _b.loading, loaderProps = _b.loaderProps, timeout = _b.timeout, /** Handled Portal Props */ closeOnEscape = _b.closeOnEscape, openOnTriggerClick = _b.openOnTriggerClick, openOnTriggerFocus = _b.openOnTriggerFocus, openOnTriggerMouseEnter = _b.openOnTriggerMouseEnter, trigger = _b.trigger, triggerRef = _b.triggerRef, /** All other Props */ rest = __rest(_b, [ 'actions', 'basic', 'children', 'closeIcon', 'closeOnBackdropClick', 'content', 'header', 'icon', 'mountNode', 'size', 'onActionClick', 'onClose', 'onOpen', 'defaultOpen', 'open', 'loading', 'loaderProps', 'timeout', 'closeOnEscape', 'openOnTriggerClick', 'openOnTriggerFocus', 'openOnTriggerMouseEnter', 'trigger', 'triggerRef', ]); // ---- // Init Modal Internal State // ---- /** Init the AutoControlled open state */ var _c = __read( useAutoControlledValue(false, { prop: openProp, defaultProp: defaultOpen, }), 2 ), open = _c[0], trySetOpen = _c[1]; /** Init a state to define if inner modal component must be visible */ var _d = __read(React.useState(open), 2), innerModalVisible = _d[0], setInnerModalVisible = _d[1]; /** Get the component element type */ var ElementType = useElementType(Modal, receivedProps, props); /** Check if in this render modal has children */ var hasChildren = !childrenUtils.isNil(children); // ---- // Define Modal Handlers // ---- var handleModalEntering = React.useCallback(function () { setInnerModalVisible(true); }, []); var handleModalExited = React.useCallback(function () { setInnerModalVisible(false); }, []); var handleModalClose = function (e) { /** Stop Event Propagation */ e.stopPropagation(); /** Call User Handler if Exists */ if (onClose) { onClose(e, props); } /** Try to close the modal */ trySetOpen(false); }; var handleModalOpen = function (e) { /** Stop Event Propagation */ e.stopPropagation(); /** Call User Handler if Exists */ if (onOpen) { onOpen(e, props); } /** Try to open the modal */ trySetOpen(true); }; // ---- // Build Component Classes // ---- var contentClasses = clsx( 'modal', size, { basic: basic }, icon && 'with-icon', className ); var mountNodeClasses = clsx('dimmable', open && 'dimmed'); // ---- // Memoized Elements // ---- var modalIconElement = React.useMemo( function () { return ( icon && Icon.create(icon, { autoGenerateKey: false, overrideProps: { solid: 'inverted circle', }, }) ); }, [icon] ); var closeIconElement = closeIcon && Button.create( { icon: closeIcon, flat: true, appearance: 'white shade', }, { autoGenerateKey: false, defaultProps: { className: 'close' }, overrideProps: function (predefinedProps) { return { onClick: function (e) { /** Call original user defined handler on icon */ if (predefinedProps.onClick) { predefinedProps.onClick(e, predefinedProps); } /** Try to close the Modal */ handleModalClose(e); }, }; }, } ); var modalHeaderElement = React.useMemo( function () { /** Set empty component if is closed */ if (!innerModalVisible || !header) { return null; } /** Create a new Modal Header using Shorthand Factory */ return ModalHeader.create(header, { autoGenerateKey: false }); }, [innerModalVisible, header] ); var modalActionsElement = React.useMemo( function () { /** Set empty component if is closed */ if (hasChildren || !innerModalVisible || !actions) { return null; } /** Create modal action element using Shorthand Factory */ return ModalActions.create(actions, { autoGenerateKey: false, overrideProps: function (predefinedProps) { return { onActionClick: function (e, buttonProps) { /** Call predefined on Action Click function */ if (predefinedProps.onActionClick) { predefinedProps.onActionClick(e, buttonProps); } /** Call modal action click if exists */ if (onActionClick) { onActionClick(e, buttonProps); } }, }; }, }); }, [hasChildren, innerModalVisible, actions, onActionClick] ); // ---- // Init an internal function to build Modal Content // ---- var renderModalContent = function () { return React.createElement( ModalProvider, { value: { closeModal: handleModalClose } }, React.createElement( ElementType, __assign({}, rest, { className: contentClasses }), React.createElement(MountNode, { className: mountNodeClasses, node: userDefinedMountNode !== null && userDefinedMountNode !== void 0 ? userDefinedMountNode : document.body, }), modalIconElement, closeIconElement, modalHeaderElement, !hasChildren ? React.createElement( React.Fragment, null, ModalContent.create(content, { autoGenerateKey: false }), modalActionsElement ) : children ) ); }; // ---- // Render the Component // ---- return React.createElement( Backdrop, { page: true, className: 'modals', visible: open, closeOnBackdropClick: closeOnBackdropClick, closeOnDocumentClick: false, closeOnEscape: closeOnEscape, openOnTriggerClick: openOnTriggerClick, openOnTriggerMouseEnter: openOnTriggerMouseEnter, openOnTriggerFocus: openOnTriggerFocus, trigger: trigger, triggerRef: triggerRef, verticalAlign: 'on top', loading: loading, loaderProps: loaderProps, timeout: timeout, onClose: handleModalClose, onOpen: handleModalOpen, onEntering: handleModalEntering, onExited: handleModalExited, }, renderModalContent() ); }; Modal.displayName = 'Modal'; Modal.Actions = ModalActions; Modal.Content = ModalContent; Modal.Header = ModalHeader; export { Modal as default };