- A single overlay (
.modal) that shows one of several states at a time. Each state is a panel (.modal__container.<name>). - Opening a state while another is open closes the modal and opens the new state 0.25 s later.
- Can register the overlay with UICollisionLayer so
input.over_uiistruewhile the pointer is over it. - Two exports:
AbstractModalComponentis the base class of the app's modal component.ModalStateis the base class of each state.
- To scaffold a new state, its template and its styles, run
yarn create-modal my_modalin the boilerplate. See Creating Modals.
- Class. Extend it and export one instance, as the boilerplate's
ModalComponentdoes.
-
init(ui_collision_layer, time): Initialize component.ui_collision_layer: The UICollisionLayer singleton.time: Time fromohzi-core.
Reads
.modalintocontainerand.modal__animationintoanimation, starts hidden, and resetsstatesto{}. Register states afterinit(). -
start(): Empty hook. The boilerplate registers its states here. -
show_state(state_name, collision = true): Opens the state registered understate_name.- Hidden: adds
containerto the UICollisionLayer whencollisionistrue, switches to the state, then callson_enter(). - Open: calls
hide(state_name, collision).update()opens the state 0.25 s later.
- Hidden: adds
-
hide(next_state_name?, next_state_collision = true): Removescontainerfrom the UICollisionLayer, callson_exit()and clearslast_state. Ifnext_state_nameis given,update()opens it 0.25 s later. -
set_state(state): Switches to a state object without closing the modal. Callson_exiton the current state andon_enteron the new one. If the modal is open, it saves the current state inlast_state. -
restore_last_state(): Re-openslast_stateby itsname(close, then open 0.25 s later). Hides the modal if there is nolast_state. -
on_enter(): Removes thehiddenclass fromcontainer. -
on_exit(): Adds thehiddenclass tocontainer. -
update(current_state_data): Should be called in anupdatemethod. Callsupdate()on the current state, and opens the state queued byhide(). The argument is unused.
states: Registered states by key.show_state()looks states up here.current_state: The active state. An emptyAbstractModalStateuntil the firstshow_state().last_state: The state to go back to withrestore_last_state(). See Notes.hidden: Whether the overlay is hidden. Starts astrue.container: The.modalelement.animation: The.modal__animationelement. The base class doesn't use it.
- Base class of a modal state. Extend it and call
superin each hook.
constructor(name): Storesnameand reads.modal__container.<name>intocontainer.on_enter(modal_component): Removes thehiddenclass fromcontainer.on_exit(modal_component): Adds thehiddenclass tocontainer.update(modal_component): Empty. Called every frame from the component'supdate().
name: The state's CSS class, used to find itscontainer.container: The.modal__container.<name>element.
import { AbstractModalComponent, ModalState } from 'ohzi-components';
class PrivacyPolicyModalState extends ModalState
{
on_enter(modal_component: AbstractModalComponent)
{
super.on_enter(modal_component);
// Bind buttons, start animations
}
}
class ModalComponent extends AbstractModalComponent
{
start()
{
super.start();
this.states = {
// key used by show_state() CSS class of the panel
privacy_policy: new PrivacyPolicyModalState('privacy-policy-modal')
};
}
}
const modal_component = new ModalComponent();
export { modal_component as ModalComponent };// App init
ModalComponent.init(UICollisionLayer, Time);
ModalComponent.start();
// In your update loop
ModalComponent.update();
// Open, then close
ModalComponent.show_state('privacy_policy');
ModalComponent.hide();- A state has two names: the key in
states, used byshow_state(), and itsname, the CSS class.yarn create-modal privacy_policyregistersprivacy_policy: new PrivacyPolicyModalState('privacy-policy-modal'). restore_last_state()re-opens the state by itsname, not its key. It only works when both are the same string.last_stateis only saved byset_state()while the modal is open.show_state()never saves it. For a nested modal, switch withset_state(this.states[key])and go back withrestore_last_state().hide()doesn't call the state'son_exit(). The state exits on the nextset_state(), and itsupdate()keeps running while the modal is hidden.- Opening a state while the modal is open needs
update()every frame. Without it the queued state never opens. show_state()with a key that isn't instatesthrows.collisiondoesn't block clicks. It only makesinput.over_uitrueover the overlay, so your 3D input code can ignore the pointer there.- The app needs CSS that hides
.modal.hiddenand.modal__container.hidden. The boilerplate has it inapp/css/components/modal/_modal.scss.