@datalayer/core
Version:
[](https://datalayer.io)
144 lines (143 loc) • 5.72 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/*
* Copyright (c) 2023-2025 Datalayer, Inc.
* Distributed under the terms of the Modified BSD License.
*/
import React from 'react';
import { toast } from 'react-toastify';
import { Notification } from '@jupyterlab/apputils';
import { Button } from '@primer/react';
import { JupyterReactTheme } from '@datalayer/jupyter-react';
import { isInsideJupyterLab } from '../utils';
const TOAST_POSITION = 'bottom-right';
const displayType2Class = {
accent: 'primary',
link: 'invisible',
warn: 'danger',
default: 'default',
};
/**
* Create a button with customized callback in a toast
*/
function ToastButton({ action, closeToast }) {
const clickHandler = (event) => {
action.callback(event);
if (!event.defaultPrevented) {
closeToast();
}
};
return (_jsx(Button, { title: action.caption ?? action.label, onClick: clickHandler, variant: displayType2Class[action.displayType ?? 'default'], size: "small", children: action.label }));
}
/**
* Helper function to construct the notification content
*
* @param message Message to print in the notification
* @param closeHandler Function closing the notification
* @param actions Toast actions
*/
function createContent(message, closeHandler, actions) {
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "jp-toast-message", children: message.split('\n').map((part, index) => (_jsxs(React.Fragment, { children: [index > 0 ? _jsx("br", {}) : null, part] }, `part-${index}`))) }), (actions?.length ?? 0) > 0 && (_jsxs("div", { className: "jp-toast-buttonBar", children: [_jsx("div", { className: "jp-toast-spacer" }), actions.map((action, idx) => {
return (_jsx(JupyterReactTheme, { children: _jsx(ToastButton, { action: action, closeToast: closeHandler }, 'button-' + idx) }));
})] }))] }));
}
export const useToast = () => {
// This CANNOT use Jupyter React hooks as it may be used outside Jupyter React context.
const insideJupyterLab = isInsideJupyterLab();
const enqueueToast = (message, options = { variant: 'info' }) => {
const { actions, autoClose } = options;
switch (options.variant) {
case 'info': {
return insideJupyterLab
? Notification.info(message, {
autoClose: autoClose ?? 5000,
actions,
})
: toast.info(({ closeToast }) => createContent(message, () => {
if (closeToast)
closeToast();
}, actions), { autoClose, position: TOAST_POSITION });
}
case 'success': {
return insideJupyterLab
? Notification.success(message, {
autoClose: autoClose ?? 5000,
actions,
})
: toast.success(({ closeToast }) => createContent(message, () => {
if (closeToast)
closeToast();
}, actions), { autoClose, position: TOAST_POSITION });
}
case 'warning': {
return insideJupyterLab
? Notification.warning(message, {
autoClose: autoClose ?? false,
actions,
})
: toast.warning(({ closeToast }) => createContent(message, () => {
if (closeToast)
closeToast();
}, actions), { autoClose: autoClose ?? false, position: TOAST_POSITION });
}
case 'error': {
return insideJupyterLab
? Notification.error(message, {
autoClose: autoClose ?? false,
actions,
})
: toast.error(({ closeToast }) => createContent(message, () => {
if (closeToast)
closeToast();
}, actions), { autoClose: autoClose ?? false, position: TOAST_POSITION });
}
}
};
const trackAsyncTask = (promise, options) => {
return insideJupyterLab
? Notification.promise(promise, options)
: toast.promise(promise, {
error: { render: options.error.message, ...options.error.options },
pending: options.pending.message,
success: {
render: options.success.message,
...options.success.options,
},
}, {
position: TOAST_POSITION,
...options.pending.options,
});
};
return Object.freeze({
/**
* Emit a message as a toast.
*
* @param message Toast message
* @param options Toast option
* @returns Toast id
*/
enqueueToast,
/**
* Dismiss a toast
*
* @param id Toast id
*/
dismiss: (id) => {
if (insideJupyterLab) {
Notification.dismiss(id);
}
else {
toast.dismiss(id);
}
},
/**
* Track the progress of an asynchronous task
* and display a message depending on the outcome.
*
* @param promise Asynchronous task
* @param options Task progress options
* @returns Toast id
*/
trackAsyncTask,
});
};
export default useToast;