@unabridged/midwest 0.27.3 → 0.27.5

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.
@@ -19,18 +19,30 @@ class Card extends Controller {
19
19
  get flippable() {
20
20
  return this.element.classList.contains("flippable");
21
21
  }
22
+ // Both faces are re-measured whenever either is replaced, which is what happens
23
+ // when a card rendered with `frame:` has its contents swapped by a response.
24
+ // Without this the min-heights keep whatever the faces measured on first
25
+ // connect, and a card whose back grew or shrank is left at the wrong size.
26
+ frontTargetConnected() {
27
+ this.measureFaces();
28
+ }
29
+ backTargetConnected() {
30
+ this.measureFaces();
31
+ }
22
32
  async applyReady() {
23
33
  if (this.flippable) {
24
- this.originalHeightValue = this.frontTarget.offsetHeight;
25
- this.backHeightValue = this.backTarget.offsetHeight;
34
+ this.measureFaces();
26
35
  this.element.classList.add("flip-ready");
27
- this.resizeHandler = () => {
28
- this.originalHeightValue = this.frontTarget.offsetHeight;
29
- this.backHeightValue = this.backTarget.offsetHeight;
30
- };
36
+ this.resizeHandler = () => this.measureFaces();
31
37
  window.addEventListener("resize", this.resizeHandler);
32
38
  }
33
39
  }
40
+ measureFaces() {
41
+ if (!this.flippable || !this.hasFrontTarget || !this.hasBackTarget)
42
+ return;
43
+ this.originalHeightValue = this.frontTarget.offsetHeight;
44
+ this.backHeightValue = this.backTarget.offsetHeight;
45
+ }
34
46
  originalHeightValueChanged() {
35
47
  this.element.style.setProperty("--min-height", `${this.originalHeightValue}px`);
36
48
  }
@@ -40,6 +52,31 @@ class Card extends Controller {
40
52
  flip() {
41
53
  this.element.classList.toggle("flipped");
42
54
  }
55
+ // Returns the card to its front, animating rather than cutting because the
56
+ // element is never replaced. Pairs with `frame:`: a form on the back can save,
57
+ // let the response swap the faces, and turn the card back over.
58
+ //
59
+ // data-action="turbo:frame-render->midwest-card#returnToFront"
60
+ //
61
+ // Bind it to `turbo:frame-render`, not `turbo:submit-end`. The form lives
62
+ // inside the frame the response replaces, so by the time the submission ends
63
+ // it is detached — and Turbo redispatches events whose target is disconnected
64
+ // onto documentElement instead, where they never reach this card.
65
+ // `turbo:frame-render` targets the frame itself, which survives the swap.
66
+ //
67
+ // A failed response is ignored so a form that came back carrying errors stays
68
+ // where the errors are: `success` covers turbo:submit-end, `fetchResponse`
69
+ // covers turbo:frame-render. An event carrying neither — a click, a custom
70
+ // event — is an unconditional request to show the front.
71
+ returnToFront(event) {
72
+ const detail = event?.detail;
73
+ if (detail?.success === false)
74
+ return;
75
+ const status = detail?.fetchResponse?.statusCode;
76
+ if (typeof status === "number" && status >= 400)
77
+ return;
78
+ this.element.classList.remove("flipped");
79
+ }
43
80
  }
44
81
 
45
82
  export { Card as default };
@@ -1 +1 @@
1
- {"version":3,"file":"card_component_controller.js","sources":["../../../../../../../app/components/midwest/card_component/card_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Card extends Controller<HTMLFormElement> {\n static targets = ['back', 'front']\n static values = {\n originalHeight: { type: Number, default: 0 },\n backHeight: { type: Number, default: 0 }\n }\n\n declare readonly hasBackTarget: boolean\n declare readonly hasFrontTarget: boolean\n declare readonly backTarget: HTMLInputElement\n declare readonly backTargets: HTMLInputElement[]\n declare readonly frontTarget: HTMLInputElement\n declare readonly frontTargets: HTMLInputElement[]\n\n declare originalHeightValue: number\n declare backHeightValue: number\n declare readonly hasOriginalHeightValue: boolean\n declare readonly hasBackHeightValue: boolean\n\n private resizeHandler: (() => void) | null = null\n\n connect () {\n this.applyReady()\n }\n\n disconnect () {\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler)\n this.resizeHandler = null\n }\n }\n\n get flippable () {\n return this.element.classList.contains('flippable')\n }\n\n async applyReady () {\n if (this.flippable) {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n\n this.element.classList.add('flip-ready')\n\n this.resizeHandler = () => {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n }\n window.addEventListener('resize', this.resizeHandler)\n }\n }\n\n originalHeightValueChanged () {\n this.element.style.setProperty('--min-height', `${this.originalHeightValue}px`)\n }\n\n backHeightValueChanged () {\n this.element.style.setProperty('--flipped-min-height', `${this.backHeightValue}px`)\n }\n\n flip () {\n this.element.classList.toggle('flipped')\n }\n}\n"],"names":[],"mappings":";;AAGA,MAAqB,aAAa,UAA4B,CAAA;AAAA,EAC5D,OAAO,OAAA,GAAU,CAAC,MAAA,EAAQ,OAAO,CAAA,CAAA;AAAA,EACjC,OAAO,MAAS,GAAA;AAAA,IACd,cAAgB,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,IAC3C,UAAY,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,GACzC,CAAA;AAAA,EAcQ,aAAqC,GAAA,IAAA,CAAA;AAAA,EAE7C,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,UAAW,EAAA,CAAA;AAAA,GAClB;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAI,KAAK,aAAe,EAAA;AACtB,MAAO,MAAA,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AACvD,MAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAA;AAAA,KACvB;AAAA,GACF;AAAA,EAEA,IAAI,SAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,OAAA,CAAQ,SAAU,CAAA,QAAA,CAAS,WAAW,CAAA,CAAA;AAAA,GACpD;AAAA,EAEA,MAAM,UAAc,GAAA;AAClB,IAAA,IAAI,KAAK,SAAW,EAAA;AAClB,MAAK,IAAA,CAAA,mBAAA,GAAsB,KAAK,WAAY,CAAA,YAAA,CAAA;AAC5C,MAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAW,CAAA,YAAA,CAAA;AAEvC,MAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,YAAY,CAAA,CAAA;AAEvC,MAAA,IAAA,CAAK,gBAAgB,MAAM;AACzB,QAAK,IAAA,CAAA,mBAAA,GAAsB,KAAK,WAAY,CAAA,YAAA,CAAA;AAC5C,QAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAW,CAAA,YAAA,CAAA;AAAA,OACzC,CAAA;AACA,MAAO,MAAA,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AAAA,KACtD;AAAA,GACF;AAAA,EAEA,0BAA8B,GAAA;AAC5B,IAAA,IAAA,CAAK,QAAQ,KAAM,CAAA,WAAA,CAAY,cAAgB,EAAA,CAAA,EAAG,KAAK,mBAAuB,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,GAChF;AAAA,EAEA,sBAA0B,GAAA;AACxB,IAAA,IAAA,CAAK,QAAQ,KAAM,CAAA,WAAA,CAAY,sBAAwB,EAAA,CAAA,EAAG,KAAK,eAAmB,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,GACpF;AAAA,EAEA,IAAQ,GAAA;AACN,IAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,MAAA,CAAO,SAAS,CAAA,CAAA;AAAA,GACzC;AACF;;;;"}
1
+ {"version":3,"file":"card_component_controller.js","sources":["../../../../../../../app/components/midwest/card_component/card_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Card extends Controller<HTMLFormElement> {\n static targets = ['back', 'front']\n static values = {\n originalHeight: { type: Number, default: 0 },\n backHeight: { type: Number, default: 0 }\n }\n\n declare readonly hasBackTarget: boolean\n declare readonly hasFrontTarget: boolean\n declare readonly backTarget: HTMLInputElement\n declare readonly backTargets: HTMLInputElement[]\n declare readonly frontTarget: HTMLInputElement\n declare readonly frontTargets: HTMLInputElement[]\n\n declare originalHeightValue: number\n declare backHeightValue: number\n declare readonly hasOriginalHeightValue: boolean\n declare readonly hasBackHeightValue: boolean\n\n private resizeHandler: (() => void) | null = null\n\n connect () {\n this.applyReady()\n }\n\n disconnect () {\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler)\n this.resizeHandler = null\n }\n }\n\n get flippable () {\n return this.element.classList.contains('flippable')\n }\n\n // Both faces are re-measured whenever either is replaced, which is what happens\n // when a card rendered with `frame:` has its contents swapped by a response.\n // Without this the min-heights keep whatever the faces measured on first\n // connect, and a card whose back grew or shrank is left at the wrong size.\n frontTargetConnected () {\n this.measureFaces()\n }\n\n backTargetConnected () {\n this.measureFaces()\n }\n\n async applyReady () {\n if (this.flippable) {\n this.measureFaces()\n\n this.element.classList.add('flip-ready')\n\n this.resizeHandler = () => this.measureFaces()\n window.addEventListener('resize', this.resizeHandler)\n }\n }\n\n private measureFaces () {\n // A target callback can fire before its partner is in the DOM, both on first\n // render and mid-swap, so neither height is read until both faces exist.\n if (!this.flippable || !this.hasFrontTarget || !this.hasBackTarget) return\n\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n }\n\n originalHeightValueChanged () {\n this.element.style.setProperty('--min-height', `${this.originalHeightValue}px`)\n }\n\n backHeightValueChanged () {\n this.element.style.setProperty('--flipped-min-height', `${this.backHeightValue}px`)\n }\n\n flip () {\n this.element.classList.toggle('flipped')\n }\n\n // Returns the card to its front, animating rather than cutting because the\n // element is never replaced. Pairs with `frame:`: a form on the back can save,\n // let the response swap the faces, and turn the card back over.\n //\n // data-action=\"turbo:frame-render->midwest-card#returnToFront\"\n //\n // Bind it to `turbo:frame-render`, not `turbo:submit-end`. The form lives\n // inside the frame the response replaces, so by the time the submission ends\n // it is detached — and Turbo redispatches events whose target is disconnected\n // onto documentElement instead, where they never reach this card.\n // `turbo:frame-render` targets the frame itself, which survives the swap.\n //\n // A failed response is ignored so a form that came back carrying errors stays\n // where the errors are: `success` covers turbo:submit-end, `fetchResponse`\n // covers turbo:frame-render. An event carrying neither — a click, a custom\n // event — is an unconditional request to show the front.\n returnToFront (event?: Event) {\n const detail = (event as CustomEvent | undefined)?.detail\n\n if (detail?.success === false) return\n\n const status = detail?.fetchResponse?.statusCode\n if (typeof status === 'number' && status >= 400) return\n\n this.element.classList.remove('flipped')\n }\n}\n"],"names":[],"mappings":"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"}
@@ -26,10 +26,14 @@ declare class Card extends Controller<HTMLFormElement> {
26
26
  connect(): void;
27
27
  disconnect(): void;
28
28
  get flippable(): boolean;
29
+ frontTargetConnected(): void;
30
+ backTargetConnected(): void;
29
31
  applyReady(): Promise<void>;
32
+ private measureFaces;
30
33
  originalHeightValueChanged(): void;
31
34
  backHeightValueChanged(): void;
32
35
  flip(): void;
36
+ returnToFront(event?: Event): void;
33
37
  }
34
38
 
35
39
  declare class Banner extends Controller<HTMLFormElement> {
@@ -507,18 +507,30 @@ class Card extends Controller {
507
507
  get flippable() {
508
508
  return this.element.classList.contains("flippable");
509
509
  }
510
+ // Both faces are re-measured whenever either is replaced, which is what happens
511
+ // when a card rendered with `frame:` has its contents swapped by a response.
512
+ // Without this the min-heights keep whatever the faces measured on first
513
+ // connect, and a card whose back grew or shrank is left at the wrong size.
514
+ frontTargetConnected() {
515
+ this.measureFaces();
516
+ }
517
+ backTargetConnected() {
518
+ this.measureFaces();
519
+ }
510
520
  async applyReady() {
511
521
  if (this.flippable) {
512
- this.originalHeightValue = this.frontTarget.offsetHeight;
513
- this.backHeightValue = this.backTarget.offsetHeight;
522
+ this.measureFaces();
514
523
  this.element.classList.add("flip-ready");
515
- this.resizeHandler = () => {
516
- this.originalHeightValue = this.frontTarget.offsetHeight;
517
- this.backHeightValue = this.backTarget.offsetHeight;
518
- };
524
+ this.resizeHandler = () => this.measureFaces();
519
525
  window.addEventListener("resize", this.resizeHandler);
520
526
  }
521
527
  }
528
+ measureFaces() {
529
+ if (!this.flippable || !this.hasFrontTarget || !this.hasBackTarget)
530
+ return;
531
+ this.originalHeightValue = this.frontTarget.offsetHeight;
532
+ this.backHeightValue = this.backTarget.offsetHeight;
533
+ }
522
534
  originalHeightValueChanged() {
523
535
  this.element.style.setProperty("--min-height", `${this.originalHeightValue}px`);
524
536
  }
@@ -528,6 +540,31 @@ class Card extends Controller {
528
540
  flip() {
529
541
  this.element.classList.toggle("flipped");
530
542
  }
543
+ // Returns the card to its front, animating rather than cutting because the
544
+ // element is never replaced. Pairs with `frame:`: a form on the back can save,
545
+ // let the response swap the faces, and turn the card back over.
546
+ //
547
+ // data-action="turbo:frame-render->midwest-card#returnToFront"
548
+ //
549
+ // Bind it to `turbo:frame-render`, not `turbo:submit-end`. The form lives
550
+ // inside the frame the response replaces, so by the time the submission ends
551
+ // it is detached — and Turbo redispatches events whose target is disconnected
552
+ // onto documentElement instead, where they never reach this card.
553
+ // `turbo:frame-render` targets the frame itself, which survives the swap.
554
+ //
555
+ // A failed response is ignored so a form that came back carrying errors stays
556
+ // where the errors are: `success` covers turbo:submit-end, `fetchResponse`
557
+ // covers turbo:frame-render. An event carrying neither — a click, a custom
558
+ // event — is an unconditional request to show the front.
559
+ returnToFront(event) {
560
+ const detail = event?.detail;
561
+ if (detail?.success === false)
562
+ return;
563
+ const status = detail?.fetchResponse?.statusCode;
564
+ if (typeof status === "number" && status >= 400)
565
+ return;
566
+ this.element.classList.remove("flipped");
567
+ }
531
568
  }
532
569
 
533
570
  class Banner extends Controller {