You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

54 lines
1.8 KiB

import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["dialog"]
confirm(event) {
// The second pass -- after the player confirmed -- falls through to Turbo.
if (this.confirmed) return
event.preventDefault()
this.pendingForm = event.target
this.dialogTarget.classList.remove("is-confirming", "is-leaving")
this.leaving = false
this.dialogTarget.showModal()
}
// The dialog leaves upwards before the answer is sent, so the wait is however
// long that slide takes -- and nothing at all where the slide doesn't exist.
async ok() {
if (this.leaving) return
await this.#slideOut("is-confirming")
// requestSubmit(), not submit(): the native call skips the submit event, so
// Turbo would miss it and navigate the whole page out of the game frame.
this.confirmed = true
this.pendingForm?.requestSubmit()
}
async cancel() {
if (this.leaving) return
await this.#slideOut("is-leaving")
this.pendingForm = null
}
backdropClick(event) {
if (event.target === this.dialogTarget) this.cancel()
}
// The slide runs while the dialog is still open, so close() only ever lands
// once it is off screen: nothing is left behind for the browser to lay out,
// which is what Safari does with a dialog that outlives its top layer.
async #slideOut(state) {
this.leaving = true
this.dialogTarget.classList.add(state)
// Reading a style forces the class change to resolve, so the transition
// exists by the time we ask for it.
getComputedStyle(this.dialogTarget).translate
const running = this.dialogTarget.getAnimations({ subtree: false })
await Promise.all(running.map((animation) => animation.finished)).catch(() => {})
this.dialogTarget.close()
}
}