@unabridged/midwest 0.24.4 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3579,13 +3579,30 @@ class FormLiveSummary extends Controller {
3579
3579
  }
3580
3580
 
3581
3581
  class Form extends Controller {
3582
+ static values = {
3583
+ // Auto-submit the form (debounced) whenever a field changes.
3584
+ autosave: { type: Boolean, default: false },
3585
+ autosaveDelay: { type: Number, default: 600 },
3586
+ // Emit success/error events and keep buttons interactive after an in-page
3587
+ // (non-navigating) Turbo submission.
3588
+ ajax: { type: Boolean, default: false }
3589
+ };
3590
+ autosaveTimer;
3582
3591
  connect() {
3583
3592
  this.element.addEventListener("submit", this.handleSubmit);
3584
3593
  this.element.addEventListener("turbo:submit-end", this.handleTurboEnd);
3594
+ if (this.autosaveValue) {
3595
+ this.element.addEventListener("input", this.scheduleAutosave);
3596
+ this.element.addEventListener("change", this.scheduleAutosave);
3597
+ }
3585
3598
  }
3586
3599
  disconnect() {
3587
3600
  this.element.removeEventListener("submit", this.handleSubmit);
3588
3601
  this.element.removeEventListener("turbo:submit-end", this.handleTurboEnd);
3602
+ this.element.removeEventListener("input", this.scheduleAutosave);
3603
+ this.element.removeEventListener("change", this.scheduleAutosave);
3604
+ if (this.autosaveTimer != null)
3605
+ clearTimeout(this.autosaveTimer);
3589
3606
  }
3590
3607
  handleSubmit = () => {
3591
3608
  this.submitButtons.forEach((btn) => {
@@ -3593,15 +3610,32 @@ class Form extends Controller {
3593
3610
  btn.disabled = true;
3594
3611
  });
3595
3612
  };
3596
- // Restore buttons if the submission fails (e.g. a Turbo Frame validation
3597
- // error that re-renders the form without a full page transition).
3598
3613
  handleTurboEnd = (event) => {
3599
- if (!event.detail?.success) {
3614
+ const detail = event.detail;
3615
+ const success = detail?.success ?? false;
3616
+ if (!success || this.ajaxValue || this.autosaveValue) {
3600
3617
  this.submitButtons.forEach((btn) => {
3601
3618
  btn.classList.remove("loading");
3602
3619
  btn.disabled = false;
3603
3620
  });
3604
3621
  }
3622
+ if (this.ajaxValue) {
3623
+ this.dispatch(success ? "success" : "error", { detail });
3624
+ }
3625
+ };
3626
+ // Debounce field changes into a single background submission. `requestSubmit`
3627
+ // runs constraint validation and fires the `submit` event, so buttons pick up
3628
+ // their loading state and Turbo handles the request just like a manual submit.
3629
+ scheduleAutosave = () => {
3630
+ if (this.autosaveTimer != null)
3631
+ clearTimeout(this.autosaveTimer);
3632
+ this.autosaveTimer = setTimeout(() => {
3633
+ if (typeof this.element.requestSubmit === "function") {
3634
+ this.element.requestSubmit();
3635
+ } else {
3636
+ this.element.submit();
3637
+ }
3638
+ }, this.autosaveDelayValue);
3605
3639
  };
3606
3640
  get submitButtons() {
3607
3641
  return Array.from(