Don't dismiss on any key, only with N or ESC

Also, this reworks the system to rely on stimulus event handling. This cover cases like unbinding events automatically when the controller get disconnected and such.

See:
https://3.basecamp.com/2914079/buckets/37331921/todos/8617430347
This commit is contained in:
Jorge Manrubia
2025-05-08 11:21:39 +02:00
parent 05e55adbaa
commit 5cd71a7699
3 changed files with 27 additions and 26 deletions
@@ -5,6 +5,10 @@ export default class extends Controller {
static targets = [ "input", "form", "confirmation" ]
static classes = [ "error", "confirmation", "help" ]
disconnect() {
if (this.waitingForConfirmation) { this.#reset() }
}
// Actions
focus() {
@@ -26,6 +30,13 @@ export default class extends Controller {
this.element.classList.remove(this.helpClass)
}
handleKeyPress(event) {
if (this.waitingForConfirmation) {
this.#handleConfirmationKey(event.key.toLowerCase())
event.preventDefault()
}
}
handleCommandResponse(event) {
if (event.detail.success) {
this.#reset()
@@ -74,6 +85,8 @@ export default class extends Controller {
this.formTarget.reset()
this.inputTarget.value = inputValue
this.confirmationTarget.value = ""
this.waitingForConfirmation = false
this.originalInputValue = null
this.element.classList.remove(this.errorClass)
this.element.classList.remove(this.confirmationClass)
@@ -84,35 +97,23 @@ export default class extends Controller {
}
async #requestConfirmation(message) {
const originalInputValue = this.inputTarget.value
this.originalInputValue = this.inputTarget.value
this.element.classList.add(this.confirmationClass)
this.inputTarget.value = `${message}? [Y/n] `
try {
await this.#waitForConfirmation()
this.#submitWithConfirmation(originalInputValue)
} catch {
this.#reset(originalInputValue)
this.waitingForConfirmation = true
}
#handleConfirmationKey(key) {
if (key === "enter" || key === "y") {
this.#submitWithConfirmation()
} else if (key === "escape" || key === "n") {
this.#reset(this.originalInputValue)
}
}
#waitForConfirmation() {
return new Promise((resolve, reject) => {
this.inputTarget.addEventListener("keydown", (event) => {
event.preventDefault()
const key = event.key.toLowerCase()
if (key === "enter" || key === "y") {
resolve()
} else {
reject()
}
}, { once: true })
})
}
#submitWithConfirmation(inputValue) {
this.inputTarget.value = inputValue
#submitWithConfirmation() {
this.inputTarget.value = this.originalInputValue
this.confirmationTarget.value = "confirmed"
this.formTarget.requestSubmit()
}
+2 -2
View File
@@ -4,6 +4,7 @@
data: {
controller: "form",
terminal_target: "form",
turbo_permanent: true,
action: "turbo:submit-end->terminal#focus keydown.meta+k@document->terminal#focus keydown.enter->terminal#executeCommand keydown.esc->terminal#hideHelpMenu turbo:submit-end->terminal#handleCommandResponse"
} do %>
<label class="terminal__label txt-nowrap" for="fizzy_do">Fizzy do &gt;</label>
@@ -15,8 +16,7 @@
class: "terminal__input input fill-transparent unpad",
data: {
terminal_target: "input",
action: "keydown.up->toggle-class#add:prevent keydown.up->navigable-list#selectCurrentOrLast terminal#hideError",
turbo_permanent: true
action: "keydown.up->toggle-class#add:prevent keydown.up->navigable-list#selectCurrentOrLast terminal#hideError"
},
placeholder: "Press ⌘+K to search or type commands…",
spellcheck: "false" %>
+1 -1
View File
@@ -4,7 +4,7 @@
terminal_confirmation_class: "terminal--confirmation",
terminal_help_class: "terminal--showing-help",
toggle_class_toggle_class: "terminal--open",
action: "keydown->navigable-list#navigate focusin->navigable-list#select keydown.esc->toggle-class#remove:stop keydown.esc->terminal#focus keydown.esc->navigable-list#selectLast" } do %>
action: "keydown->terminal#handleKeyPress keydown->navigable-list#navigate focusin->navigable-list#select keydown.esc->toggle-class#remove:stop keydown.esc->terminal#focus keydown.esc->navigable-list#selectLast" } do %>
<%= turbo_frame_tag :recent_commands, src: commands_path, refresh: "morph" %>
<%= render "commands/form" %>