@unabridged/midwest 0.18.0 → 0.19.1

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.
Files changed (32) hide show
  1. package/README.md +4 -2
  2. package/app/assets/javascript/midwest/index.ts +6 -0
  3. package/app/assets/javascript/midwest.js +327 -571
  4. package/app/assets/javascript/midwest.js.map +1 -1
  5. package/app/assets/stylesheets/midwest/form-group.css +4 -0
  6. package/app/assets/stylesheets/midwest.css +1 -1
  7. package/app/assets/stylesheets/midwest.tailwind.css +4 -1
  8. package/dist/css/midwest.css +1 -1
  9. package/dist/javascript/collection/app/assets/javascript/midwest/index.js +7 -5
  10. package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
  11. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +106 -6
  12. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
  13. package/dist/javascript/collection/app/components/midwest/dropdown_component/dropdown_component_controller.js +1 -1
  14. package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js +116 -1
  15. package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js.map +1 -1
  16. package/dist/javascript/collection/app/components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller.js +24 -0
  17. package/dist/javascript/collection/app/components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller.js.map +1 -0
  18. package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js +60 -0
  19. package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js.map +1 -0
  20. package/dist/javascript/collection/app/components/midwest/table_component/table_component_controller.js +30 -0
  21. package/dist/javascript/collection/app/components/midwest/table_component/table_component_controller.js.map +1 -0
  22. package/dist/javascript/collection/node_modules/@floating-ui/core/dist/floating-ui.core.js +561 -0
  23. package/dist/javascript/collection/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -0
  24. package/dist/javascript/collection/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +736 -0
  25. package/dist/javascript/collection/node_modules/@floating-ui/dom/dist/floating-ui.dom.js.map +1 -0
  26. package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +166 -0
  27. package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -0
  28. package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +105 -0
  29. package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.js.map +1 -0
  30. package/dist/javascript/midwest.js +327 -571
  31. package/dist/javascript/midwest.js.map +1 -1
  32. package/package.json +3 -4
@@ -0,0 +1,24 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ class HorizontalScroll extends Controller {
4
+ resizeObserver = null;
5
+ connect() {
6
+ this.updateOverflow();
7
+ this.element.addEventListener("scroll", this.updateOverflow);
8
+ this.resizeObserver = new ResizeObserver(this.updateOverflow);
9
+ this.resizeObserver.observe(this.element);
10
+ }
11
+ disconnect() {
12
+ this.element.removeEventListener("scroll", this.updateOverflow);
13
+ this.resizeObserver?.disconnect();
14
+ this.resizeObserver = null;
15
+ }
16
+ updateOverflow = () => {
17
+ const el = this.element;
18
+ el.classList.toggle("can-scroll-left", el.scrollLeft > 0);
19
+ el.classList.toggle("can-scroll-right", el.scrollLeft < el.scrollWidth - el.clientWidth - 1);
20
+ };
21
+ }
22
+
23
+ export { HorizontalScroll as default };
24
+ //# sourceMappingURL=horizontal_scroll_component_controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"horizontal_scroll_component_controller.js","sources":["../../../../../../../app/components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\nexport default class HorizontalScroll extends Controller<HTMLElement> {\n private resizeObserver: ResizeObserver | null = null\n\n connect () {\n this.updateOverflow()\n this.element.addEventListener('scroll', this.updateOverflow)\n this.resizeObserver = new ResizeObserver(this.updateOverflow)\n this.resizeObserver.observe(this.element)\n }\n\n disconnect () {\n this.element.removeEventListener('scroll', this.updateOverflow)\n this.resizeObserver?.disconnect()\n this.resizeObserver = null\n }\n\n private updateOverflow = () => {\n const el = this.element\n el.classList.toggle('can-scroll-left', el.scrollLeft > 0)\n el.classList.toggle('can-scroll-right', el.scrollLeft < el.scrollWidth - el.clientWidth - 1)\n }\n}\n"],"names":[],"mappings":";;AAEA,MAAqB,yBAAyB,UAAwB,CAAA;AAAA,EAC5D,cAAwC,GAAA,IAAA,CAAA;AAAA,EAEhD,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,cAAe,EAAA,CAAA;AACpB,IAAA,IAAA,CAAK,OAAQ,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAC3D,IAAA,IAAA,CAAK,cAAiB,GAAA,IAAI,cAAe,CAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAC5D,IAAK,IAAA,CAAA,cAAA,CAAe,OAAQ,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,GAC1C;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,OAAQ,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,cAAc,CAAA,CAAA;AAC9D,IAAA,IAAA,CAAK,gBAAgB,UAAW,EAAA,CAAA;AAChC,IAAA,IAAA,CAAK,cAAiB,GAAA,IAAA,CAAA;AAAA,GACxB;AAAA,EAEQ,iBAAiB,MAAM;AAC7B,IAAA,MAAM,KAAK,IAAK,CAAA,OAAA,CAAA;AAChB,IAAA,EAAA,CAAG,SAAU,CAAA,MAAA,CAAO,iBAAmB,EAAA,EAAA,CAAG,aAAa,CAAC,CAAA,CAAA;AACxD,IAAG,EAAA,CAAA,SAAA,CAAU,OAAO,kBAAoB,EAAA,EAAA,CAAG,aAAa,EAAG,CAAA,WAAA,GAAc,EAAG,CAAA,WAAA,GAAc,CAAC,CAAA,CAAA;AAAA,GAC7F,CAAA;AACF;;;;"}
@@ -0,0 +1,60 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ class LoadMore extends Controller {
4
+ static values = {
5
+ url: String,
6
+ tbodyId: String
7
+ };
8
+ observer = null;
9
+ loading = false;
10
+ connect() {
11
+ if (!this.urlValue)
12
+ return;
13
+ this.observer = new IntersectionObserver(
14
+ (entries) => {
15
+ if (entries[0].isIntersecting)
16
+ this.load();
17
+ },
18
+ // Start fetching 300px before the sentinel enters the viewport so rows
19
+ // appear before the user actually reaches the bottom.
20
+ { rootMargin: "0px 0px 300px 0px" }
21
+ );
22
+ this.observer.observe(this.element);
23
+ }
24
+ disconnect() {
25
+ this.observer?.disconnect();
26
+ this.observer = null;
27
+ }
28
+ async load() {
29
+ if (this.loading)
30
+ return;
31
+ this.loading = true;
32
+ this.observer?.disconnect();
33
+ try {
34
+ const response = await fetch(this.urlValue, {
35
+ headers: {
36
+ Accept: "text/html",
37
+ "X-Requested-With": "XMLHttpRequest"
38
+ },
39
+ credentials: "same-origin"
40
+ });
41
+ if (!response.ok)
42
+ return;
43
+ const html = await response.text();
44
+ const doc = new DOMParser().parseFromString(html, "text/html");
45
+ const tbody = document.getElementById(this.tbodyIdValue);
46
+ const newRows = Array.from(
47
+ doc.querySelectorAll(".midwest-table-body tr")
48
+ );
49
+ if (!tbody || newRows.length === 0)
50
+ return;
51
+ this.element.remove();
52
+ newRows.forEach((row) => tbody.appendChild(document.importNode(row, true)));
53
+ } catch {
54
+ this.loading = false;
55
+ }
56
+ }
57
+ }
58
+
59
+ export { LoadMore as default };
60
+ //# sourceMappingURL=load_more_controller.js.map
@@ -0,0 +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 observer: IntersectionObserver | 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 this.observer = new IntersectionObserver(\n (entries) => { if (entries[0].isIntersecting) this.load() },\n // Start fetching 300px before the sentinel enters the viewport so rows\n // appear before the user actually reaches the bottom.\n { rootMargin: '0px 0px 300px 0px' }\n )\n this.observer.observe(this.element)\n }\n\n disconnect () {\n this.observer?.disconnect()\n this.observer = null\n }\n\n private async load () {\n if (this.loading) return\n this.loading = true\n this.observer?.disconnect()\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":";;AAWA,MAAqB,iBAAiB,UAAgC,CAAA;AAAA,EACpE,OAAO,MAAS,GAAA;AAAA,IACd,GAAS,EAAA,MAAA;AAAA,IACT,OAAS,EAAA,MAAA;AAAA,GACX,CAAA;AAAA,EAKQ,QAAwC,GAAA,IAAA,CAAA;AAAA,EACxC,OAAU,GAAA,KAAA,CAAA;AAAA,EAElB,OAAW,GAAA;AAET,IAAA,IAAI,CAAC,IAAK,CAAA,QAAA;AAAU,MAAA,OAAA;AAEpB,IAAA,IAAA,CAAK,WAAW,IAAI,oBAAA;AAAA,MAClB,CAAC,OAAY,KAAA;AAAE,QAAI,IAAA,OAAA,CAAQ,CAAC,CAAE,CAAA,cAAA;AAAgB,UAAA,IAAA,CAAK,IAAK,EAAA,CAAA;AAAA,OAAE;AAAA;AAAA;AAAA,MAG1D,EAAE,YAAY,mBAAoB,EAAA;AAAA,KACpC,CAAA;AACA,IAAK,IAAA,CAAA,QAAA,CAAS,OAAQ,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,GACpC;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,UAAU,UAAW,EAAA,CAAA;AAC1B,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,UAAU,UAAW,EAAA,CAAA;AAE1B,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;;;;"}
@@ -0,0 +1,30 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ class Table extends Controller {
4
+ static targets = ["selectAll", "rowCheckbox"];
5
+ toggleAll() {
6
+ const checked = this.selectAllTarget.checked;
7
+ this.rowCheckboxTargets.forEach((cb) => {
8
+ cb.checked = checked;
9
+ });
10
+ }
11
+ updateSelectAll() {
12
+ if (!this.hasSelectAllTarget)
13
+ return;
14
+ const total = this.rowCheckboxTargets.length;
15
+ const checkedCount = this.rowCheckboxTargets.filter((cb) => cb.checked).length;
16
+ if (checkedCount === 0) {
17
+ this.selectAllTarget.checked = false;
18
+ this.selectAllTarget.indeterminate = false;
19
+ } else if (checkedCount === total) {
20
+ this.selectAllTarget.checked = true;
21
+ this.selectAllTarget.indeterminate = false;
22
+ } else {
23
+ this.selectAllTarget.checked = false;
24
+ this.selectAllTarget.indeterminate = true;
25
+ }
26
+ }
27
+ }
28
+
29
+ export { Table as default };
30
+ //# sourceMappingURL=table_component_controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table_component_controller.js","sources":["../../../../../../../app/components/midwest/table_component/table_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\nexport default class Table extends Controller<HTMLElement> {\n static targets = ['selectAll', 'rowCheckbox']\n\n declare readonly selectAllTarget: HTMLInputElement\n declare readonly rowCheckboxTargets: HTMLInputElement[]\n declare readonly hasSelectAllTarget: boolean\n\n toggleAll () {\n const checked = this.selectAllTarget.checked\n this.rowCheckboxTargets.forEach(cb => { cb.checked = checked })\n }\n\n updateSelectAll () {\n if (!this.hasSelectAllTarget) return\n\n const total = this.rowCheckboxTargets.length\n const checkedCount = this.rowCheckboxTargets.filter(cb => cb.checked).length\n\n if (checkedCount === 0) {\n this.selectAllTarget.checked = false\n this.selectAllTarget.indeterminate = false\n } else if (checkedCount === total) {\n this.selectAllTarget.checked = true\n this.selectAllTarget.indeterminate = false\n } else {\n this.selectAllTarget.checked = false\n this.selectAllTarget.indeterminate = true\n }\n }\n}\n"],"names":[],"mappings":";;AAEA,MAAqB,cAAc,UAAwB,CAAA;AAAA,EACzD,OAAO,OAAA,GAAU,CAAC,WAAA,EAAa,aAAa,CAAA,CAAA;AAAA,EAM5C,SAAa,GAAA;AACX,IAAM,MAAA,OAAA,GAAU,KAAK,eAAgB,CAAA,OAAA,CAAA;AACrC,IAAK,IAAA,CAAA,kBAAA,CAAmB,QAAQ,CAAM,EAAA,KAAA;AAAE,MAAA,EAAA,CAAG,OAAU,GAAA,OAAA,CAAA;AAAA,KAAS,CAAA,CAAA;AAAA,GAChE;AAAA,EAEA,eAAmB,GAAA;AACjB,IAAA,IAAI,CAAC,IAAK,CAAA,kBAAA;AAAoB,MAAA,OAAA;AAE9B,IAAM,MAAA,KAAA,GAAQ,KAAK,kBAAmB,CAAA,MAAA,CAAA;AACtC,IAAA,MAAM,eAAe,IAAK,CAAA,kBAAA,CAAmB,OAAO,CAAM,EAAA,KAAA,EAAA,CAAG,OAAO,CAAE,CAAA,MAAA,CAAA;AAEtE,IAAA,IAAI,iBAAiB,CAAG,EAAA;AACtB,MAAA,IAAA,CAAK,gBAAgB,OAAU,GAAA,KAAA,CAAA;AAC/B,MAAA,IAAA,CAAK,gBAAgB,aAAgB,GAAA,KAAA,CAAA;AAAA,KACvC,MAAA,IAAW,iBAAiB,KAAO,EAAA;AACjC,MAAA,IAAA,CAAK,gBAAgB,OAAU,GAAA,IAAA,CAAA;AAC/B,MAAA,IAAA,CAAK,gBAAgB,aAAgB,GAAA,KAAA,CAAA;AAAA,KAChC,MAAA;AACL,MAAA,IAAA,CAAK,gBAAgB,OAAU,GAAA,KAAA,CAAA;AAC/B,MAAA,IAAA,CAAK,gBAAgB,aAAgB,GAAA,IAAA,CAAA;AAAA,KACvC;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,561 @@
1
+ import { evaluate, placements, getAlignmentSides, getSide, getAlignment, getSideAxis, clamp, getAlignmentAxis, getPaddingObject, rectToClientRect, getOppositeAlignmentPlacement, sides, getOppositeAxis, getAxisLength } from '../../utils/dist/floating-ui.utils.js';
2
+
3
+ function computeCoordsFromPlacement(_ref, placement, rtl) {
4
+ let {
5
+ reference,
6
+ floating
7
+ } = _ref;
8
+ const sideAxis = getSideAxis(placement);
9
+ const alignmentAxis = getAlignmentAxis(placement);
10
+ const alignLength = getAxisLength(alignmentAxis);
11
+ const side = getSide(placement);
12
+ const isVertical = sideAxis === 'y';
13
+ const commonX = reference.x + reference.width / 2 - floating.width / 2;
14
+ const commonY = reference.y + reference.height / 2 - floating.height / 2;
15
+ const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
16
+ let coords;
17
+ switch (side) {
18
+ case 'top':
19
+ coords = {
20
+ x: commonX,
21
+ y: reference.y - floating.height
22
+ };
23
+ break;
24
+ case 'bottom':
25
+ coords = {
26
+ x: commonX,
27
+ y: reference.y + reference.height
28
+ };
29
+ break;
30
+ case 'right':
31
+ coords = {
32
+ x: reference.x + reference.width,
33
+ y: commonY
34
+ };
35
+ break;
36
+ case 'left':
37
+ coords = {
38
+ x: reference.x - floating.width,
39
+ y: commonY
40
+ };
41
+ break;
42
+ default:
43
+ coords = {
44
+ x: reference.x,
45
+ y: reference.y
46
+ };
47
+ }
48
+ switch (getAlignment(placement)) {
49
+ case 'start':
50
+ coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
51
+ break;
52
+ case 'end':
53
+ coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
54
+ break;
55
+ }
56
+ return coords;
57
+ }
58
+
59
+ /**
60
+ * Resolves with an object of overflow side offsets that determine how much the
61
+ * element is overflowing a given clipping boundary on each side.
62
+ * - positive = overflowing the boundary by that number of pixels
63
+ * - negative = how many pixels left before it will overflow
64
+ * - 0 = lies flush with the boundary
65
+ * @see https://floating-ui.com/docs/detectOverflow
66
+ */
67
+ async function detectOverflow(state, options) {
68
+ var _await$platform$isEle;
69
+ if (options === void 0) {
70
+ options = {};
71
+ }
72
+ const {
73
+ x,
74
+ y,
75
+ platform,
76
+ rects,
77
+ elements,
78
+ strategy
79
+ } = state;
80
+ const {
81
+ boundary = 'clippingAncestors',
82
+ rootBoundary = 'viewport',
83
+ elementContext = 'floating',
84
+ altBoundary = false,
85
+ padding = 0
86
+ } = evaluate(options, state);
87
+ const paddingObject = getPaddingObject(padding);
88
+ const altContext = elementContext === 'floating' ? 'reference' : 'floating';
89
+ const element = elements[altBoundary ? altContext : elementContext];
90
+ const clippingClientRect = rectToClientRect(await platform.getClippingRect({
91
+ element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
92
+ boundary,
93
+ rootBoundary,
94
+ strategy
95
+ }));
96
+ const rect = elementContext === 'floating' ? {
97
+ x,
98
+ y,
99
+ width: rects.floating.width,
100
+ height: rects.floating.height
101
+ } : rects.reference;
102
+ const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
103
+ const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
104
+ x: 1,
105
+ y: 1
106
+ } : {
107
+ x: 1,
108
+ y: 1
109
+ };
110
+ const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
111
+ elements,
112
+ rect,
113
+ offsetParent,
114
+ strategy
115
+ }) : rect);
116
+ return {
117
+ top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
118
+ bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
119
+ left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
120
+ right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
121
+ };
122
+ }
123
+
124
+ // Maximum number of resets that can occur before bailing to avoid infinite reset loops.
125
+ const MAX_RESET_COUNT = 50;
126
+
127
+ /**
128
+ * Computes the `x` and `y` coordinates that will place the floating element
129
+ * next to a given reference element.
130
+ *
131
+ * This export does not have any `platform` interface logic. You will need to
132
+ * write one for the platform you are using Floating UI with.
133
+ */
134
+ const computePosition = async (reference, floating, config) => {
135
+ const {
136
+ placement = 'bottom',
137
+ strategy = 'absolute',
138
+ middleware = [],
139
+ platform
140
+ } = config;
141
+ const platformWithDetectOverflow = platform.detectOverflow ? platform : {
142
+ ...platform,
143
+ detectOverflow
144
+ };
145
+ const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
146
+ let rects = await platform.getElementRects({
147
+ reference,
148
+ floating,
149
+ strategy
150
+ });
151
+ let {
152
+ x,
153
+ y
154
+ } = computeCoordsFromPlacement(rects, placement, rtl);
155
+ let statefulPlacement = placement;
156
+ let resetCount = 0;
157
+ const middlewareData = {};
158
+ for (let i = 0; i < middleware.length; i++) {
159
+ const currentMiddleware = middleware[i];
160
+ if (!currentMiddleware) {
161
+ continue;
162
+ }
163
+ const {
164
+ name,
165
+ fn
166
+ } = currentMiddleware;
167
+ const {
168
+ x: nextX,
169
+ y: nextY,
170
+ data,
171
+ reset
172
+ } = await fn({
173
+ x,
174
+ y,
175
+ initialPlacement: placement,
176
+ placement: statefulPlacement,
177
+ strategy,
178
+ middlewareData,
179
+ rects,
180
+ platform: platformWithDetectOverflow,
181
+ elements: {
182
+ reference,
183
+ floating
184
+ }
185
+ });
186
+ x = nextX != null ? nextX : x;
187
+ y = nextY != null ? nextY : y;
188
+ middlewareData[name] = {
189
+ ...middlewareData[name],
190
+ ...data
191
+ };
192
+ if (reset && resetCount < MAX_RESET_COUNT) {
193
+ resetCount++;
194
+ if (typeof reset === 'object') {
195
+ if (reset.placement) {
196
+ statefulPlacement = reset.placement;
197
+ }
198
+ if (reset.rects) {
199
+ rects = reset.rects === true ? await platform.getElementRects({
200
+ reference,
201
+ floating,
202
+ strategy
203
+ }) : reset.rects;
204
+ }
205
+ ({
206
+ x,
207
+ y
208
+ } = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
209
+ }
210
+ i = -1;
211
+ }
212
+ }
213
+ return {
214
+ x,
215
+ y,
216
+ placement: statefulPlacement,
217
+ strategy,
218
+ middlewareData
219
+ };
220
+ };
221
+
222
+ function getPlacementList(alignment, autoAlignment, allowedPlacements) {
223
+ const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);
224
+ return allowedPlacementsSortedByAlignment.filter(placement => {
225
+ if (alignment) {
226
+ return getAlignment(placement) === alignment || (autoAlignment ? getOppositeAlignmentPlacement(placement) !== placement : false);
227
+ }
228
+ return true;
229
+ });
230
+ }
231
+ /**
232
+ * Optimizes the visibility of the floating element by choosing the placement
233
+ * that has the most space available automatically, without needing to specify a
234
+ * preferred placement. Alternative to `flip`.
235
+ * @see https://floating-ui.com/docs/autoPlacement
236
+ */
237
+ const autoPlacement = function (options) {
238
+ if (options === void 0) {
239
+ options = {};
240
+ }
241
+ return {
242
+ name: 'autoPlacement',
243
+ options,
244
+ async fn(state) {
245
+ var _middlewareData$autoP, _middlewareData$autoP2, _placementsThatFitOnE;
246
+ const {
247
+ rects,
248
+ middlewareData,
249
+ placement,
250
+ platform,
251
+ elements
252
+ } = state;
253
+ const {
254
+ crossAxis = false,
255
+ alignment,
256
+ allowedPlacements = placements,
257
+ autoAlignment = true,
258
+ ...detectOverflowOptions
259
+ } = evaluate(options, state);
260
+ const placements$1 = alignment !== undefined || allowedPlacements === placements ? getPlacementList(alignment || null, autoAlignment, allowedPlacements) : allowedPlacements;
261
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
262
+ const currentIndex = ((_middlewareData$autoP = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP.index) || 0;
263
+ const currentPlacement = placements$1[currentIndex];
264
+ if (currentPlacement == null) {
265
+ return {};
266
+ }
267
+ const alignmentSides = getAlignmentSides(currentPlacement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)));
268
+
269
+ // Make `computeCoords` start from the right place.
270
+ if (placement !== currentPlacement) {
271
+ return {
272
+ reset: {
273
+ placement: placements$1[0]
274
+ }
275
+ };
276
+ }
277
+ const currentOverflows = [overflow[getSide(currentPlacement)], overflow[alignmentSides[0]], overflow[alignmentSides[1]]];
278
+ const allOverflows = [...(((_middlewareData$autoP2 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP2.overflows) || []), {
279
+ placement: currentPlacement,
280
+ overflows: currentOverflows
281
+ }];
282
+ const nextPlacement = placements$1[currentIndex + 1];
283
+
284
+ // There are more placements to check.
285
+ if (nextPlacement) {
286
+ return {
287
+ data: {
288
+ index: currentIndex + 1,
289
+ overflows: allOverflows
290
+ },
291
+ reset: {
292
+ placement: nextPlacement
293
+ }
294
+ };
295
+ }
296
+ const placementsSortedByMostSpace = allOverflows.map(d => {
297
+ const alignment = getAlignment(d.placement);
298
+ return [d.placement, alignment && crossAxis ?
299
+ // Check along the mainAxis and main crossAxis side.
300
+ d.overflows.slice(0, 2).reduce((acc, v) => acc + v, 0) :
301
+ // Check only the mainAxis.
302
+ d.overflows[0], d.overflows];
303
+ }).sort((a, b) => a[1] - b[1]);
304
+ const placementsThatFitOnEachSide = placementsSortedByMostSpace.filter(d => d[2].slice(0,
305
+ // Aligned placements should not check their opposite crossAxis
306
+ // side.
307
+ getAlignment(d[0]) ? 2 : 3).every(v => v <= 0));
308
+ const resetPlacement = ((_placementsThatFitOnE = placementsThatFitOnEachSide[0]) == null ? void 0 : _placementsThatFitOnE[0]) || placementsSortedByMostSpace[0][0];
309
+ if (resetPlacement !== placement) {
310
+ return {
311
+ data: {
312
+ index: currentIndex + 1,
313
+ overflows: allOverflows
314
+ },
315
+ reset: {
316
+ placement: resetPlacement
317
+ }
318
+ };
319
+ }
320
+ return {};
321
+ }
322
+ };
323
+ };
324
+
325
+ function getSideOffsets(overflow, rect) {
326
+ return {
327
+ top: overflow.top - rect.height,
328
+ right: overflow.right - rect.width,
329
+ bottom: overflow.bottom - rect.height,
330
+ left: overflow.left - rect.width
331
+ };
332
+ }
333
+ function isAnySideFullyClipped(overflow) {
334
+ return sides.some(side => overflow[side] >= 0);
335
+ }
336
+ /**
337
+ * Provides data to hide the floating element in applicable situations, such as
338
+ * when it is not in the same clipping context as the reference element.
339
+ * @see https://floating-ui.com/docs/hide
340
+ */
341
+ const hide = function (options) {
342
+ if (options === void 0) {
343
+ options = {};
344
+ }
345
+ return {
346
+ name: 'hide',
347
+ options,
348
+ async fn(state) {
349
+ const {
350
+ rects,
351
+ platform
352
+ } = state;
353
+ const {
354
+ strategy = 'referenceHidden',
355
+ ...detectOverflowOptions
356
+ } = evaluate(options, state);
357
+ switch (strategy) {
358
+ case 'referenceHidden':
359
+ {
360
+ const overflow = await platform.detectOverflow(state, {
361
+ ...detectOverflowOptions,
362
+ elementContext: 'reference'
363
+ });
364
+ const offsets = getSideOffsets(overflow, rects.reference);
365
+ return {
366
+ data: {
367
+ referenceHiddenOffsets: offsets,
368
+ referenceHidden: isAnySideFullyClipped(offsets)
369
+ }
370
+ };
371
+ }
372
+ case 'escaped':
373
+ {
374
+ const overflow = await platform.detectOverflow(state, {
375
+ ...detectOverflowOptions,
376
+ altBoundary: true
377
+ });
378
+ const offsets = getSideOffsets(overflow, rects.floating);
379
+ return {
380
+ data: {
381
+ escapedOffsets: offsets,
382
+ escaped: isAnySideFullyClipped(offsets)
383
+ }
384
+ };
385
+ }
386
+ default:
387
+ {
388
+ return {};
389
+ }
390
+ }
391
+ }
392
+ };
393
+ };
394
+
395
+ const originSides = /*#__PURE__*/new Set(['left', 'top']);
396
+
397
+ // For type backwards-compatibility, the `OffsetOptions` type was also
398
+ // Derivable.
399
+
400
+ async function convertValueToCoords(state, options) {
401
+ const {
402
+ placement,
403
+ platform,
404
+ elements
405
+ } = state;
406
+ const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
407
+ const side = getSide(placement);
408
+ const alignment = getAlignment(placement);
409
+ const isVertical = getSideAxis(placement) === 'y';
410
+ const mainAxisMulti = originSides.has(side) ? -1 : 1;
411
+ const crossAxisMulti = rtl && isVertical ? -1 : 1;
412
+ const rawValue = evaluate(options, state);
413
+
414
+ // eslint-disable-next-line prefer-const
415
+ let {
416
+ mainAxis,
417
+ crossAxis,
418
+ alignmentAxis
419
+ } = typeof rawValue === 'number' ? {
420
+ mainAxis: rawValue,
421
+ crossAxis: 0,
422
+ alignmentAxis: null
423
+ } : {
424
+ mainAxis: rawValue.mainAxis || 0,
425
+ crossAxis: rawValue.crossAxis || 0,
426
+ alignmentAxis: rawValue.alignmentAxis
427
+ };
428
+ if (alignment && typeof alignmentAxis === 'number') {
429
+ crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
430
+ }
431
+ return isVertical ? {
432
+ x: crossAxis * crossAxisMulti,
433
+ y: mainAxis * mainAxisMulti
434
+ } : {
435
+ x: mainAxis * mainAxisMulti,
436
+ y: crossAxis * crossAxisMulti
437
+ };
438
+ }
439
+
440
+ /**
441
+ * Modifies the placement by translating the floating element along the
442
+ * specified axes.
443
+ * A number (shorthand for `mainAxis` or distance), or an axes configuration
444
+ * object may be passed.
445
+ * @see https://floating-ui.com/docs/offset
446
+ */
447
+ const offset = function (options) {
448
+ if (options === void 0) {
449
+ options = 0;
450
+ }
451
+ return {
452
+ name: 'offset',
453
+ options,
454
+ async fn(state) {
455
+ var _middlewareData$offse, _middlewareData$arrow;
456
+ const {
457
+ x,
458
+ y,
459
+ placement,
460
+ middlewareData
461
+ } = state;
462
+ const diffCoords = await convertValueToCoords(state, options);
463
+
464
+ // If the placement is the same and the arrow caused an alignment offset
465
+ // then we don't need to change the positioning coordinates.
466
+ if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
467
+ return {};
468
+ }
469
+ return {
470
+ x: x + diffCoords.x,
471
+ y: y + diffCoords.y,
472
+ data: {
473
+ ...diffCoords,
474
+ placement
475
+ }
476
+ };
477
+ }
478
+ };
479
+ };
480
+
481
+ /**
482
+ * Optimizes the visibility of the floating element by shifting it in order to
483
+ * keep it in view when it will overflow the clipping boundary.
484
+ * @see https://floating-ui.com/docs/shift
485
+ */
486
+ const shift = function (options) {
487
+ if (options === void 0) {
488
+ options = {};
489
+ }
490
+ return {
491
+ name: 'shift',
492
+ options,
493
+ async fn(state) {
494
+ const {
495
+ x,
496
+ y,
497
+ placement,
498
+ platform
499
+ } = state;
500
+ const {
501
+ mainAxis: checkMainAxis = true,
502
+ crossAxis: checkCrossAxis = false,
503
+ limiter = {
504
+ fn: _ref => {
505
+ let {
506
+ x,
507
+ y
508
+ } = _ref;
509
+ return {
510
+ x,
511
+ y
512
+ };
513
+ }
514
+ },
515
+ ...detectOverflowOptions
516
+ } = evaluate(options, state);
517
+ const coords = {
518
+ x,
519
+ y
520
+ };
521
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
522
+ const crossAxis = getSideAxis(getSide(placement));
523
+ const mainAxis = getOppositeAxis(crossAxis);
524
+ let mainAxisCoord = coords[mainAxis];
525
+ let crossAxisCoord = coords[crossAxis];
526
+ if (checkMainAxis) {
527
+ const minSide = mainAxis === 'y' ? 'top' : 'left';
528
+ const maxSide = mainAxis === 'y' ? 'bottom' : 'right';
529
+ const min = mainAxisCoord + overflow[minSide];
530
+ const max = mainAxisCoord - overflow[maxSide];
531
+ mainAxisCoord = clamp(min, mainAxisCoord, max);
532
+ }
533
+ if (checkCrossAxis) {
534
+ const minSide = crossAxis === 'y' ? 'top' : 'left';
535
+ const maxSide = crossAxis === 'y' ? 'bottom' : 'right';
536
+ const min = crossAxisCoord + overflow[minSide];
537
+ const max = crossAxisCoord - overflow[maxSide];
538
+ crossAxisCoord = clamp(min, crossAxisCoord, max);
539
+ }
540
+ const limitedCoords = limiter.fn({
541
+ ...state,
542
+ [mainAxis]: mainAxisCoord,
543
+ [crossAxis]: crossAxisCoord
544
+ });
545
+ return {
546
+ ...limitedCoords,
547
+ data: {
548
+ x: limitedCoords.x - x,
549
+ y: limitedCoords.y - y,
550
+ enabled: {
551
+ [mainAxis]: checkMainAxis,
552
+ [crossAxis]: checkCrossAxis
553
+ }
554
+ }
555
+ };
556
+ }
557
+ };
558
+ };
559
+
560
+ export { autoPlacement, computePosition, detectOverflow, hide, offset, rectToClientRect, shift };
561
+ //# sourceMappingURL=floating-ui.core.js.map