@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load_more_controller.js","sources":["../../../../../../../app/components/midwest/table_component/load_more_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Enables infinite scroll on a `midwest-table` by observing a sentinel <tr>\n// element at the bottom of the tbody. When the sentinel scrolls near the\n// viewport, this controller fetches the next-page URL, extracts the new <tr>\n// elements from the returned HTML, and appends them (plus the new sentinel,\n// if present) to the current tbody — replacing itself in the process.\n//\n// Values\n// url — URL for the next page (built by TablePresenter#next_page_url)\n// tbodyId — DOM id of the <tbody> to append rows into\nexport default class LoadMore extends Controller<HTMLTableRowElement> {\n static values = {\n url: String,\n tbodyId: String,\n }\n\n declare urlValue: string\n declare tbodyIdValue: string\n\n private
|
|
1
|
+
{"version":3,"file":"load_more_controller.js","sources":["../../../../../../../app/components/midwest/table_component/load_more_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\nimport { observeViewport } from '../../../assets/javascript/midwest/viewport_observer'\n\n// Enables infinite scroll on a `midwest-table` by observing a sentinel <tr>\n// element at the bottom of the tbody. When the sentinel scrolls near the\n// viewport, this controller fetches the next-page URL, extracts the new <tr>\n// elements from the returned HTML, and appends them (plus the new sentinel,\n// if present) to the current tbody — replacing itself in the process.\n//\n// Values\n// url — URL for the next page (built by TablePresenter#next_page_url)\n// tbodyId — DOM id of the <tbody> to append rows into\nexport default class LoadMore extends Controller<HTMLTableRowElement> {\n static values = {\n url: String,\n tbodyId: String,\n }\n\n declare urlValue: string\n declare tbodyIdValue: string\n\n private teardown: (() => void) | null = null\n private loading = false\n\n connect () {\n // No URL means this is the last page — nothing to load.\n if (!this.urlValue) return\n\n // The sentinel loads exactly once, then removes itself and is replaced by\n // the next page's sentinel — so `once` matches the lifecycle. `rootMargin`\n // starts the fetch 300px early so rows appear before the user hits bottom.\n this.teardown = observeViewport(this.element, {\n rootMargin: '0px 0px 300px 0px',\n once: true,\n onEnter: () => this.load(),\n })\n }\n\n disconnect () {\n this.teardown?.()\n this.teardown = null\n }\n\n private async load () {\n if (this.loading) return\n this.loading = true\n this.teardown?.()\n\n try {\n const response = await fetch(this.urlValue, {\n headers: {\n Accept: 'text/html',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n credentials: 'same-origin',\n })\n\n if (!response.ok) return\n\n const html = await response.text()\n const doc = new DOMParser().parseFromString(html, 'text/html')\n const tbody = document.getElementById(this.tbodyIdValue)\n const newRows = Array.from(\n doc.querySelectorAll<HTMLTableRowElement>('.midwest-table-body tr')\n )\n\n if (!tbody || newRows.length === 0) return\n\n // Remove the current sentinel before appending new rows so its position\n // doesn't shift the table layout during the DOM update.\n this.element.remove()\n\n // Import each row (including any new sentinel for the next page) into the\n // current document and append it to the live tbody.\n newRows.forEach(row => tbody.appendChild(document.importNode(row, true)))\n } catch {\n // Silently fail — the table remains fully functional, just without\n // auto-loading more rows.\n this.loading = false\n }\n }\n}\n"],"names":[],"mappings":";;;AAYA,MAAqB,iBAAiB,UAAgC,CAAA;AAAA,EACpE,OAAO,MAAS,GAAA;AAAA,IACd,GAAS,EAAA,MAAA;AAAA,IACT,OAAS,EAAA,MAAA;AAAA,GACX,CAAA;AAAA,EAKQ,QAAgC,GAAA,IAAA,CAAA;AAAA,EAChC,OAAU,GAAA,KAAA,CAAA;AAAA,EAElB,OAAW,GAAA;AAET,IAAA,IAAI,CAAC,IAAK,CAAA,QAAA;AAAU,MAAA,OAAA;AAKpB,IAAK,IAAA,CAAA,QAAA,GAAW,eAAgB,CAAA,IAAA,CAAK,OAAS,EAAA;AAAA,MAC5C,UAAY,EAAA,mBAAA;AAAA,MACZ,IAAM,EAAA,IAAA;AAAA,MACN,OAAA,EAAS,MAAM,IAAA,CAAK,IAAK,EAAA;AAAA,KAC1B,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,QAAW,IAAA,CAAA;AAChB,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA,CAAA;AAAA,GAClB;AAAA,EAEA,MAAc,IAAQ,GAAA;AACpB,IAAA,IAAI,IAAK,CAAA,OAAA;AAAS,MAAA,OAAA;AAClB,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,QAAW,IAAA,CAAA;AAEhB,IAAI,IAAA;AACF,MAAA,MAAM,QAAW,GAAA,MAAM,KAAM,CAAA,IAAA,CAAK,QAAU,EAAA;AAAA,QAC1C,OAAS,EAAA;AAAA,UACP,MAAmB,EAAA,WAAA;AAAA,UACnB,kBAAoB,EAAA,gBAAA;AAAA,SACtB;AAAA,QACA,WAAa,EAAA,aAAA;AAAA,OACd,CAAA,CAAA;AAED,MAAA,IAAI,CAAC,QAAS,CAAA,EAAA;AAAI,QAAA,OAAA;AAElB,MAAM,MAAA,IAAA,GAAU,MAAM,QAAA,CAAS,IAAK,EAAA,CAAA;AACpC,MAAA,MAAM,MAAU,IAAI,SAAA,EAAY,CAAA,eAAA,CAAgB,MAAM,WAAW,CAAA,CAAA;AACjE,MAAA,MAAM,KAAU,GAAA,QAAA,CAAS,cAAe,CAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AACzD,MAAA,MAAM,UAAU,KAAM,CAAA,IAAA;AAAA,QACpB,GAAA,CAAI,iBAAsC,wBAAwB,CAAA;AAAA,OACpE,CAAA;AAEA,MAAI,IAAA,CAAC,KAAS,IAAA,OAAA,CAAQ,MAAW,KAAA,CAAA;AAAG,QAAA,OAAA;AAIpC,MAAA,IAAA,CAAK,QAAQ,MAAO,EAAA,CAAA;AAIpB,MAAQ,OAAA,CAAA,OAAA,CAAQ,SAAO,KAAM,CAAA,WAAA,CAAY,SAAS,UAAW,CAAA,GAAA,EAAK,IAAI,CAAC,CAAC,CAAA,CAAA;AAAA,KACxE,CAAA,MAAA;AAGA,MAAA,IAAA,CAAK,OAAU,GAAA,KAAA,CAAA;AAAA,KACjB;AAAA,GACF;AACF;;;;"}
|
|
@@ -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 };
|