[FIX] Modal keeps state if reset too fast. (#23791)
* Remove subscription, queue updates * use key instead of queue * Fix types * little adjustmentspull/23901/head
parent
abc59e1b9d
commit
49fe4e2cca
@ -1,81 +1,28 @@ |
||||
import { Emitter } from '@rocket.chat/emitter'; |
||||
import { ComponentType } from 'react'; |
||||
import { Subscription, Unsubscribe } from 'use-subscription'; |
||||
|
||||
type BlazeModalOptions = { |
||||
confirmButtonText?: string; |
||||
cancelButtonText?: string; |
||||
showCancelButton?: boolean; |
||||
confirmButtonColor?: string; |
||||
cancelButtonColor?: string; |
||||
|
||||
allowOutsideClick?: boolean; |
||||
confirmOnEnter?: boolean; |
||||
|
||||
closeOnConfirm?: boolean; |
||||
closeOnEscape?: boolean; |
||||
|
||||
type?: 'input'; |
||||
inputType?: 'text' | 'password'; |
||||
inputActionText?: string; |
||||
inputAction?: () => any; |
||||
inputPlaceholder?: string; |
||||
|
||||
modalIcon?: string; |
||||
|
||||
timer?: number; |
||||
dontAskAgain?: { |
||||
action: string; |
||||
label: string; |
||||
}; |
||||
|
||||
data?: Record<string, any>; |
||||
content?: string; |
||||
template?: string; |
||||
|
||||
title?: string; |
||||
text?: string; |
||||
html?: boolean; |
||||
type ReactModalDescriptor<TProps extends {}> = { |
||||
component: ComponentType<TProps>; |
||||
props?: TProps; |
||||
}; |
||||
|
||||
type BlazeModalDescriptor = { |
||||
options: BlazeModalOptions; |
||||
confirmFn?: () => any; |
||||
cancelFn?: () => any; |
||||
}; |
||||
|
||||
type ReactModalDescriptor<Props extends {} = {}> = { |
||||
component: ComponentType<Props>; |
||||
props?: Props; |
||||
}; |
||||
|
||||
type ModalDescriptor = BlazeModalDescriptor | ReactModalDescriptor | null; |
||||
|
||||
class ImperativeModalSubscription |
||||
extends Emitter<{ update: void }> |
||||
implements Subscription<ModalDescriptor> |
||||
{ |
||||
private descriptor: ModalDescriptor = null; |
||||
|
||||
getCurrentValue = (): ModalDescriptor => this.descriptor; |
||||
|
||||
subscribe = (callback: () => void): Unsubscribe => this.on('update', callback); |
||||
type ModalDescriptor = ReactModalDescriptor<{}> | null; |
||||
|
||||
setCurrentValue(descriptor: ModalDescriptor): void { |
||||
this.descriptor = descriptor; |
||||
this.emit('update'); |
||||
class ImperativeModalEmmiter extends Emitter<{ update: ModalDescriptor }> { |
||||
update(descriptor: ModalDescriptor): void { |
||||
this.emit('update', descriptor); |
||||
} |
||||
|
||||
open: { |
||||
(descriptor: BlazeModalDescriptor): void; |
||||
<Props = {}>(descriptor: ReactModalDescriptor<Props>): void; |
||||
} = (templateOrDescriptor: ModalDescriptor): void => { |
||||
this.setCurrentValue(templateOrDescriptor); |
||||
open = <TProps extends {}>(descriptor: ReactModalDescriptor<TProps> | null): void => { |
||||
// There are some TS shenanigans causing errors if this is not asserted
|
||||
// Since this method is for internal use only, it's ok to use this here
|
||||
// This will not affect prop types inference when using the method.
|
||||
this.update(descriptor as ModalDescriptor); |
||||
}; |
||||
|
||||
close = (): void => { |
||||
this.setCurrentValue(null); |
||||
this.update(null); |
||||
}; |
||||
} |
||||
|
||||
export const imperativeModal = new ImperativeModalSubscription(); |
||||
export const imperativeModal = new ImperativeModalEmmiter(); |
||||
|
||||
@ -1,26 +1,22 @@ |
||||
import { createElement, useEffect, Dispatch, SetStateAction, ReactNode } from 'react'; |
||||
import { useSubscription } from 'use-subscription'; |
||||
|
||||
import { imperativeModal } from '../../lib/imperativeModal'; |
||||
|
||||
export const useImperativeModal = (setModal: Dispatch<SetStateAction<ReactNode>>): void => { |
||||
const descriptor = useSubscription(imperativeModal); |
||||
|
||||
useEffect(() => { |
||||
if (descriptor === null) { |
||||
return setModal(null); |
||||
} |
||||
|
||||
// todo API to accept old modal props
|
||||
// and return equivalent React modal
|
||||
if ('options' in descriptor) { |
||||
return; // handleBlazeModal
|
||||
} |
||||
|
||||
if ('component' in descriptor) { |
||||
return setModal(createElement(descriptor.component, descriptor.props)); |
||||
} |
||||
|
||||
throw new Error('invalid modal descriptor'); |
||||
}, [descriptor, setModal]); |
||||
const unsub = imperativeModal.on('update', (descriptor) => { |
||||
if (descriptor === null) { |
||||
return setModal(null); |
||||
} |
||||
if ('component' in descriptor) { |
||||
setModal( |
||||
createElement(descriptor.component, { |
||||
key: Math.random(), |
||||
...descriptor.props, |
||||
}), |
||||
); |
||||
} |
||||
}); |
||||
return unsub; |
||||
}, [setModal]); |
||||
}; |
||||
|
||||
Loading…
Reference in new issue