@unabridged/midwest 0.8.2 → 0.10.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.
- package/README.md +5 -5
- package/app/assets/icons/available-icons.yml +11 -0
- package/app/assets/icons/loader-audio.svg +29 -0
- package/app/assets/icons/loader-ball-triangle.svg +46 -0
- package/app/assets/icons/loader-bars.svg +52 -0
- package/app/assets/icons/loader-circles.svg +20 -0
- package/app/assets/icons/loader-grid.svg +56 -0
- package/app/assets/icons/loader-oval.svg +17 -0
- package/app/assets/icons/loader-puff.svg +37 -0
- package/app/assets/icons/loader-rings.svg +42 -0
- package/app/assets/icons/loader-spinning-circles.svg +55 -0
- package/app/assets/icons/loader-tail-spin.svg +32 -0
- package/app/assets/icons/loader-three-dots.svg +33 -0
- package/app/assets/javascript/midwest/index.ts +2 -10
- package/app/assets/javascript/midwest.js +371 -82
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest/color-system.css +0 -2
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +4 -2
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +2 -10
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/card_component/card_component_controller.js +10 -2
- package/dist/javascript/collection/app/components/midwest/card_component/card_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +62 -2
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/dialog_component/dialog_component_controller.js +58 -17
- package/dist/javascript/collection/app/components/midwest/dialog_component/dialog_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js +62 -2
- package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/file_component/file_component_controller.js +49 -22
- package/dist/javascript/collection/app/components/midwest/form/file_component/file_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/form_controller.js +36 -0
- package/dist/javascript/collection/app/components/midwest/form/form_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js +48 -0
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/prose_component/prose_component_controller.js +2 -1
- package/dist/javascript/collection/app/components/midwest/prose_component/prose_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js +32 -0
- package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/tooltip_component/tooltip_component_controller.js +15 -1
- package/dist/javascript/collection/app/components/midwest/tooltip_component/tooltip_component_controller.js.map +1 -1
- package/dist/javascript/midwest.d.ts +2 -0
- package/dist/javascript/midwest.js +371 -82
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +2 -1
|
@@ -2,38 +2,30 @@ import Card from '../../../components/midwest/card_component/card_component_cont
|
|
|
2
2
|
export { default as Card } from '../../../components/midwest/card_component/card_component_controller.js';
|
|
3
3
|
import Banner from '../../../components/midwest/banner_component/banner_component_controller.js';
|
|
4
4
|
export { default as Banner } from '../../../components/midwest/banner_component/banner_component_controller.js';
|
|
5
|
-
import Callout from '../../../components/midwest/callout_component/callout_component_controller.js';
|
|
6
5
|
import Input from '../../../components/midwest/form/input_component/input_component_controller.js';
|
|
7
6
|
import File from '../../../components/midwest/form/file_component/file_component_controller.js';
|
|
8
|
-
import Switch from '../../../components/midwest/form/switch_component/switch_component_controller.js';
|
|
9
7
|
import Dropdown from '../../../components/midwest/dropdown_component/dropdown_component_controller.js';
|
|
10
|
-
import Avatar from '../../../components/midwest/avatar_component/avatar_component_controller.js';
|
|
11
8
|
import Prose from '../../../components/midwest/prose_component/prose_component_controller.js';
|
|
12
9
|
import Dialog from '../../../components/midwest/dialog_component/dialog_component_controller.js';
|
|
13
|
-
import Video from '../../../components/midwest/video_component/video_component_controller.js';
|
|
14
|
-
import DropdownItem from '../../../components/midwest/dropdown_item_component/dropdown_item_component_controller.js';
|
|
15
10
|
import Tabs from '../../../components/midwest/tabs_component/tabs_component_controller.js';
|
|
16
11
|
import Tooltip from '../../../components/midwest/tooltip_component/tooltip_component_controller.js';
|
|
17
12
|
import Carousel from '../../../components/midwest/carousel_component/carousel_component_controller.js';
|
|
18
13
|
import FormLiveSummary from '../../../components/midwest/form/live_summary_component/live_summary_component_controller.js';
|
|
14
|
+
import Form from '../../../components/midwest/form/form_controller.js';
|
|
19
15
|
|
|
20
16
|
function registerMidwestControllers(application) {
|
|
21
17
|
application.register("midwest-card", Card);
|
|
22
18
|
application.register("midwest-banner", Banner);
|
|
23
|
-
application.register("midwest-callout", Callout);
|
|
24
19
|
application.register("midwest-input", Input);
|
|
25
20
|
application.register("midwest-file", File);
|
|
26
|
-
application.register("midwest-switch", Switch);
|
|
27
21
|
application.register("midwest-dropdown", Dropdown);
|
|
28
|
-
application.register("midwest-avatar", Avatar);
|
|
29
22
|
application.register("midwest-prose", Prose);
|
|
30
23
|
application.register("midwest-dialog", Dialog);
|
|
31
|
-
application.register("midwest-video", Video);
|
|
32
|
-
application.register("midwest-dropdown-item", DropdownItem);
|
|
33
24
|
application.register("midwest-tabs", Tabs);
|
|
34
25
|
application.register("midwest-tooltip", Tooltip);
|
|
35
26
|
application.register("midwest-carousel", Carousel);
|
|
36
27
|
application.register("midwest-form-live-summary", FormLiveSummary);
|
|
28
|
+
application.register("midwest-form", Form);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
31
|
export { registerMidwestControllers };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../../../app/assets/javascript/midwest/index.ts"],"sourcesContent":["import Card from '../../../components/midwest/card_component/card_component_controller'\nimport Banner from '../../../components/midwest/banner_component/banner_component_controller'\nimport
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../../app/assets/javascript/midwest/index.ts"],"sourcesContent":["import Card from '../../../components/midwest/card_component/card_component_controller'\nimport Banner from '../../../components/midwest/banner_component/banner_component_controller'\nimport Input from '../../../components/midwest/form/input_component/input_component_controller'\nimport File from '../../../components/midwest/form/file_component/file_component_controller'\nimport Dropdown from '../../../components/midwest/dropdown_component/dropdown_component_controller'\nimport Prose from '../../../components/midwest/prose_component/prose_component_controller'\nimport Dialog from '../../../components/midwest/dialog_component/dialog_component_controller'\nimport Tabs from '../../../components/midwest/tabs_component/tabs_component_controller'\nimport Tooltip from '../../../components/midwest/tooltip_component/tooltip_component_controller'\nimport Carousel from '../../../components/midwest/carousel_component/carousel_component_controller'\nimport FormLiveSummary from '../../../components/midwest/form/live_summary_component/live_summary_component_controller'\nimport Form from '../../../components/midwest/form/form_controller'\n/* IMPORTS */\n\nexport { Card, Banner }\n\nexport function registerMidwestControllers (application: any) {\n application.register('midwest-card', Card)\n application.register('midwest-banner', Banner)\n application.register('midwest-input', Input)\n application.register('midwest-file', File)\n application.register('midwest-dropdown', Dropdown)\n application.register('midwest-prose', Prose)\n application.register('midwest-dialog', Dialog)\n application.register('midwest-tabs', Tabs)\n application.register('midwest-tooltip', Tooltip)\n application.register('midwest-carousel', Carousel)\n application.register('midwest-form-live-summary', FormLiveSummary)\n application.register('midwest-form', Form)\n /* EXPORTS */\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAgBO,SAAS,2BAA4B,WAAkB,EAAA;AAC5D,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,kBAAkB,MAAM,CAAA,CAAA;AAC7C,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,oBAAoB,QAAQ,CAAA,CAAA;AACjD,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,kBAAkB,MAAM,CAAA,CAAA;AAC7C,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,mBAAmB,OAAO,CAAA,CAAA;AAC/C,EAAY,WAAA,CAAA,QAAA,CAAS,oBAAoB,QAAQ,CAAA,CAAA;AACjD,EAAY,WAAA,CAAA,QAAA,CAAS,6BAA6B,eAAe,CAAA,CAAA;AACjE,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AAE3C;;;;"}
|
|
@@ -6,9 +6,16 @@ class Card extends Controller {
|
|
|
6
6
|
originalHeight: { type: Number, default: 0 },
|
|
7
7
|
backHeight: { type: Number, default: 0 }
|
|
8
8
|
};
|
|
9
|
+
resizeHandler = null;
|
|
9
10
|
connect() {
|
|
10
11
|
this.applyReady();
|
|
11
12
|
}
|
|
13
|
+
disconnect() {
|
|
14
|
+
if (this.resizeHandler) {
|
|
15
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
16
|
+
this.resizeHandler = null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
12
19
|
get flippable() {
|
|
13
20
|
return this.element.classList.contains("flippable");
|
|
14
21
|
}
|
|
@@ -17,10 +24,11 @@ class Card extends Controller {
|
|
|
17
24
|
this.originalHeightValue = this.frontTarget.offsetHeight;
|
|
18
25
|
this.backHeightValue = this.backTarget.offsetHeight;
|
|
19
26
|
this.element.classList.add("flip-ready");
|
|
20
|
-
|
|
27
|
+
this.resizeHandler = () => {
|
|
21
28
|
this.originalHeightValue = this.frontTarget.offsetHeight;
|
|
22
29
|
this.backHeightValue = this.backTarget.offsetHeight;
|
|
23
|
-
}
|
|
30
|
+
};
|
|
31
|
+
window.addEventListener("resize", this.resizeHandler);
|
|
24
32
|
}
|
|
25
33
|
}
|
|
26
34
|
originalHeightValueChanged() {
|
|
@@ -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 connect () {\n this.applyReady()\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 this.element.classList.add('flip-ready')\n\n
|
|
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 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;AACvC,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;;;;"}
|
|
@@ -20,16 +20,24 @@ class Carousel extends Controller {
|
|
|
20
20
|
observer = null;
|
|
21
21
|
_currentIndex = 0;
|
|
22
22
|
_maxUnlocked = 0;
|
|
23
|
+
_lastTouchX = 0;
|
|
23
24
|
connect() {
|
|
24
25
|
this.setupObserver();
|
|
25
26
|
this.updateNavigation();
|
|
26
27
|
if (this.wizardValue) {
|
|
27
28
|
this.element.addEventListener("keydown", this.handleKeydown);
|
|
29
|
+
this.trackTarget.addEventListener("wheel", this.handleWheel, { passive: false });
|
|
30
|
+
this.trackTarget.addEventListener("touchstart", this.handleTouchStart, { passive: true });
|
|
31
|
+
this.trackTarget.addEventListener("touchmove", this.handleTouchMove, { passive: false });
|
|
32
|
+
this.updateSlideAccessibility();
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
disconnect() {
|
|
31
36
|
this.observer?.disconnect();
|
|
32
37
|
this.element.removeEventListener("keydown", this.handleKeydown);
|
|
38
|
+
this.trackTarget.removeEventListener("wheel", this.handleWheel);
|
|
39
|
+
this.trackTarget.removeEventListener("touchstart", this.handleTouchStart);
|
|
40
|
+
this.trackTarget.removeEventListener("touchmove", this.handleTouchMove);
|
|
33
41
|
}
|
|
34
42
|
next() {
|
|
35
43
|
this.trackTarget.scrollBy({ left: this.trackTarget.clientWidth, behavior: "smooth" });
|
|
@@ -54,10 +62,13 @@ class Carousel extends Controller {
|
|
|
54
62
|
const nextIndex = this._currentIndex + 1;
|
|
55
63
|
if (nextIndex > this._maxUnlocked) {
|
|
56
64
|
this._maxUnlocked = nextIndex;
|
|
65
|
+
this.updateSlideAccessibility();
|
|
57
66
|
}
|
|
58
67
|
this.next();
|
|
59
68
|
}
|
|
60
69
|
scrolled() {
|
|
70
|
+
if (this.wizardValue)
|
|
71
|
+
this.clampToFrontier();
|
|
61
72
|
this.updateCurrentIndex();
|
|
62
73
|
this.updateNavigation();
|
|
63
74
|
}
|
|
@@ -75,9 +86,49 @@ class Carousel extends Controller {
|
|
|
75
86
|
event.preventDefault();
|
|
76
87
|
this.unlockNext();
|
|
77
88
|
};
|
|
89
|
+
// Blocks wheel-based horizontal scrolling past the wizard frontier.
|
|
90
|
+
handleWheel = (event) => {
|
|
91
|
+
const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth;
|
|
92
|
+
if (event.deltaX > 0 && this.trackTarget.scrollLeft >= maxLeft - 2) {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
handleTouchStart = (event) => {
|
|
97
|
+
this._lastTouchX = event.touches[0].clientX;
|
|
98
|
+
};
|
|
99
|
+
// Blocks touch-swipe scrolling past the wizard frontier. Tracks incremental
|
|
100
|
+
// delta per move event so direction is accurate mid-gesture.
|
|
101
|
+
handleTouchMove = (event) => {
|
|
102
|
+
const currentX = event.touches[0].clientX;
|
|
103
|
+
const delta = currentX - this._lastTouchX;
|
|
104
|
+
this._lastTouchX = currentX;
|
|
105
|
+
const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth;
|
|
106
|
+
if (delta < 0 && this.trackTarget.scrollLeft >= maxLeft - 2) {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
78
110
|
get slides() {
|
|
79
111
|
return Array.from(this.trackTarget.children);
|
|
80
112
|
}
|
|
113
|
+
// Snaps scroll position back to the frontier if the user somehow scrolled
|
|
114
|
+
// past it (e.g. momentum after a partially-blocked gesture).
|
|
115
|
+
clampToFrontier() {
|
|
116
|
+
const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth;
|
|
117
|
+
if (this.trackTarget.scrollLeft > maxLeft + 2) {
|
|
118
|
+
this.trackTarget.scrollLeft = maxLeft;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Applies/removes `inert` on each slide based on the wizard frontier,
|
|
122
|
+
// removing locked slides from the tab order and accessibility tree.
|
|
123
|
+
updateSlideAccessibility() {
|
|
124
|
+
this.slides.forEach((slide, i) => {
|
|
125
|
+
if (i > this._maxUnlocked) {
|
|
126
|
+
slide.setAttribute("inert", "");
|
|
127
|
+
} else {
|
|
128
|
+
slide.removeAttribute("inert");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
81
132
|
updateCurrentIndex() {
|
|
82
133
|
const track = this.trackTarget;
|
|
83
134
|
if (track.clientWidth > 0) {
|
|
@@ -94,7 +145,15 @@ class Carousel extends Controller {
|
|
|
94
145
|
entries.forEach((entry) => {
|
|
95
146
|
const index = this.slides.indexOf(entry.target);
|
|
96
147
|
if (index >= 0) {
|
|
97
|
-
this.dotTargets[index]
|
|
148
|
+
const dot = this.dotTargets[index];
|
|
149
|
+
if (!dot)
|
|
150
|
+
return;
|
|
151
|
+
dot.classList.toggle("active", entry.isIntersecting);
|
|
152
|
+
if (entry.isIntersecting) {
|
|
153
|
+
dot.setAttribute("aria-current", "true");
|
|
154
|
+
} else {
|
|
155
|
+
dot.removeAttribute("aria-current");
|
|
156
|
+
}
|
|
98
157
|
}
|
|
99
158
|
});
|
|
100
159
|
},
|
|
@@ -109,8 +168,9 @@ class Carousel extends Controller {
|
|
|
109
168
|
if (this.hasPrevTarget)
|
|
110
169
|
this.prevTarget.classList.toggle("hide", atStart);
|
|
111
170
|
if (this.hasNextTarget) {
|
|
171
|
+
const atLastSlide = this._currentIndex >= this.slides.length - 1;
|
|
112
172
|
const frontierReached = this.wizardValue && this._currentIndex >= this._maxUnlocked;
|
|
113
|
-
this.nextTarget.classList.toggle("hide", atEnd || frontierReached);
|
|
173
|
+
this.nextTarget.classList.toggle("hide", atEnd || atLastSlide || frontierReached);
|
|
114
174
|
}
|
|
115
175
|
if (this.wizardValue && this.hasDotTarget) {
|
|
116
176
|
this.dotTargets.forEach((dot, i) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"carousel_component_controller.js","sources":["../../../../../../../app/components/midwest/carousel_component/carousel_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types where pressing Enter in a form does NOT normally submit it.\n// For all other input types, Enter submits — so wizard mode intercepts it.\nconst NON_SUBMITTING_INPUT_TYPES = new Set([\n 'button', 'checkbox', 'color', 'file', 'hidden', 'image', 'radio', 'range', 'reset', 'submit'\n])\n\nexport default class Carousel extends Controller<HTMLElement> {\n static targets = ['track', 'prev', 'next', 'dot']\n static values = {\n wizard: { type: Boolean, default: false }\n }\n\n declare readonly trackTarget: HTMLElement\n declare readonly prevTarget: HTMLButtonElement\n declare readonly nextTarget: HTMLButtonElement\n declare readonly dotTargets: HTMLButtonElement[]\n declare readonly hasPrevTarget: boolean\n declare readonly hasNextTarget: boolean\n declare readonly hasDotTarget: boolean\n declare wizardValue: boolean\n\n private observer: IntersectionObserver | null = null\n private _currentIndex = 0\n private _maxUnlocked = 0\n\n connect () {\n this.setupObserver()\n this.updateNavigation()\n if (this.wizardValue) {\n this.element.addEventListener('keydown', this.handleKeydown)\n }\n }\n\n disconnect () {\n this.observer?.disconnect()\n this.element.removeEventListener('keydown', this.handleKeydown)\n }\n\n next () {\n this.trackTarget.scrollBy({ left: this.trackTarget.clientWidth, behavior: 'smooth' })\n }\n\n previous () {\n this.trackTarget.scrollBy({ left: -this.trackTarget.clientWidth, behavior: 'smooth' })\n }\n\n goto (event: Event) {\n const button = event.currentTarget as HTMLButtonElement\n const index = parseInt(button.dataset.index ?? '0', 10)\n const slide = this.slides[index]\n slide?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })\n }\n\n // Unlocks the next slide and advances to it. Intended for wizard mode: wire\n // a \"Continue\" button inside a slide to this action so users progress\n // linearly through steps before the carousel nav becomes available.\n //\n // <button type=\"button\" data-action=\"click->midwest-carousel#unlockNext\">\n // Continue\n // </button>\n unlockNext () {\n const nextIndex = this._currentIndex + 1\n if (nextIndex > this._maxUnlocked) {\n this._maxUnlocked = nextIndex\n }\n this.next()\n }\n\n scrolled () {\n this.updateCurrentIndex()\n this.updateNavigation()\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n private handleKeydown = (event: KeyboardEvent) => {\n if (event.key !== 'Enter') return\n\n const target = event.target as HTMLElement\n // Only intercept Enter on text-like inputs; textarea newlines and button\n // activations should pass through untouched.\n if (target.tagName === 'TEXTAREA' || target.tagName !== 'INPUT') return\n if (NON_SUBMITTING_INPUT_TYPES.has((target as HTMLInputElement).type)) return\n\n // On the final step let Enter submit the form normally.\n if (this._currentIndex >= this.slides.length - 1) return\n\n event.preventDefault()\n this.unlockNext()\n }\n\n private get slides (): HTMLElement[] {\n return Array.from(this.trackTarget.children) as HTMLElement[]\n }\n\n private updateCurrentIndex () {\n const track = this.trackTarget\n if (track.clientWidth > 0) {\n this._currentIndex = Math.round(track.scrollLeft / track.clientWidth)\n }\n }\n\n private setupObserver () {\n if (!this.hasDotTarget) return\n if (!('IntersectionObserver' in window)) return\n\n this.observer = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n const index = this.slides.indexOf(entry.target as HTMLElement)\n if (index >= 0) {\n this.dotTargets[index]?.classList.toggle('active', entry.isIntersecting)\n }\n })\n },\n { root: this.trackTarget, threshold: 0.5 }\n )\n\n this.slides.forEach(slide => this.observer?.observe(slide))\n }\n\n private updateNavigation () {\n const track = this.trackTarget\n const atStart = track.scrollLeft <= 0\n const atEnd = track.scrollLeft >= track.scrollWidth - track.clientWidth - 1\n\n if (this.hasPrevTarget) this.prevTarget.classList.toggle('hide', atStart)\n\n if (this.hasNextTarget) {\n const frontierReached = this.wizardValue && this._currentIndex >= this._maxUnlocked\n this.nextTarget.classList.toggle('hide', atEnd || frontierReached)\n }\n\n if (this.wizardValue && this.hasDotTarget) {\n this.dotTargets.forEach((dot, i) => {\n const locked = i > this._maxUnlocked\n dot.disabled = locked\n dot.classList.toggle('locked', locked)\n })\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"carousel_component_controller.js","sources":["../../../../../../../app/components/midwest/carousel_component/carousel_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types where pressing Enter in a form does NOT normally submit it.\n// For all other input types, Enter submits — so wizard mode intercepts it.\nconst NON_SUBMITTING_INPUT_TYPES = new Set([\n 'button', 'checkbox', 'color', 'file', 'hidden', 'image', 'radio', 'range', 'reset', 'submit'\n])\n\nexport default class Carousel extends Controller<HTMLElement> {\n static targets = ['track', 'prev', 'next', 'dot']\n static values = {\n wizard: { type: Boolean, default: false }\n }\n\n declare readonly trackTarget: HTMLElement\n declare readonly prevTarget: HTMLButtonElement\n declare readonly nextTarget: HTMLButtonElement\n declare readonly dotTargets: HTMLButtonElement[]\n declare readonly hasPrevTarget: boolean\n declare readonly hasNextTarget: boolean\n declare readonly hasDotTarget: boolean\n declare wizardValue: boolean\n\n private observer: IntersectionObserver | null = null\n private _currentIndex = 0\n private _maxUnlocked = 0\n private _lastTouchX = 0\n\n connect () {\n this.setupObserver()\n this.updateNavigation()\n if (this.wizardValue) {\n this.element.addEventListener('keydown', this.handleKeydown)\n this.trackTarget.addEventListener('wheel', this.handleWheel, { passive: false })\n this.trackTarget.addEventListener('touchstart', this.handleTouchStart, { passive: true })\n this.trackTarget.addEventListener('touchmove', this.handleTouchMove, { passive: false })\n this.updateSlideAccessibility()\n }\n }\n\n disconnect () {\n this.observer?.disconnect()\n this.element.removeEventListener('keydown', this.handleKeydown)\n this.trackTarget.removeEventListener('wheel', this.handleWheel)\n this.trackTarget.removeEventListener('touchstart', this.handleTouchStart)\n this.trackTarget.removeEventListener('touchmove', this.handleTouchMove)\n }\n\n next () {\n this.trackTarget.scrollBy({ left: this.trackTarget.clientWidth, behavior: 'smooth' })\n }\n\n previous () {\n this.trackTarget.scrollBy({ left: -this.trackTarget.clientWidth, behavior: 'smooth' })\n }\n\n goto (event: Event) {\n const button = event.currentTarget as HTMLButtonElement\n const index = parseInt(button.dataset.index ?? '0', 10)\n const slide = this.slides[index]\n slide?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })\n }\n\n // Unlocks the next slide and advances to it. Intended for wizard mode: wire\n // a \"Continue\" button inside a slide to this action so users progress\n // linearly through steps before the carousel nav becomes available.\n //\n // <button type=\"button\" data-action=\"click->midwest-carousel#unlockNext\">\n // Continue\n // </button>\n unlockNext () {\n const nextIndex = this._currentIndex + 1\n if (nextIndex > this._maxUnlocked) {\n this._maxUnlocked = nextIndex\n this.updateSlideAccessibility()\n }\n this.next()\n }\n\n scrolled () {\n if (this.wizardValue) this.clampToFrontier()\n this.updateCurrentIndex()\n this.updateNavigation()\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n private handleKeydown = (event: KeyboardEvent) => {\n if (event.key !== 'Enter') return\n\n const target = event.target as HTMLElement\n // Only intercept Enter on text-like inputs; textarea newlines and button\n // activations should pass through untouched.\n if (target.tagName === 'TEXTAREA' || target.tagName !== 'INPUT') return\n if (NON_SUBMITTING_INPUT_TYPES.has((target as HTMLInputElement).type)) return\n\n // On the final step let Enter submit the form normally.\n if (this._currentIndex >= this.slides.length - 1) return\n\n event.preventDefault()\n this.unlockNext()\n }\n\n // Blocks wheel-based horizontal scrolling past the wizard frontier.\n private handleWheel = (event: WheelEvent) => {\n const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth\n if (event.deltaX > 0 && this.trackTarget.scrollLeft >= maxLeft - 2) {\n event.preventDefault()\n }\n }\n\n private handleTouchStart = (event: TouchEvent) => {\n this._lastTouchX = event.touches[0].clientX\n }\n\n // Blocks touch-swipe scrolling past the wizard frontier. Tracks incremental\n // delta per move event so direction is accurate mid-gesture.\n private handleTouchMove = (event: TouchEvent) => {\n const currentX = event.touches[0].clientX\n const delta = currentX - this._lastTouchX // positive = swiping right (going back)\n this._lastTouchX = currentX\n\n const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth\n if (delta < 0 && this.trackTarget.scrollLeft >= maxLeft - 2) {\n event.preventDefault()\n }\n }\n\n private get slides (): HTMLElement[] {\n return Array.from(this.trackTarget.children) as HTMLElement[]\n }\n\n // Snaps scroll position back to the frontier if the user somehow scrolled\n // past it (e.g. momentum after a partially-blocked gesture).\n private clampToFrontier () {\n const maxLeft = this._maxUnlocked * this.trackTarget.clientWidth\n if (this.trackTarget.scrollLeft > maxLeft + 2) {\n this.trackTarget.scrollLeft = maxLeft\n }\n }\n\n // Applies/removes `inert` on each slide based on the wizard frontier,\n // removing locked slides from the tab order and accessibility tree.\n private updateSlideAccessibility () {\n this.slides.forEach((slide, i) => {\n if (i > this._maxUnlocked) {\n slide.setAttribute('inert', '')\n } else {\n slide.removeAttribute('inert')\n }\n })\n }\n\n private updateCurrentIndex () {\n const track = this.trackTarget\n if (track.clientWidth > 0) {\n this._currentIndex = Math.round(track.scrollLeft / track.clientWidth)\n }\n }\n\n private setupObserver () {\n if (!this.hasDotTarget) return\n if (!('IntersectionObserver' in window)) return\n\n this.observer = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n const index = this.slides.indexOf(entry.target as HTMLElement)\n if (index >= 0) {\n const dot = this.dotTargets[index]\n if (!dot) return\n dot.classList.toggle('active', entry.isIntersecting)\n if (entry.isIntersecting) {\n dot.setAttribute('aria-current', 'true')\n } else {\n dot.removeAttribute('aria-current')\n }\n }\n })\n },\n { root: this.trackTarget, threshold: 0.5 }\n )\n\n this.slides.forEach(slide => this.observer?.observe(slide))\n }\n\n private updateNavigation () {\n const track = this.trackTarget\n const atStart = track.scrollLeft <= 0\n const atEnd = track.scrollLeft >= track.scrollWidth - track.clientWidth - 1\n\n if (this.hasPrevTarget) this.prevTarget.classList.toggle('hide', atStart)\n\n if (this.hasNextTarget) {\n const atLastSlide = this._currentIndex >= this.slides.length - 1\n const frontierReached = this.wizardValue && this._currentIndex >= this._maxUnlocked\n this.nextTarget.classList.toggle('hide', atEnd || atLastSlide || frontierReached)\n }\n\n if (this.wizardValue && this.hasDotTarget) {\n this.dotTargets.forEach((dot, i) => {\n const locked = i > this._maxUnlocked\n dot.disabled = locked\n dot.classList.toggle('locked', locked)\n })\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -5,9 +5,19 @@ class Dialog extends Controller {
|
|
|
5
5
|
static values = {
|
|
6
6
|
resetFrame: { type: Boolean, default: false }
|
|
7
7
|
};
|
|
8
|
+
_previousFocus = null;
|
|
8
9
|
connect() {
|
|
9
|
-
document.addEventListener("turbo:frame-load", this.
|
|
10
|
-
this.
|
|
10
|
+
document.addEventListener("turbo:frame-load", this.bindToggleEls);
|
|
11
|
+
document.addEventListener("turbo:before-visit", this.dismiss);
|
|
12
|
+
document.addEventListener("click", this.handleClickOutside);
|
|
13
|
+
this.dialog.addEventListener("close", this.onClose);
|
|
14
|
+
this.bindToggleEls();
|
|
15
|
+
}
|
|
16
|
+
disconnect() {
|
|
17
|
+
document.removeEventListener("turbo:frame-load", this.bindToggleEls);
|
|
18
|
+
document.removeEventListener("turbo:before-visit", this.dismiss);
|
|
19
|
+
document.removeEventListener("click", this.handleClickOutside);
|
|
20
|
+
this.dialog.removeEventListener("close", this.onClose);
|
|
11
21
|
}
|
|
12
22
|
get dialog() {
|
|
13
23
|
return this.element;
|
|
@@ -21,20 +31,18 @@ class Dialog extends Controller {
|
|
|
21
31
|
get frameEl() {
|
|
22
32
|
return this.dialog.querySelector("turbo-frame");
|
|
23
33
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
document.addEventListener("turbo:before-visit", this.dismiss.bind(this));
|
|
34
|
+
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
35
|
+
handleClickOutside = (event) => {
|
|
36
|
+
if (event.target !== this.dialog)
|
|
37
|
+
return;
|
|
38
|
+
this.dismiss();
|
|
39
|
+
};
|
|
40
|
+
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
41
|
+
bindToggleEls = () => {
|
|
33
42
|
this.toggleEls.forEach((el) => {
|
|
34
43
|
el.addEventListener("click", this.toggle.bind(this));
|
|
35
44
|
});
|
|
36
|
-
|
|
37
|
-
}
|
|
45
|
+
};
|
|
38
46
|
remoteContentTargetConnected() {
|
|
39
47
|
this.show();
|
|
40
48
|
}
|
|
@@ -45,32 +53,65 @@ class Dialog extends Controller {
|
|
|
45
53
|
if (this.dialog.open) {
|
|
46
54
|
this.dialog.close();
|
|
47
55
|
} else {
|
|
56
|
+
this._previousFocus = document.activeElement;
|
|
48
57
|
this.dialog.showModal();
|
|
58
|
+
this.dialog.addEventListener("keydown", this.handleFocusTrap);
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
61
|
show(e = void 0) {
|
|
52
62
|
if (e instanceof Event)
|
|
53
63
|
e.preventDefault();
|
|
54
64
|
this.htmlEl.classList.toggle("overflow-hidden", true);
|
|
65
|
+
this._previousFocus = document.activeElement;
|
|
55
66
|
this.dialog.showModal();
|
|
67
|
+
this.dialog.addEventListener("keydown", this.handleFocusTrap);
|
|
56
68
|
}
|
|
57
69
|
hide({ detail }) {
|
|
58
70
|
if (!detail.success)
|
|
59
71
|
return;
|
|
60
72
|
this.dismiss();
|
|
61
73
|
}
|
|
62
|
-
|
|
74
|
+
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
75
|
+
dismiss = () => {
|
|
63
76
|
this.dialog.close();
|
|
64
|
-
}
|
|
77
|
+
};
|
|
65
78
|
reloadPage() {
|
|
66
79
|
window.location.reload();
|
|
67
80
|
}
|
|
68
|
-
|
|
81
|
+
handleFocusTrap = (event) => {
|
|
82
|
+
if (event.key !== "Tab")
|
|
83
|
+
return;
|
|
84
|
+
const focusable = Array.from(
|
|
85
|
+
this.dialog.querySelectorAll(
|
|
86
|
+
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
|
|
87
|
+
)
|
|
88
|
+
).filter((el) => !el.closest("[inert]"));
|
|
89
|
+
if (focusable.length === 0)
|
|
90
|
+
return;
|
|
91
|
+
const first = focusable[0];
|
|
92
|
+
const last = focusable[focusable.length - 1];
|
|
93
|
+
if (event.shiftKey) {
|
|
94
|
+
if (document.activeElement === first) {
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
last.focus();
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
if (document.activeElement === last) {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
first.focus();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
106
|
+
onClose = async () => {
|
|
107
|
+
this.dialog.removeEventListener("keydown", this.handleFocusTrap);
|
|
108
|
+
this._previousFocus?.focus();
|
|
109
|
+
this._previousFocus = null;
|
|
69
110
|
this.htmlEl.classList.toggle("overflow-hidden", false);
|
|
70
111
|
await this.delay(500);
|
|
71
112
|
this.resetForm();
|
|
72
113
|
this.resetFrame();
|
|
73
|
-
}
|
|
114
|
+
};
|
|
74
115
|
resetFrame() {
|
|
75
116
|
if (!this.resetFrameValue || this.frameEl == null)
|
|
76
117
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog_component_controller.js","sources":["../../../../../../../app/components/midwest/dialog_component/dialog_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Dialog extends Controller<HTMLFormElement> {\n static targets = ['remoteContent', 'clearableForm']\n\n declare readonly hasRemoteContentTarget: boolean\n declare readonly remoteContentTarget: HTMLInputElement\n declare readonly remoteContentTargets: HTMLInputElement[]\n\n declare readonly hasClearableFormTarget: boolean\n declare readonly clearableFormTarget: HTMLFormElement\n declare readonly clearableFormTargets: HTMLFormElement[]\n\n static values = {\n resetFrame: { type: Boolean, default: false }\n }\n\n declare resetFrameValue: boolean\n declare readonly hasResetFrameValue: boolean\n\n connect () {\n document.addEventListener('turbo:frame-load', this.
|
|
1
|
+
{"version":3,"file":"dialog_component_controller.js","sources":["../../../../../../../app/components/midwest/dialog_component/dialog_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Dialog extends Controller<HTMLFormElement> {\n static targets = ['remoteContent', 'clearableForm']\n\n declare readonly hasRemoteContentTarget: boolean\n declare readonly remoteContentTarget: HTMLInputElement\n declare readonly remoteContentTargets: HTMLInputElement[]\n\n declare readonly hasClearableFormTarget: boolean\n declare readonly clearableFormTarget: HTMLFormElement\n declare readonly clearableFormTargets: HTMLFormElement[]\n\n static values = {\n resetFrame: { type: Boolean, default: false }\n }\n\n declare resetFrameValue: boolean\n declare readonly hasResetFrameValue: boolean\n\n private _previousFocus: HTMLElement | null = null\n\n connect () {\n document.addEventListener('turbo:frame-load', this.bindToggleEls)\n document.addEventListener('turbo:before-visit', this.dismiss)\n document.addEventListener('click', this.handleClickOutside)\n this.dialog.addEventListener('close', this.onClose)\n this.bindToggleEls()\n }\n\n disconnect () {\n document.removeEventListener('turbo:frame-load', this.bindToggleEls)\n document.removeEventListener('turbo:before-visit', this.dismiss)\n document.removeEventListener('click', this.handleClickOutside)\n this.dialog.removeEventListener('close', this.onClose)\n }\n\n get dialog () {\n return this.element\n }\n\n get htmlEl () {\n return document.documentElement\n }\n\n get toggleEls () {\n return document.querySelectorAll(`[data-toggle-dialog=\"${this.dialog.id}\"]`)\n }\n\n get frameEl () {\n return this.dialog.querySelector('turbo-frame')\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n private handleClickOutside = (event: Event) => {\n if (event.target !== this.dialog) return\n this.dismiss()\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n private bindToggleEls = () => {\n this.toggleEls.forEach((el) => {\n el.addEventListener('click', this.toggle.bind(this))\n })\n }\n\n remoteContentTargetConnected () {\n this.show()\n }\n\n toggle (e: any = undefined) {\n // if clicked elem is a link, prevent default behavior.\n if (e instanceof Event) e.preventDefault()\n this.htmlEl.classList.toggle('overflow-hidden', true)\n\n if (this.dialog.open) {\n this.dialog.close()\n } else {\n this._previousFocus = document.activeElement as HTMLElement\n this.dialog.showModal()\n this.dialog.addEventListener('keydown', this.handleFocusTrap)\n }\n }\n\n show (e: any = undefined) {\n // if clicked elem is a link, prevent default behavior.\n if (e instanceof Event) e.preventDefault()\n this.htmlEl.classList.toggle('overflow-hidden', true)\n this._previousFocus = document.activeElement as HTMLElement\n this.dialog.showModal()\n this.dialog.addEventListener('keydown', this.handleFocusTrap)\n }\n\n hide ({ detail }: { detail: { success: boolean } }) {\n if (!detail.success) return\n this.dismiss()\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n dismiss = () => {\n this.dialog.close()\n }\n\n reloadPage () {\n window.location.reload()\n }\n\n private handleFocusTrap = (event: KeyboardEvent) => {\n if (event.key !== 'Tab') return\n\n const focusable = Array.from(\n this.dialog.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter(el => !el.closest('[inert]'))\n\n if (focusable.length === 0) return\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey) {\n if (document.activeElement === first) {\n event.preventDefault()\n last.focus()\n }\n } else {\n if (document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n }\n }\n\n // Arrow function so `this` is stable for add/removeEventListener pairing.\n private onClose = async () => {\n this.dialog.removeEventListener('keydown', this.handleFocusTrap)\n this._previousFocus?.focus()\n this._previousFocus = null\n this.htmlEl.classList.toggle('overflow-hidden', false)\n await this.delay(500)\n this.resetForm()\n this.resetFrame()\n }\n\n private resetFrame () {\n if (!this.resetFrameValue || (this.frameEl == null)) return\n\n this.frameEl.innerHTML = ''\n this.frameEl.removeAttribute('src')\n }\n\n private resetForm () {\n if (!this.hasClearableFormTarget) return\n this.clearableFormTarget.reset()\n }\n\n async delay (time = 500) {\n return await new Promise((resolve) => {\n setTimeout(resolve, time)\n })\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,9 @@ class Dropdown extends Controller {
|
|
|
25
25
|
}
|
|
26
26
|
this.buttonEl.removeEventListener("click", this.unsupportedClickCB);
|
|
27
27
|
this.element.removeEventListener("toggle", this.addOpenedClass);
|
|
28
|
+
this.element.removeEventListener("keydown", this.handleKeydown);
|
|
28
29
|
this.element.removeEventListener("turbo:click", this.closeIfOpen);
|
|
30
|
+
this.element.removeEventListener("popover:close", this.closeIfOpen);
|
|
29
31
|
}
|
|
30
32
|
unsupportedClickCB = (event) => {
|
|
31
33
|
event.preventDefault();
|
|
@@ -34,15 +36,73 @@ class Dropdown extends Controller {
|
|
|
34
36
|
};
|
|
35
37
|
get buttonEl() {
|
|
36
38
|
return this.element.parentElement?.querySelector(
|
|
37
|
-
`[popovertarget="${this.element.id}"]`
|
|
39
|
+
`[popovertarget="${this.element.id}"]:not([popovertargetaction="hide"])`
|
|
38
40
|
);
|
|
39
41
|
}
|
|
40
42
|
get isComputed() {
|
|
41
43
|
return this.computedValue || !this.supportedValue;
|
|
42
44
|
}
|
|
43
45
|
addOpenedClass = (event) => {
|
|
44
|
-
|
|
46
|
+
const isOpen = event.newState === "open";
|
|
47
|
+
this.buttonEl.classList.toggle("opened", isOpen);
|
|
48
|
+
this.buttonEl.setAttribute("aria-expanded", String(isOpen));
|
|
49
|
+
if (isOpen) {
|
|
50
|
+
this.element.addEventListener("keydown", this.handleKeydown);
|
|
51
|
+
requestAnimationFrame(() => this.menuItems[0]?.focus());
|
|
52
|
+
} else {
|
|
53
|
+
this.element.removeEventListener("keydown", this.handleKeydown);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
handleKeydown = (event) => {
|
|
57
|
+
const items = this.menuItems;
|
|
58
|
+
if (items.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End", "Escape", "Tab"].includes(event.key))
|
|
61
|
+
return;
|
|
62
|
+
event.stopPropagation();
|
|
63
|
+
const currentIndex = items.findIndex((item) => item === document.activeElement);
|
|
64
|
+
switch (event.key) {
|
|
65
|
+
case "ArrowDown": {
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
const next = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
|
|
68
|
+
items[next].focus();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case "ArrowUp": {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
const prev = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
|
|
74
|
+
items[prev].focus();
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case "Home":
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
items[0].focus();
|
|
80
|
+
break;
|
|
81
|
+
case "End":
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
items[items.length - 1].focus();
|
|
84
|
+
break;
|
|
85
|
+
case "Escape":
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
this.element.hidePopover();
|
|
88
|
+
requestAnimationFrame(() => this.buttonEl?.focus());
|
|
89
|
+
break;
|
|
90
|
+
case "Tab":
|
|
91
|
+
this.element.hidePopover();
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
45
96
|
};
|
|
97
|
+
get menuItems() {
|
|
98
|
+
return Array.from(
|
|
99
|
+
this.element.querySelectorAll(
|
|
100
|
+
'[role="menuitem"]:not([disabled]):not([aria-disabled="true"])'
|
|
101
|
+
)
|
|
102
|
+
).filter(
|
|
103
|
+
(item) => item.closest('[data-controller~="midwest-dropdown"]') === this.element && getComputedStyle(item).display !== "none"
|
|
104
|
+
);
|
|
105
|
+
}
|
|
46
106
|
computedCB(entries) {
|
|
47
107
|
entries.forEach(async () => {
|
|
48
108
|
this.computation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown_component_controller.js","sources":["../../../../../../../app/components/midwest/dropdown_component/dropdown_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nimport {\n computePosition,\n autoPlacement,\n shift,\n offset,\n autoUpdate,\n hide,\n Placement\n} from '@floating-ui/dom'\n\nexport default class Dropdown extends Controller<HTMLFormElement> {\n static values = {\n computed: { type: Boolean, default: false },\n supported: { type: Boolean, default: true },\n align: { type: String, default: 'right' }\n }\n\n declare computedValue: boolean\n declare supportedValue: boolean\n declare alignValue: Placement\n declare readonly hasComputedValue: boolean\n declare readonly hasSupportedValue: boolean\n declare readonly hasAlignValue: boolean\n\n observer = new IntersectionObserver(this.computedCB.bind(this), { threshold: 1 })\n\n cleanup: any\n\n connect () {\n this.supportedValue = CSS.supports('anchor-name: --myanchor')\n\n if (this.isComputed) {\n this.buttonEl.addEventListener('click', this.unsupportedClickCB)\n this.cleanup = autoUpdate(this.buttonEl, this.element, async () => await this.computation())\n }\n\n this.element.addEventListener('toggle', this.addOpenedClass)\n this.element.addEventListener('turbo:click', this.closeIfOpen)\n this.element.addEventListener('popover:close', this.closeIfOpen)\n }\n\n disconnect () {\n if (this.isComputed) {\n this.cleanup()\n }\n\n this.buttonEl.removeEventListener('click', this.unsupportedClickCB)\n this.element.removeEventListener('toggle', this.addOpenedClass)\n this.element.removeEventListener('turbo:click', this.closeIfOpen)\n }\n\n unsupportedClickCB = (event: MouseEvent) => {\n event.preventDefault()\n event.stopPropagation()\n this.element.togglePopover()\n }\n\n get buttonEl () {\n return this.element.parentElement?.querySelector(\n `[popovertarget=\"${this.element.id}\"]`\n ) as HTMLButtonElement\n }\n\n get isComputed () {\n return this.computedValue || !this.supportedValue\n }\n\n addOpenedClass = (event: any) => {\n this.buttonEl.classList.toggle('opened', event.newState === 'open')\n }\n\n computedCB (entries: IntersectionObserverEntry[]) {\n entries.forEach(async () => {\n this.computation()\n })\n }\n\n closeIfOpen = () => {\n this.element.hidePopover()\n }\n\n async computation () {\n if (!this.buttonEl) return\n if (!this.isComputed) return\n\n const { x, y, middlewareData } = await computePosition(this.buttonEl, this.element, {\n strategy: 'fixed',\n placement: this.alignValue,\n middleware: [\n hide(),\n offset(6),\n autoPlacement({\n allowedPlacements: [\n 'left-start',\n 'left-end',\n 'right-start',\n 'right-end',\n 'bottom-end',\n 'bottom-start'\n ],\n crossAxis: true\n }),\n shift({ padding: 24 })\n ]\n })\n\n if (!middlewareData || (middlewareData.hide == null)) return\n\n Object.assign(this.element.style, {\n left: `${x}px`,\n top: `${y}px`,\n visibility: middlewareData.hide.referenceHidden ? 'hidden' : 'visible'\n })\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown_component_controller.js","sources":["../../../../../../../app/components/midwest/dropdown_component/dropdown_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nimport {\n computePosition,\n autoPlacement,\n shift,\n offset,\n autoUpdate,\n hide,\n Placement\n} from '@floating-ui/dom'\n\nexport default class Dropdown extends Controller<HTMLFormElement> {\n static values = {\n computed: { type: Boolean, default: false },\n supported: { type: Boolean, default: true },\n align: { type: String, default: 'right' }\n }\n\n declare computedValue: boolean\n declare supportedValue: boolean\n declare alignValue: Placement\n declare readonly hasComputedValue: boolean\n declare readonly hasSupportedValue: boolean\n declare readonly hasAlignValue: boolean\n\n observer = new IntersectionObserver(this.computedCB.bind(this), { threshold: 1 })\n\n cleanup: any\n\n connect () {\n this.supportedValue = CSS.supports('anchor-name: --myanchor')\n\n if (this.isComputed) {\n this.buttonEl.addEventListener('click', this.unsupportedClickCB)\n this.cleanup = autoUpdate(this.buttonEl, this.element, async () => await this.computation())\n }\n\n this.element.addEventListener('toggle', this.addOpenedClass)\n this.element.addEventListener('turbo:click', this.closeIfOpen)\n this.element.addEventListener('popover:close', this.closeIfOpen)\n }\n\n disconnect () {\n if (this.isComputed) {\n this.cleanup()\n }\n\n this.buttonEl.removeEventListener('click', this.unsupportedClickCB)\n this.element.removeEventListener('toggle', this.addOpenedClass)\n this.element.removeEventListener('keydown', this.handleKeydown)\n this.element.removeEventListener('turbo:click', this.closeIfOpen)\n this.element.removeEventListener('popover:close', this.closeIfOpen)\n }\n\n unsupportedClickCB = (event: MouseEvent) => {\n event.preventDefault()\n event.stopPropagation()\n this.element.togglePopover()\n }\n\n get buttonEl () {\n return this.element.parentElement?.querySelector(\n `[popovertarget=\"${this.element.id}\"]:not([popovertargetaction=\"hide\"])`\n ) as HTMLButtonElement\n }\n\n get isComputed () {\n return this.computedValue || !this.supportedValue\n }\n\n addOpenedClass = (event: any) => {\n const isOpen = event.newState === 'open'\n this.buttonEl.classList.toggle('opened', isOpen)\n this.buttonEl.setAttribute('aria-expanded', String(isOpen))\n\n if (isOpen) {\n this.element.addEventListener('keydown', this.handleKeydown)\n requestAnimationFrame(() => this.menuItems[0]?.focus())\n } else {\n this.element.removeEventListener('keydown', this.handleKeydown)\n }\n }\n\n private handleKeydown = (event: KeyboardEvent) => {\n const items = this.menuItems\n if (items.length === 0) return\n\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End', 'Escape', 'Tab'].includes(event.key)) return\n\n event.stopPropagation()\n\n const currentIndex = items.findIndex(item => item === document.activeElement)\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault()\n const next = currentIndex < items.length - 1 ? currentIndex + 1 : 0\n items[next].focus()\n break\n }\n case 'ArrowUp': {\n event.preventDefault()\n const prev = currentIndex > 0 ? currentIndex - 1 : items.length - 1\n items[prev].focus()\n break\n }\n case 'Home':\n event.preventDefault()\n items[0].focus()\n break\n case 'End':\n event.preventDefault()\n items[items.length - 1].focus()\n break\n case 'Escape':\n event.preventDefault()\n this.element.hidePopover()\n requestAnimationFrame(() => this.buttonEl?.focus())\n break\n case 'Tab':\n this.element.hidePopover()\n break\n default:\n return\n }\n }\n\n private get menuItems (): HTMLElement[] {\n return Array.from(\n this.element.querySelectorAll<HTMLElement>(\n '[role=\"menuitem\"]:not([disabled]):not([aria-disabled=\"true\"])'\n )\n ).filter(item =>\n item.closest('[data-controller~=\"midwest-dropdown\"]') === this.element &&\n getComputedStyle(item).display !== 'none'\n )\n }\n\n computedCB (entries: IntersectionObserverEntry[]) {\n entries.forEach(async () => {\n this.computation()\n })\n }\n\n closeIfOpen = () => {\n this.element.hidePopover()\n }\n\n async computation () {\n if (!this.buttonEl) return\n if (!this.isComputed) return\n\n const { x, y, middlewareData } = await computePosition(this.buttonEl, this.element, {\n strategy: 'fixed',\n placement: this.alignValue,\n middleware: [\n hide(),\n offset(6),\n autoPlacement({\n allowedPlacements: [\n 'left-start',\n 'left-end',\n 'right-start',\n 'right-end',\n 'bottom-end',\n 'bottom-start'\n ],\n crossAxis: true\n }),\n shift({ padding: 24 })\n ]\n })\n\n if (!middlewareData || (middlewareData.hide == null)) return\n\n Object.assign(this.element.style, {\n left: `${x}px`,\n top: `${y}px`,\n visibility: middlewareData.hide.referenceHidden ? 'hidden' : 'visible'\n })\n }\n}\n"],"names":[],"mappings":"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"}
|