You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vizality/src/core/builtins/notifications/components/Toast.jsx

218 lines
5.9 KiB

/**
*
*/
import { Button, Icon, Flex, LazyImage, ContextMenu, Markdown } from '@vizality/components';
import { getModule, contextMenu } from '@vizality/webpack';
import { joinClassNames } from '@vizality/util/dom';
import React, { memo } from 'react';
const { openContextMenu, closeContextMenu } = contextMenu;
/**
*
* @component
*/
const Content = memo(({ markdown, content }) => {
const { thin } = getModule('thin');
return (
<div className={joinClassNames('vz-toast-content', thin)}>
{markdown
? <Markdown source={content} />
: content
}
</div>
);
});
/**
*
* @component
*/
const CloseButton = memo(({ toastId }) => (
<Icon
name='Close'
size='20'
className='vz-toast-close-wrapper'
iconClassName='vz-toast-close'
onClick={evt => evt.shiftKey ? vizality.api.notifications.closeAllActiveToasts() : vizality.api.notifications.closeToast(toastId)}
/>
));
/**
*
* @component
*/
const Header = memo(({ toastId, icon, markdown, header, content, buttons }) => {
return (
<div className='vz-toast-meta-wrapper'>
{(icon?.url || icon?.name) && (
<div className='vz-toast-decorator'>
{icon.url && !icon.name && (
<LazyImage
src={icon.url}
width={icon.size || '40'}
height={icon.size || '40'}
className='vz-toast-icon'
/>
)}
{icon.name && (
<Icon
size={icon.size || '40'}
className='vz-toast-icon-wrapper'
iconClassName='vz-toast-icon'
color={icon.color}
name={icon.name}
/>
)}
</div>
)}
<div className='vz-toast-meta'>
<div className='vz-toast-header'>
{markdown
? <Markdown source={header} />
: header
}
</div>
{!content && !buttons?.length && (
<CloseButton toastId={toastId} />
)}
{content && <Content markdown={markdown} content={content} />}
</div>
</div>
);
});
/**
*
* @component
*/
const Footer = memo(({ buttons }) => {
const { horizontal } = getModule('buttonsWrapper', 'horizontal');
const { marginTop20 } = getModule('marginTop20');
return (
<Flex className={joinClassNames('vz-toast-footer', marginTop20)}>
<Flex className={joinClassNames('vz-toast-footer-buttons', horizontal)} justify={Flex.Justify.END}>
{buttons.map((button, i) => {
const btnProps = {};
[ 'size', 'look', 'color' ].forEach(prop => {
if (button[prop]) {
const value = button[prop].includes('-')
? button[prop]
: Button[`${prop.charAt(0).toUpperCase() + prop.slice(1)}s`][button[prop].toUpperCase()];
if (value) {
btnProps[prop] = value;
}
}
});
if (!btnProps.size) {
btnProps.size = Button.Sizes.SMALL;
}
return (
<Button
key={i}
{...btnProps}
onClick={evt => {
if (button.onClick) {
button.onClick(evt);
}
}}
>
{button.text}
</Button>
);
})}
</Flex>
</Flex>
);
});
/**
*
* @component
*/
export default memo(({ toast }) => {
const Toast =
typeof toast.custom === 'function'
? toast.custom
: () => toast.custom;
/**
* We only need to insert a close button if it's not a custom toast, has content, and
* the showCloseButton property is true.
*/
if (toast.showCloseButton && !toast.custom && toast.content) {
const CloseButton = {
text: 'Dismiss',
color: 'white',
look: 'link',
onClick: evt => evt.shiftKey ? vizality.api.notifications.closeAllActiveToasts() : vizality.api.notifications.closeToast(toast.id)
};
/**
* If there are button(s) already, insert a close button into the beginning
* of the array.
*/
if (toast.buttons?.length) {
/**
* Let's give the close button the same size as the last button specified.
*/
CloseButton.size = toast.buttons[toast.buttons.length - 1].size;
toast.buttons.unshift(CloseButton);
} else {
CloseButton.text = 'Okay';
CloseButton.color = 'white';
CloseButton.look = 'filled';
toast.buttons = [ CloseButton ];
}
}
return (
toast.custom
? <Toast {...toast.custom.props} />
: (
<div
className='vz-toast-body-inner'
vz-toast-id={toast.id}
onContextMenu={evt => openContextMenu(evt, () => (
<ContextMenu.Menu navId='dashboard-item' onClose={closeContextMenu}>
<ContextMenu.Item
id='close-toast'
label='Close Toast'
action={() => vizality.api.notifications.closeToast(toast.id)}
/>
<ContextMenu.Item
id='close-all-toasts'
label='Close All Toasts'
action={() => vizality.api.notifications.closeAllActiveToasts()}
/>
<ContextMenu.Item
id='view-toast-settings'
label='View Toast Settings'
action={() => vizality.api.routes.navigateTo('settings/notifications#toasts')}
/>
</ContextMenu.Menu>
))}
>
<Header
markdown={toast.markdown}
image={toast.image}
icon={toast.icon}
buttons={toast.buttons}
header={toast.header}
toastId={toast.id}
content={toast.content}
/>
{toast.buttons?.length && (
<Footer
buttons={toast.buttons}
toastId={toast.id}
showCloseButton={toast.showCloseButton}
/>
)}
</div>
)
);
});