-
-
Notifications
You must be signed in to change notification settings - Fork 835
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite ModalManagerState into Typescript
- Fixes `attrs` parameter being marked as required - Add `isModalOpen` method
- Loading branch information
Showing
2 changed files
with
75 additions
and
46 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import Modal from '../components/Modal'; | ||
|
||
/** | ||
* Class used to manage modal state. | ||
* | ||
* Accessible on the `app` object via `app.modal` property. | ||
*/ | ||
export default class ModalManagerState { | ||
/** | ||
* @internal | ||
*/ | ||
modal: null | { | ||
componentClass: typeof Modal; | ||
attrs?: Record<string, unknown>; | ||
}; | ||
|
||
private closeTimeout?: number; | ||
|
||
constructor() { | ||
this.modal = null; | ||
} | ||
|
||
/** | ||
* Shows a modal dialog. | ||
* | ||
* If a modal is already open, the existing one will close and the new modal will replace it. | ||
* | ||
* @example <caption>Show a modal</caption> | ||
* app.modal.show(MyCoolModal, { attr: 'value' }); | ||
* | ||
* @example <caption>Show a modal from a lifecycle method (`oncreate`, `view`, etc.)</caption> | ||
* // This "hack" is needed due to quirks with nested redraws in Mithril. | ||
* setTimeout(() => app.modal.show(MyCoolModal, { attr: 'value' }), 0); | ||
*/ | ||
show(componentClass: typeof Modal, attrs: Record<string, unknown> = {}): void { | ||
if (!(componentClass.prototype instanceof Modal)) { | ||
// This is duplicated so that if the error is caught, an error message still shows up in the debug console. | ||
const invalidModalWarning = 'The ModalManager can only show Modals.'; | ||
console.error(invalidModalWarning); | ||
throw new Error(invalidModalWarning); | ||
} | ||
|
||
clearTimeout(this.closeTimeout); | ||
|
||
this.modal = { componentClass, attrs }; | ||
|
||
m.redraw.sync(); | ||
} | ||
|
||
/** | ||
* Closes the currently open dialog, if one is open. | ||
*/ | ||
close(): void { | ||
if (!this.modal) return; | ||
|
||
// Don't hide the modal immediately, because if the consumer happens to call | ||
// the `show` method straight after to show another modal dialog, it will | ||
// cause Bootstrap's modal JS to misbehave. Instead we will wait for a tiny | ||
// bit to give the `show` method the opportunity to prevent this from going | ||
// ahead. | ||
this.closeTimeout = setTimeout(() => { | ||
this.modal = null; | ||
m.redraw(); | ||
}); | ||
} | ||
|
||
/** | ||
* Checks if a modal is currently open. | ||
* | ||
* @returns `true` if a modal dialog is currently open, otherwise `false`. | ||
*/ | ||
isModalOpen(): boolean { | ||
return !!this.modal; | ||
} | ||
} |