import * as RMWC from '@rmwc/types' ; import React , { useState , useEffect } from 'react' ; import { SimpleDialog , SimpleDialogProps , SimpleDialogHTMLProps , DialogOnCloseEventT } from './dialog' ; import { ArrayEmitter , randomId } from '@rmwc/base' ; import { TextField , TextFieldProps , TextFieldHTMLProps } from '@rmwc/textfield' ; export interface DialogQueueInput extends SimpleDialogProps , SimpleDialogHTMLProps { id ? : string ; /** Props for the input when using the prompt dialog. Only applies to prompt. */ inputProps ? : TextFieldProps & TextFieldHTMLProps ; } export interface DialogQueueSpec extends DialogQueueInput { id : string ; resolve : ( response : any ) => void ; reject : ( reason : any ) => void ; } /** A snackbar queue for rendering messages */ export interface DialogQueueProps extends SimpleDialogProps { dialogs : ArrayEmitter < DialogQueueSpec > ; } /** A snackbar queue for rendering messages */ export function DialogQueue ( { dialogs , ... defaultDialogProps } ) { const [ , setIteration ] = useState ( 0 ) ; const [ closingDialogs , setClosingDialogs ] = useState < { [ key ] : true ; } > ( { } ) ; useEffect ( ( ) => { const forceUpdate = ( ) => setIteration ( val => val + 1 ) ; dialogs . on ( 'change' , forceUpdate ) ; return ( ) => { dialogs . off ( 'change' , forceUpdate ) ; } ; } , [ dialogs ] ) ; const removeDialog = ( evt , dialog ) => { setClosingDialogs ( { ... closingDialogs , [ dialog . id ] : true } ) ; dialog . resolve ( evt ) ; setTimeout ( ( ) => { const index = dialogs . array . indexOf ( dialog ) ; ! ! ~ index && dialogs . array . splice ( index , 1 ) ; const newClosingDialogs = { ... closingDialogs } ; delete newClosingDialogs [ dialog . id ] ; setClosingDialogs ( newClosingDialogs ) ; } , 150 ) ; } ; let foundOpen = false ; return ( < > { dialogs . array . map ( dialog => { const { resolve , reject , id , inputProps , ... rest } = dialog ; const rendered = ( < SimpleDialog { ... defaultDialogProps } { ... rest } key = { id } open = { ! closingDialogs [ id ] && ! foundOpen } onClose = { evt => { removeDialog ( evt , dialog ) ; dialog . onClose && dialog . onClose ( evt ) ; } } / > ) ; if ( ! closingDialogs [ id ] ) { foundOpen = true ; } return rendered ; } ) } < />); } /**
 * A base dialog factory that handle setting up the promise
 * With some consistent behavior
 */ const dialogFactory = ( factory , queue ) => ( dialog ) => { return new Promise ( ( resolve , reject ) => { const d = factory ( { id : randomId ( ) , ... dialog , resolve , reject } ) ; queue . push ( d ) ; } ) ; } ; /**
 * Handle prompt dialogs
 * We have to jump through a few hoops to get the value back out
 */ function PromptBody ( { body , inputProps , apiRef } ) { const [ value , setValue ] = useState ( '' ) ; useEffect ( ( ) => { apiRef ( ( ) => value ) ; } , [ apiRef , value ] ) ; return ( < div > { ! ! body && < div style = { { marginBottom : '1rem' } } > { body } < /div>} < TextField style = { { width : '100%' } } autoFocus { ... inputProps } value = { value } onChange = { evt => { setValue ( evt . currentTarget . value ) ; } } /> < /div>); } const promptFactory = ( dialog ) : DialogQueueSpec => { let getValue = ( ) => '' ; const body = ( < PromptBody body = { dialog . body } inputProps = { dialog . inputProps } apiRef = { _getValue => ( getValue = _getValue ) } />); return { title : 'Prompt' , ... dialog , body , resolve : ( evt ) => { dialog . resolve ( evt . detail . action === 'accept' ? getValue ( ) : null ) ; getValue = undefined ; } } ; } ; /** Alerts */ const alertFactory = ( dialog ) : DialogQueueSpec => ( { title : 'Alert' , body : 'You have been alerted!' , acceptLabel : 'OK' , cancelLabel : null , ... dialog , resolve : ( evt ) => dialog . resolve ( evt . detail . action ) } ) ; /** Confirm */ const confirmFactory = ( dialog ) : DialogQueueSpec => ( { title : 'Confirm' , body : 'Are you sure you want do that?' , acceptLabel : 'OK' , cancelLabel : 'Cancel' , ... dialog , resolve : ( evt ) => dialog . resolve ( evt . detail . action === 'accept' ) } ) ; /** Creates a snackbar queue */ export const createDialogQueue = ( ) : { dialogs : ArrayEmitter < DialogQueueSpec > ; alert : ( dialog : DialogQueueInput ) => Promise < any > ; confirm : ( dialog : DialogQueueInput ) => Promise < any > ; prompt : ( dialog : DialogQueueInput ) => Promise < any > ; } => { const dialogs = new ArrayEmitter < DialogQueueSpec > ( ) ; return { dialogs , alert : dialogFactory ( alertFactory , dialogs ) , confirm : dialogFactory ( confirmFactory , dialogs ) , prompt : dialogFactory ( promptFactory , dialogs ) } ; } ;