11import * as React from "react" ;
2+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
3+ import {
4+ faSpinner ,
5+ faBell ,
6+ faCheck ,
7+ faExclamationTriangle ,
8+ faExclamationCircle
9+ } from "@fortawesome/free-solid-svg-icons" ;
10+ import { closeIcon } from "@jupyterlab/ui-components" ;
211import {
312 ToastContent ,
413 ToastOptions ,
@@ -90,12 +99,15 @@ export namespace INotification {
9099 function createContent (
91100 message : React . ReactNode ,
92101 closeHandler : ( ) => void ,
93- buttons ?: IButton [ ]
102+ buttons ?: IButton [ ] ,
103+ icon ?: JSX . Element
94104 ) : React . ReactNode {
95- if ( buttons && buttons . length > 0 ) {
96- return (
97- < div >
98- { message }
105+ const hasButtons = buttons && buttons . length > 0 ;
106+ return (
107+ < >
108+ { icon ? icon : null }
109+ { message }
110+ { hasButtons && (
99111 < div className = "jp-toast-buttonBar" >
100112 < div className = "jp-toast-spacer" />
101113 { buttons . map ( ( button , idx ) => {
@@ -108,26 +120,31 @@ export namespace INotification {
108120 ) ;
109121 } ) }
110122 </ div >
111- </ div >
112- ) ;
113- } else {
114- return < div > { message } </ div > ;
115- }
123+ ) }
124+ </ >
125+ ) ;
116126 }
117127
118128 async function createToast (
119129 message : React . ReactNode ,
120130 buttons ?: IButton [ ] ,
121- options ?: ToastOptions
131+ options ?: ToastOptions ,
132+ icon ?: JSX . Element
122133 ) : Promise < React . ReactText > {
123134 let _resolve : ( value : React . ReactText ) => void ;
124135 const toast = await Private . toast ( ) ;
125136 const promise = new Promise < React . ReactText > ( resolve => {
126137 _resolve = resolve ;
127138 } ) ;
139+ const theOptions = { ...options } ;
128140 const toastId : React . ReactText = toast (
129141 ( { closeToast } : { closeToast : ( ) => void } ) =>
130- createContent ( message , closeToast , buttons ) ,
142+ createContent (
143+ message ,
144+ closeToast ,
145+ buttons ,
146+ icon || Private . type2Icon . get ( theOptions . type )
147+ ) ,
131148 {
132149 ...options ,
133150 onOpen : ( ) => _resolve ( toastId )
@@ -186,9 +203,11 @@ export namespace INotification {
186203 message : React . ReactNode ,
187204 options ?: IOptions
188205 ) : Promise < React . ReactText > => {
189- const buttons = options && options . buttons ;
206+ const theOptions = { ...options } ;
207+ const buttons = theOptions . buttons ;
190208 const autoClose =
191- options . autoClose || ( buttons && buttons . length > 0 ? false : undefined ) ;
209+ theOptions . autoClose ||
210+ ( buttons && buttons . length > 0 ? false : undefined ) ;
192211 return createToast ( message , buttons , {
193212 type : "info" ,
194213 className : "jp-toast-info" ,
@@ -208,9 +227,11 @@ export namespace INotification {
208227 message : React . ReactNode ,
209228 options ?: IOptions
210229 ) : Promise < React . ReactText > => {
211- const buttons = options && options . buttons ;
230+ const theOptions = { ...options } ;
231+ const buttons = theOptions . buttons ;
212232 const autoClose =
213- options . autoClose || ( buttons && buttons . length > 0 ? false : undefined ) ;
233+ theOptions . autoClose ||
234+ ( buttons && buttons . length > 0 ? false : undefined ) ;
214235 return createToast ( message , buttons , {
215236 type : "success" ,
216237 className : "jp-toast-success" ,
@@ -230,11 +251,21 @@ export namespace INotification {
230251 message : React . ReactNode ,
231252 options ?: IOptions
232253 ) : Promise < React . ReactText > => {
233- return createToast ( message , options && options . buttons , {
234- type : "default" ,
235- className : "jp-toast-inprogress" ,
236- autoClose : ( options && options . autoClose ) || false
237- } ) ;
254+ return createToast (
255+ message ,
256+ options && options . buttons ,
257+ {
258+ type : "default" ,
259+ className : "jp-toast-inprogress" ,
260+ autoClose : ( options && options . autoClose ) || false
261+ } ,
262+ < FontAwesomeIcon
263+ icon = { faSpinner }
264+ pull = "left"
265+ spin
266+ style = { { color : "var(--jp-inverse-layout-color3)" } }
267+ />
268+ ) ;
238269 } ;
239270
240271 /** Options needed to update an existing toast */
@@ -280,7 +311,12 @@ export namespace INotification {
280311 } ;
281312 toast . update ( args . toastId , {
282313 ...options ,
283- render : createContent ( args . message , closeToast , args . buttons )
314+ render : createContent (
315+ args . message ,
316+ closeToast ,
317+ args . buttons ,
318+ Private . type2Icon . get ( options . type )
319+ )
284320 } ) ;
285321 } else {
286322 // Needs to recreate a closed toast
@@ -405,6 +441,42 @@ interface IToast {
405441}
406442
407443namespace Private {
444+ export const type2Icon = new Map < TypeOptions , JSX . Element > ( [
445+ [ "default" , null ] ,
446+ [
447+ "error" ,
448+ < FontAwesomeIcon
449+ icon = { faExclamationCircle }
450+ pull = "left"
451+ style = { { color : "var(--jp-error-color1)" } }
452+ />
453+ ] ,
454+ [
455+ "warning" ,
456+ < FontAwesomeIcon
457+ icon = { faExclamationTriangle }
458+ pull = "left"
459+ style = { { color : "var(--jp-warn-color1)" } }
460+ />
461+ ] ,
462+ [
463+ "info" ,
464+ < FontAwesomeIcon
465+ icon = { faBell }
466+ pull = "left"
467+ style = { { color : "var(--jp-info-color1)" } }
468+ />
469+ ] ,
470+ [
471+ "success" ,
472+ < FontAwesomeIcon
473+ icon = { faCheck }
474+ pull = "left"
475+ style = { { color : "var(--jp-success-color1)" } }
476+ />
477+ ]
478+ ] ) ;
479+
408480 let toastify : {
409481 toast : IToast ;
410482 Slide : (
@@ -418,6 +490,19 @@ namespace Private {
418490 ) => JSX . Element ;
419491 } = null ;
420492
493+ const CloseButton : React . FunctionComponent < { closeToast : ( ) => void } > = ( {
494+ closeToast
495+ } ) => (
496+ < i onClick = { closeToast } >
497+ < closeIcon . react
498+ className = "jp-icon-hover"
499+ elementPosition = "center"
500+ height = "16px"
501+ width = "16px"
502+ />
503+ </ i >
504+ ) ;
505+
421506 export async function toast ( ) : Promise < IToast > {
422507 if ( toastify === null ) {
423508 toastify = await import ( "react-toastify" ) ;
@@ -431,7 +516,8 @@ namespace Private {
431516 pauseOnHover : true ,
432517 position : "bottom-right" ,
433518 className : "jp-toastContainer" ,
434- transition : toastify . Slide
519+ transition : toastify . Slide ,
520+ closeButton : CloseButton
435521 } ) ;
436522 }
437523
0 commit comments