Skip to content

Commit

Permalink
Rewrite ModalManagerState into Typescript
Browse files Browse the repository at this point in the history
- Fixes `attrs` parameter being marked as required
- Add `isModalOpen` method
  • Loading branch information
davwheat committed Aug 9, 2021
1 parent 9490b3d commit 4623874
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 46 deletions.
46 changes: 0 additions & 46 deletions js/src/common/states/ModalManagerState.js

This file was deleted.

75 changes: 75 additions & 0 deletions js/src/common/states/ModalManagerState.ts
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;
}
}

0 comments on commit 4623874

Please sign in to comment.