@unabridged/midwest 0.24.0 → 0.24.3
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/app/assets/javascript/midwest/index.ts +2 -0
- package/app/assets/javascript/midwest/viewport_observer.ts +49 -0
- package/app/assets/javascript/midwest.js +84 -64
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +2 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +2 -0
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/viewport_observer.js +22 -0
- package/dist/javascript/collection/app/assets/javascript/midwest/viewport_observer.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +4 -7
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js +0 -6
- package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/intersection_observer_component/intersection_observer_component_controller.js +20 -25
- package/dist/javascript/collection/app/components/midwest/intersection_observer_component/intersection_observer_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/motion_component/motion_component_controller.js +32 -0
- package/dist/javascript/collection/app/components/midwest/motion_component/motion_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/notification_component/notification_component_controller.js +4 -12
- package/dist/javascript/collection/app/components/midwest/notification_component/notification_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js +10 -14
- package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js.map +1 -1
- package/dist/javascript/midwest.js +84 -64
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,6 +38,7 @@ import Onboarding from '../../../components/midwest/onboarding_component/onboard
|
|
|
38
38
|
import ThemeSwitch from '../../../components/midwest/form/switch_component/theme_switch_controller'
|
|
39
39
|
import Panorama from '../../../components/midwest/panorama_component/panorama_component_controller'
|
|
40
40
|
import Playlist from '../../../components/midwest/playlist_component/playlist_component_controller'
|
|
41
|
+
import Motion from '../../../components/midwest/motion_component/motion_component_controller'
|
|
41
42
|
/* IMPORTS */
|
|
42
43
|
|
|
43
44
|
export { Card, Banner, CountdownTimer, Chart }
|
|
@@ -83,5 +84,6 @@ export function registerMidwestControllers (application: any) {
|
|
|
83
84
|
application.register('midwest-theme-switch', ThemeSwitch)
|
|
84
85
|
application.register('midwest-panorama', Panorama)
|
|
85
86
|
application.register('midwest-playlist', Playlist)
|
|
87
|
+
application.register('midwest-motion', Motion)
|
|
86
88
|
/* EXPORTS */
|
|
87
89
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Shared viewport-detection helper for components that react to scrolling into
|
|
2
|
+
// and out of view (IntersectionObserverComponent, MotionComponent, …).
|
|
3
|
+
//
|
|
4
|
+
// Wraps the IntersectionObserver API so controllers only describe *what* to do
|
|
5
|
+
// on enter/leave, not the observer plumbing. Components own the reaction (toggle
|
|
6
|
+
// a class, dispatch an event, reveal an animation); this module owns creating,
|
|
7
|
+
// observing, and tearing down the observer so the behavior stays consistent.
|
|
8
|
+
|
|
9
|
+
export interface ViewportObserverOptions {
|
|
10
|
+
// Fraction(s) of the element that must be visible to count as intersecting.
|
|
11
|
+
threshold?: number | number[]
|
|
12
|
+
// Margin around the viewport root (CSS shorthand string).
|
|
13
|
+
rootMargin?: string
|
|
14
|
+
// Stop observing after the first time the element enters the viewport.
|
|
15
|
+
once?: boolean
|
|
16
|
+
// Called each time the element enters the viewport.
|
|
17
|
+
onEnter?: (entry: IntersectionObserverEntry) => void
|
|
18
|
+
// Called each time the element leaves the viewport. Never called after the
|
|
19
|
+
// first enter when `once` is true (the observer has disconnected by then).
|
|
20
|
+
onLeave?: (entry: IntersectionObserverEntry) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Observe `element` crossing the viewport threshold, invoking the callbacks as
|
|
24
|
+
// it enters and leaves. Returns a teardown function that disconnects the
|
|
25
|
+
// observer; callers should invoke it from their controller's `disconnect()`.
|
|
26
|
+
export function observeViewport (
|
|
27
|
+
element: Element,
|
|
28
|
+
options: ViewportObserverOptions = {}
|
|
29
|
+
): () => void {
|
|
30
|
+
const { threshold = 0, rootMargin = '0px', once = false, onEnter, onLeave } = options
|
|
31
|
+
|
|
32
|
+
const observer = new IntersectionObserver(
|
|
33
|
+
(entries) => {
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (entry.isIntersecting) {
|
|
36
|
+
onEnter?.(entry)
|
|
37
|
+
if (once) observer.disconnect()
|
|
38
|
+
} else {
|
|
39
|
+
onLeave?.(entry)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{ threshold, rootMargin }
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
observer.observe(element)
|
|
47
|
+
|
|
48
|
+
return () => observer.disconnect()
|
|
49
|
+
}
|
|
@@ -2557,7 +2557,6 @@ class Dropdown extends Controller {
|
|
|
2557
2557
|
supported: { type: Boolean, default: true },
|
|
2558
2558
|
align: { type: String, default: "right" }
|
|
2559
2559
|
};
|
|
2560
|
-
observer = new IntersectionObserver(this.computedCB.bind(this), { threshold: 1 });
|
|
2561
2560
|
cleanup;
|
|
2562
2561
|
connect() {
|
|
2563
2562
|
this.supportedValue = CSS.supports("anchor-name: --myanchor");
|
|
@@ -2623,11 +2622,6 @@ class Dropdown extends Controller {
|
|
|
2623
2622
|
(item) => item.closest('[data-controller~="midwest-dropdown"]') === this.element && getComputedStyle(item).display !== "none"
|
|
2624
2623
|
);
|
|
2625
2624
|
}
|
|
2626
|
-
computedCB(entries) {
|
|
2627
|
-
entries.forEach(async () => {
|
|
2628
|
-
this.computation();
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
2625
|
closeIfOpen = () => {
|
|
2632
2626
|
this.element.hidePopover();
|
|
2633
2627
|
};
|
|
@@ -3012,7 +3006,7 @@ class Carousel extends Controller {
|
|
|
3012
3006
|
}
|
|
3013
3007
|
const atEnd = this._currentIndex >= this.slides.length - 1;
|
|
3014
3008
|
if (this.loopValue && atEnd) {
|
|
3015
|
-
this.
|
|
3009
|
+
this.trackTarget.scrollTo({ left: 0, behavior: "smooth" });
|
|
3016
3010
|
} else {
|
|
3017
3011
|
this.trackTarget.scrollBy({ left: this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3018
3012
|
}
|
|
@@ -3026,8 +3020,7 @@ class Carousel extends Controller {
|
|
|
3026
3020
|
}
|
|
3027
3021
|
const atStart = this._currentIndex <= 0;
|
|
3028
3022
|
if (this.loopValue && atStart) {
|
|
3029
|
-
|
|
3030
|
-
last?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3023
|
+
this.trackTarget.scrollTo({ left: (this.slides.length - 1) * this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3031
3024
|
} else {
|
|
3032
3025
|
this.trackTarget.scrollBy({ left: -this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3033
3026
|
}
|
|
@@ -3039,8 +3032,7 @@ class Carousel extends Controller {
|
|
|
3039
3032
|
this.activateSlide(index);
|
|
3040
3033
|
return;
|
|
3041
3034
|
}
|
|
3042
|
-
|
|
3043
|
-
slide?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3035
|
+
this.trackTarget.scrollTo({ left: index * this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3044
3036
|
}
|
|
3045
3037
|
// Unlocks the next slide and advances to it. Intended for wizard mode: wire
|
|
3046
3038
|
// a "Continue" button inside a slide to this action so users progress
|
|
@@ -3144,8 +3136,7 @@ class Carousel extends Controller {
|
|
|
3144
3136
|
}
|
|
3145
3137
|
const atEnd = this._currentIndex >= this.slides.length - 1;
|
|
3146
3138
|
if (atEnd) {
|
|
3147
|
-
|
|
3148
|
-
firstSlide?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3139
|
+
this.trackTarget.scrollTo({ left: 0, behavior: "smooth" });
|
|
3149
3140
|
} else {
|
|
3150
3141
|
this.next();
|
|
3151
3142
|
}
|
|
@@ -4871,10 +4862,7 @@ class Notification extends Controller {
|
|
|
4871
4862
|
connect() {
|
|
4872
4863
|
this.container = this.element.closest("[popover]");
|
|
4873
4864
|
this.container?.showPopover?.();
|
|
4874
|
-
|
|
4875
|
-
this.element.classList.add("visible");
|
|
4876
|
-
});
|
|
4877
|
-
const frame = this.element.parentElement;
|
|
4865
|
+
const frame = this.element.closest("turbo-frame");
|
|
4878
4866
|
if (frame) {
|
|
4879
4867
|
this.observer = new MutationObserver(() => this.syncCountdown());
|
|
4880
4868
|
this.observer.observe(frame, { childList: true });
|
|
@@ -4893,14 +4881,8 @@ class Notification extends Controller {
|
|
|
4893
4881
|
}
|
|
4894
4882
|
}
|
|
4895
4883
|
close() {
|
|
4896
|
-
if (!this.element.classList.contains("animated")) {
|
|
4897
|
-
this.element.remove();
|
|
4898
|
-
return;
|
|
4899
|
-
}
|
|
4900
4884
|
this.element.classList.add("closing");
|
|
4901
|
-
setTimeout(() =>
|
|
4902
|
-
this.element.remove();
|
|
4903
|
-
}, 350);
|
|
4885
|
+
setTimeout(() => (this.element.parentElement ?? this.element).remove(), 350);
|
|
4904
4886
|
}
|
|
4905
4887
|
syncCountdown() {
|
|
4906
4888
|
const timerEl = this.element.querySelector('[data-controller~="midwest-countdown-timer"]');
|
|
@@ -4912,7 +4894,8 @@ class Notification extends Controller {
|
|
|
4912
4894
|
);
|
|
4913
4895
|
if (!timer)
|
|
4914
4896
|
return;
|
|
4915
|
-
const
|
|
4897
|
+
const wrapper = this.element.parentElement ?? this.element;
|
|
4898
|
+
const isTop = wrapper === wrapper.parentElement?.firstElementChild;
|
|
4916
4899
|
if (isTop) {
|
|
4917
4900
|
timer.resume();
|
|
4918
4901
|
} else {
|
|
@@ -4986,36 +4969,51 @@ class Table extends Controller {
|
|
|
4986
4969
|
}
|
|
4987
4970
|
}
|
|
4988
4971
|
|
|
4972
|
+
function observeViewport(element, options = {}) {
|
|
4973
|
+
const { threshold = 0, rootMargin = "0px", once = false, onEnter, onLeave } = options;
|
|
4974
|
+
const observer = new IntersectionObserver(
|
|
4975
|
+
(entries) => {
|
|
4976
|
+
for (const entry of entries) {
|
|
4977
|
+
if (entry.isIntersecting) {
|
|
4978
|
+
onEnter?.(entry);
|
|
4979
|
+
if (once)
|
|
4980
|
+
observer.disconnect();
|
|
4981
|
+
} else {
|
|
4982
|
+
onLeave?.(entry);
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
},
|
|
4986
|
+
{ threshold, rootMargin }
|
|
4987
|
+
);
|
|
4988
|
+
observer.observe(element);
|
|
4989
|
+
return () => observer.disconnect();
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4989
4992
|
class LoadMore extends Controller {
|
|
4990
4993
|
static values = {
|
|
4991
4994
|
url: String,
|
|
4992
4995
|
tbodyId: String
|
|
4993
4996
|
};
|
|
4994
|
-
|
|
4997
|
+
teardown = null;
|
|
4995
4998
|
loading = false;
|
|
4996
4999
|
connect() {
|
|
4997
5000
|
if (!this.urlValue)
|
|
4998
5001
|
return;
|
|
4999
|
-
this.
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
// Start fetching 300px before the sentinel enters the viewport so rows
|
|
5005
|
-
// appear before the user actually reaches the bottom.
|
|
5006
|
-
{ rootMargin: "0px 0px 300px 0px" }
|
|
5007
|
-
);
|
|
5008
|
-
this.observer.observe(this.element);
|
|
5002
|
+
this.teardown = observeViewport(this.element, {
|
|
5003
|
+
rootMargin: "0px 0px 300px 0px",
|
|
5004
|
+
once: true,
|
|
5005
|
+
onEnter: () => this.load()
|
|
5006
|
+
});
|
|
5009
5007
|
}
|
|
5010
5008
|
disconnect() {
|
|
5011
|
-
this.
|
|
5012
|
-
this.
|
|
5009
|
+
this.teardown?.();
|
|
5010
|
+
this.teardown = null;
|
|
5013
5011
|
}
|
|
5014
5012
|
async load() {
|
|
5015
5013
|
if (this.loading)
|
|
5016
5014
|
return;
|
|
5017
5015
|
this.loading = true;
|
|
5018
|
-
this.
|
|
5016
|
+
this.teardown?.();
|
|
5019
5017
|
try {
|
|
5020
5018
|
const response = await fetch(this.urlValue, {
|
|
5021
5019
|
headers: {
|
|
@@ -6947,35 +6945,29 @@ class ViewportObserver extends Controller {
|
|
|
6947
6945
|
once: { type: Boolean, default: false },
|
|
6948
6946
|
visibleClass: { type: String, default: "" }
|
|
6949
6947
|
};
|
|
6950
|
-
|
|
6948
|
+
teardown = null;
|
|
6951
6949
|
connect() {
|
|
6952
|
-
this.
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6950
|
+
this.teardown = observeViewport(this.element, {
|
|
6951
|
+
threshold: this.thresholdValue,
|
|
6952
|
+
rootMargin: this.rootMarginValue,
|
|
6953
|
+
once: this.onceValue,
|
|
6954
|
+
onEnter: (entry) => {
|
|
6955
|
+
this.element.setAttribute("data-intersecting", "true");
|
|
6956
|
+
if (this.visibleClassValue)
|
|
6957
|
+
this.element.classList.add(this.visibleClassValue);
|
|
6958
|
+
this.dispatch("enter", { detail: { entry }, bubbles: true });
|
|
6956
6959
|
},
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
+
onLeave: (entry) => {
|
|
6961
|
+
this.element.setAttribute("data-intersecting", "false");
|
|
6962
|
+
if (this.visibleClassValue)
|
|
6963
|
+
this.element.classList.remove(this.visibleClassValue);
|
|
6964
|
+
this.dispatch("leave", { detail: { entry }, bubbles: true });
|
|
6965
|
+
}
|
|
6966
|
+
});
|
|
6960
6967
|
}
|
|
6961
6968
|
disconnect() {
|
|
6962
|
-
this.
|
|
6963
|
-
this.
|
|
6964
|
-
}
|
|
6965
|
-
handle(entry) {
|
|
6966
|
-
if (entry.isIntersecting) {
|
|
6967
|
-
this.element.setAttribute("data-intersecting", "true");
|
|
6968
|
-
if (this.visibleClassValue)
|
|
6969
|
-
this.element.classList.add(this.visibleClassValue);
|
|
6970
|
-
this.dispatch("enter", { detail: { entry }, bubbles: true });
|
|
6971
|
-
if (this.onceValue)
|
|
6972
|
-
this.disconnect();
|
|
6973
|
-
} else {
|
|
6974
|
-
this.element.setAttribute("data-intersecting", "false");
|
|
6975
|
-
if (this.visibleClassValue)
|
|
6976
|
-
this.element.classList.remove(this.visibleClassValue);
|
|
6977
|
-
this.dispatch("leave", { detail: { entry }, bubbles: true });
|
|
6978
|
-
}
|
|
6969
|
+
this.teardown?.();
|
|
6970
|
+
this.teardown = null;
|
|
6979
6971
|
}
|
|
6980
6972
|
}
|
|
6981
6973
|
|
|
@@ -7873,6 +7865,33 @@ class Playlist extends Controller {
|
|
|
7873
7865
|
}
|
|
7874
7866
|
}
|
|
7875
7867
|
|
|
7868
|
+
class Motion extends Controller {
|
|
7869
|
+
static values = {
|
|
7870
|
+
threshold: { type: Number, default: 0.15 },
|
|
7871
|
+
once: { type: Boolean, default: true }
|
|
7872
|
+
};
|
|
7873
|
+
teardown = null;
|
|
7874
|
+
connect() {
|
|
7875
|
+
this.teardown = observeViewport(this.element, {
|
|
7876
|
+
threshold: this.thresholdValue,
|
|
7877
|
+
once: this.onceValue,
|
|
7878
|
+
onEnter: () => this.reveal(),
|
|
7879
|
+
onLeave: this.onceValue ? void 0 : () => this.reset()
|
|
7880
|
+
});
|
|
7881
|
+
}
|
|
7882
|
+
disconnect() {
|
|
7883
|
+
this.teardown?.();
|
|
7884
|
+
this.teardown = null;
|
|
7885
|
+
}
|
|
7886
|
+
reveal() {
|
|
7887
|
+
this.element.setAttribute("data-motion-visible", "");
|
|
7888
|
+
this.dispatch("reveal", { bubbles: true });
|
|
7889
|
+
}
|
|
7890
|
+
reset() {
|
|
7891
|
+
this.element.removeAttribute("data-motion-visible");
|
|
7892
|
+
}
|
|
7893
|
+
}
|
|
7894
|
+
|
|
7876
7895
|
function registerMidwestControllers(application) {
|
|
7877
7896
|
application.register("midwest-card", Card);
|
|
7878
7897
|
application.register("midwest-banner", Banner);
|
|
@@ -7914,6 +7933,7 @@ function registerMidwestControllers(application) {
|
|
|
7914
7933
|
application.register("midwest-theme-switch", ThemeSwitch);
|
|
7915
7934
|
application.register("midwest-panorama", Panorama);
|
|
7916
7935
|
application.register("midwest-playlist", Playlist);
|
|
7936
|
+
application.register("midwest-motion", Motion);
|
|
7917
7937
|
}
|
|
7918
7938
|
|
|
7919
7939
|
export { Banner, Card, Chart, CountdownTimer, registerMidwestControllers };
|