@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.
@@ -14,6 +14,13 @@
14
14
  last so generated utilities still beat components. */
15
15
  @layer properties, theme, base, components, utilities, midwest.tailwindcss, midwest.vendor, midwest.color-system, midwest.tokens, midwest.responsive, midwest.dark-mode, midwest.typography, midwest.scrollbars, midwest.components, midwest.utilities;
16
16
 
17
+ /* The generated component AST sidecars (`<name>.ast.json` / `<name>.ast.md`,
18
+ see bin/ast) are DATA, not templates. Exclude them from Tailwind's automatic
19
+ content detection so class-like strings in them never generate stray
20
+ utilities. Paths are relative to this stylesheet. */
21
+ @source not "../../components/midwest/**/*.ast.json";
22
+ @source not "../../components/midwest/**/*.ast.md";
23
+
17
24
  @import './midwest/tailwind.css';
18
25
 
19
26
  @layer
@@ -1,13 +1,30 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
3
  class Form extends Controller {
4
+ static values = {
5
+ // Auto-submit the form (debounced) whenever a field changes.
6
+ autosave: { type: Boolean, default: false },
7
+ autosaveDelay: { type: Number, default: 600 },
8
+ // Emit success/error events and keep buttons interactive after an in-page
9
+ // (non-navigating) Turbo submission.
10
+ ajax: { type: Boolean, default: false }
11
+ };
12
+ autosaveTimer;
4
13
  connect() {
5
14
  this.element.addEventListener("submit", this.handleSubmit);
6
15
  this.element.addEventListener("turbo:submit-end", this.handleTurboEnd);
16
+ if (this.autosaveValue) {
17
+ this.element.addEventListener("input", this.scheduleAutosave);
18
+ this.element.addEventListener("change", this.scheduleAutosave);
19
+ }
7
20
  }
8
21
  disconnect() {
9
22
  this.element.removeEventListener("submit", this.handleSubmit);
10
23
  this.element.removeEventListener("turbo:submit-end", this.handleTurboEnd);
24
+ this.element.removeEventListener("input", this.scheduleAutosave);
25
+ this.element.removeEventListener("change", this.scheduleAutosave);
26
+ if (this.autosaveTimer != null)
27
+ clearTimeout(this.autosaveTimer);
11
28
  }
12
29
  handleSubmit = () => {
13
30
  this.submitButtons.forEach((btn) => {
@@ -15,15 +32,32 @@ class Form extends Controller {
15
32
  btn.disabled = true;
16
33
  });
17
34
  };
18
- // Restore buttons if the submission fails (e.g. a Turbo Frame validation
19
- // error that re-renders the form without a full page transition).
20
35
  handleTurboEnd = (event) => {
21
- if (!event.detail?.success) {
36
+ const detail = event.detail;
37
+ const success = detail?.success ?? false;
38
+ if (!success || this.ajaxValue || this.autosaveValue) {
22
39
  this.submitButtons.forEach((btn) => {
23
40
  btn.classList.remove("loading");
24
41
  btn.disabled = false;
25
42
  });
26
43
  }
44
+ if (this.ajaxValue) {
45
+ this.dispatch(success ? "success" : "error", { detail });
46
+ }
47
+ };
48
+ // Debounce field changes into a single background submission. `requestSubmit`
49
+ // runs constraint validation and fires the `submit` event, so buttons pick up
50
+ // their loading state and Turbo handles the request just like a manual submit.
51
+ scheduleAutosave = () => {
52
+ if (this.autosaveTimer != null)
53
+ clearTimeout(this.autosaveTimer);
54
+ this.autosaveTimer = setTimeout(() => {
55
+ if (typeof this.element.requestSubmit === "function") {
56
+ this.element.requestSubmit();
57
+ } else {
58
+ this.element.submit();
59
+ }
60
+ }, this.autosaveDelayValue);
27
61
  };
28
62
  get submitButtons() {
29
63
  return Array.from(
@@ -1 +1 @@
1
- {"version":3,"file":"form_controller.js","sources":["../../../../../../../app/components/midwest/form/form_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Form extends Controller<HTMLFormElement> {\n connect () {\n this.element.addEventListener('submit', this.handleSubmit)\n this.element.addEventListener('turbo:submit-end', this.handleTurboEnd)\n }\n\n disconnect () {\n this.element.removeEventListener('submit', this.handleSubmit)\n this.element.removeEventListener('turbo:submit-end', this.handleTurboEnd)\n }\n\n private handleSubmit = () => {\n this.submitButtons.forEach(btn => {\n btn.classList.add('loading')\n btn.disabled = true\n })\n }\n\n // Restore buttons if the submission fails (e.g. a Turbo Frame validation\n // error that re-renders the form without a full page transition).\n private handleTurboEnd = (event: Event) => {\n if (!(event as CustomEvent).detail?.success) {\n this.submitButtons.forEach(btn => {\n btn.classList.remove('loading')\n btn.disabled = false\n })\n }\n }\n\n private get submitButtons (): HTMLButtonElement[] {\n return Array.from(\n this.element.querySelectorAll<HTMLButtonElement>('button[type=\"submit\"], button:not([type])')\n )\n }\n}\n"],"names":[],"mappings":";;AAGA,MAAqB,aAAa,UAA4B,CAAA;AAAA,EAC5D,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,OAAQ,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AACzD,IAAA,IAAA,CAAK,OAAQ,CAAA,gBAAA,CAAiB,kBAAoB,EAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAAA,GACvE;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,OAAQ,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AAC5D,IAAA,IAAA,CAAK,OAAQ,CAAA,mBAAA,CAAoB,kBAAoB,EAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAAA,GAC1E;AAAA,EAEQ,eAAe,MAAM;AAC3B,IAAK,IAAA,CAAA,aAAA,CAAc,QAAQ,CAAO,GAAA,KAAA;AAChC,MAAI,GAAA,CAAA,SAAA,CAAU,IAAI,SAAS,CAAA,CAAA;AAC3B,MAAA,GAAA,CAAI,QAAW,GAAA,IAAA,CAAA;AAAA,KAChB,CAAA,CAAA;AAAA,GACH,CAAA;AAAA;AAAA;AAAA,EAIQ,cAAA,GAAiB,CAAC,KAAiB,KAAA;AACzC,IAAI,IAAA,CAAE,KAAsB,CAAA,MAAA,EAAQ,OAAS,EAAA;AAC3C,MAAK,IAAA,CAAA,aAAA,CAAc,QAAQ,CAAO,GAAA,KAAA;AAChC,QAAI,GAAA,CAAA,SAAA,CAAU,OAAO,SAAS,CAAA,CAAA;AAC9B,QAAA,GAAA,CAAI,QAAW,GAAA,KAAA,CAAA;AAAA,OAChB,CAAA,CAAA;AAAA,KACH;AAAA,GACF,CAAA;AAAA,EAEA,IAAY,aAAsC,GAAA;AAChD,IAAA,OAAO,KAAM,CAAA,IAAA;AAAA,MACX,IAAA,CAAK,OAAQ,CAAA,gBAAA,CAAoC,2CAA2C,CAAA;AAAA,KAC9F,CAAA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"form_controller.js","sources":["../../../../../../../app/components/midwest/form/form_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Form extends Controller<HTMLFormElement> {\n static values = {\n // Auto-submit the form (debounced) whenever a field changes.\n autosave: { type: Boolean, default: false },\n autosaveDelay: { type: Number, default: 600 },\n // Emit success/error events and keep buttons interactive after an in-page\n // (non-navigating) Turbo submission.\n ajax: { type: Boolean, default: false }\n }\n\n declare autosaveValue: boolean\n declare autosaveDelayValue: number\n declare ajaxValue: boolean\n\n private autosaveTimer?: ReturnType<typeof setTimeout>\n\n connect () {\n this.element.addEventListener('submit', this.handleSubmit)\n this.element.addEventListener('turbo:submit-end', this.handleTurboEnd)\n if (this.autosaveValue) {\n this.element.addEventListener('input', this.scheduleAutosave)\n this.element.addEventListener('change', this.scheduleAutosave)\n }\n }\n\n disconnect () {\n this.element.removeEventListener('submit', this.handleSubmit)\n this.element.removeEventListener('turbo:submit-end', this.handleTurboEnd)\n this.element.removeEventListener('input', this.scheduleAutosave)\n this.element.removeEventListener('change', this.scheduleAutosave)\n if (this.autosaveTimer != null) clearTimeout(this.autosaveTimer)\n }\n\n private handleSubmit = () => {\n this.submitButtons.forEach(btn => {\n btn.classList.add('loading')\n btn.disabled = true\n })\n }\n\n private handleTurboEnd = (event: Event) => {\n const detail = (event as CustomEvent).detail\n const success: boolean = detail?.success ?? false\n\n // Restore buttons when the submission failed (e.g. a Turbo Frame validation\n // error re-renders the form without a page transition), or whenever the form\n // stays on the page ajax and autosave never navigate away, so a stuck\n // \"loading\" button would otherwise persist.\n if (!success || this.ajaxValue || this.autosaveValue) {\n this.submitButtons.forEach(btn => {\n btn.classList.remove('loading')\n btn.disabled = false\n })\n }\n\n // Let app code react to an in-page submission without a navigation.\n if (this.ajaxValue) {\n this.dispatch(success ? 'success' : 'error', { detail })\n }\n }\n\n // Debounce field changes into a single background submission. `requestSubmit`\n // runs constraint validation and fires the `submit` event, so buttons pick up\n // their loading state and Turbo handles the request just like a manual submit.\n private scheduleAutosave = () => {\n if (this.autosaveTimer != null) clearTimeout(this.autosaveTimer)\n this.autosaveTimer = setTimeout(() => {\n if (typeof this.element.requestSubmit === 'function') {\n this.element.requestSubmit()\n } else {\n this.element.submit()\n }\n }, this.autosaveDelayValue)\n }\n\n private get submitButtons (): HTMLButtonElement[] {\n return Array.from(\n this.element.querySelectorAll<HTMLButtonElement>('button[type=\"submit\"], button:not([type])')\n )\n }\n}\n"],"names":[],"mappings":"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"}
@@ -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(