@unabridged/midwest 0.18.0 → 0.19.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 +4 -2
- package/app/assets/javascript/midwest/index.ts +6 -0
- package/app/assets/javascript/midwest.js +327 -571
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest/form-group.css +4 -0
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +4 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +7 -5
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +106 -6
- 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 +1 -1
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js +116 -1
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller.js +24 -0
- package/dist/javascript/collection/app/components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js +60 -0
- package/dist/javascript/collection/app/components/midwest/table_component/load_more_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/table_component/table_component_controller.js +30 -0
- package/dist/javascript/collection/app/components/midwest/table_component/table_component_controller.js.map +1 -0
- package/dist/javascript/collection/node_modules/@floating-ui/core/dist/floating-ui.core.js +561 -0
- package/dist/javascript/collection/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -0
- package/dist/javascript/collection/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +736 -0
- package/dist/javascript/collection/node_modules/@floating-ui/dom/dist/floating-ui.dom.js.map +1 -0
- package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +166 -0
- package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -0
- package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +105 -0
- package/dist/javascript/collection/node_modules/@floating-ui/utils/dist/floating-ui.utils.js.map +1 -0
- package/dist/javascript/midwest.js +327 -571
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +3 -4
|
@@ -548,17 +548,48 @@ class Banner extends Controller {
|
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
const FORMATTERS = {
|
|
552
|
+
phone: (v) => {
|
|
553
|
+
const d = v.replace(/\D/g, "").slice(0, 10);
|
|
554
|
+
if (d.length <= 3)
|
|
555
|
+
return d;
|
|
556
|
+
if (d.length <= 6)
|
|
557
|
+
return `(${d.slice(0, 3)}) ${d.slice(3)}`;
|
|
558
|
+
return `(${d.slice(0, 3)}) ${d.slice(3, 6)}-${d.slice(6)}`;
|
|
559
|
+
},
|
|
560
|
+
credit_card: (v) => {
|
|
561
|
+
const d = v.replace(/\D/g, "").slice(0, 16);
|
|
562
|
+
return d.match(/.{1,4}/g)?.join(" ") ?? d;
|
|
563
|
+
},
|
|
564
|
+
zip: (v) => {
|
|
565
|
+
const d = v.replace(/\D/g, "");
|
|
566
|
+
if (d.length <= 5)
|
|
567
|
+
return d;
|
|
568
|
+
return `${d.slice(0, 5)}-${d.slice(5, 9)}`;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
551
571
|
class Input extends Controller {
|
|
552
|
-
static targets = ["input", "counter", "capsLockWarning"];
|
|
572
|
+
static targets = ["input", "counter", "capsLockWarning", "matchError"];
|
|
573
|
+
static values = {
|
|
574
|
+
match: { type: String, default: "" },
|
|
575
|
+
autoformat: { type: String, default: "" }
|
|
576
|
+
};
|
|
553
577
|
updateClearButton = null;
|
|
554
578
|
updateCounter = null;
|
|
555
579
|
updateCapsLock = null;
|
|
556
580
|
hideCapsLock = null;
|
|
581
|
+
matchListener = null;
|
|
582
|
+
matchInvalidListener = null;
|
|
583
|
+
matchSourceListener = null;
|
|
584
|
+
matchSourceElement = null;
|
|
585
|
+
autoformatListener = null;
|
|
557
586
|
connect() {
|
|
558
587
|
this.applyColor();
|
|
559
588
|
this.applySearchClear();
|
|
560
589
|
this.applyCounter();
|
|
561
590
|
this.applyPassword();
|
|
591
|
+
this.applyMatch();
|
|
592
|
+
this.applyAutoformat();
|
|
562
593
|
}
|
|
563
594
|
disconnect() {
|
|
564
595
|
if (this.updateClearButton) {
|
|
@@ -579,6 +610,24 @@ class Input extends Controller {
|
|
|
579
610
|
this.inputTarget.removeEventListener("blur", this.hideCapsLock);
|
|
580
611
|
this.hideCapsLock = null;
|
|
581
612
|
}
|
|
613
|
+
if (this.matchListener) {
|
|
614
|
+
this.inputTarget.removeEventListener("input", this.matchListener);
|
|
615
|
+
this.inputTarget.removeEventListener("blur", this.matchListener);
|
|
616
|
+
this.matchListener = null;
|
|
617
|
+
}
|
|
618
|
+
if (this.matchInvalidListener) {
|
|
619
|
+
this.inputTarget.removeEventListener("invalid", this.matchInvalidListener);
|
|
620
|
+
this.matchInvalidListener = null;
|
|
621
|
+
}
|
|
622
|
+
if (this.matchSourceListener && this.matchSourceElement) {
|
|
623
|
+
this.matchSourceElement.removeEventListener("input", this.matchSourceListener);
|
|
624
|
+
this.matchSourceListener = null;
|
|
625
|
+
this.matchSourceElement = null;
|
|
626
|
+
}
|
|
627
|
+
if (this.autoformatListener) {
|
|
628
|
+
this.inputTarget.removeEventListener("blur", this.autoformatListener);
|
|
629
|
+
this.autoformatListener = null;
|
|
630
|
+
}
|
|
582
631
|
}
|
|
583
632
|
increment() {
|
|
584
633
|
const input = this.inputTarget;
|
|
@@ -673,6 +722,72 @@ class Input extends Controller {
|
|
|
673
722
|
this.inputTarget.focus();
|
|
674
723
|
});
|
|
675
724
|
}
|
|
725
|
+
// Validates that this field's value matches the value of the element
|
|
726
|
+
// identified by matchValue (a CSS selector). Uses setCustomValidity to
|
|
727
|
+
// block form submission. Shows the error inline via the matchError target
|
|
728
|
+
// rather than the browser's native tooltip (invalid event is suppressed).
|
|
729
|
+
applyMatch() {
|
|
730
|
+
if (!this.matchValue)
|
|
731
|
+
return;
|
|
732
|
+
const showError = () => {
|
|
733
|
+
this.element.classList.add("has-error", "theme-red");
|
|
734
|
+
if (this.hasMatchErrorTarget)
|
|
735
|
+
this.matchErrorTarget.hidden = false;
|
|
736
|
+
};
|
|
737
|
+
const clearError = () => {
|
|
738
|
+
this.element.classList.remove("has-error", "theme-red");
|
|
739
|
+
if (this.hasMatchErrorTarget)
|
|
740
|
+
this.matchErrorTarget.hidden = true;
|
|
741
|
+
};
|
|
742
|
+
const validate = () => {
|
|
743
|
+
const other2 = document.querySelector(this.matchValue);
|
|
744
|
+
if (!this.inputTarget.value) {
|
|
745
|
+
this.inputTarget.setCustomValidity("");
|
|
746
|
+
clearError();
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (!other2 || this.inputTarget.value === other2.value) {
|
|
750
|
+
this.inputTarget.setCustomValidity("");
|
|
751
|
+
clearError();
|
|
752
|
+
} else {
|
|
753
|
+
this.inputTarget.setCustomValidity("Values do not match");
|
|
754
|
+
showError();
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
this.matchListener = validate;
|
|
758
|
+
this.inputTarget.addEventListener("input", validate);
|
|
759
|
+
this.inputTarget.addEventListener("blur", validate);
|
|
760
|
+
this.matchInvalidListener = (e) => {
|
|
761
|
+
e.preventDefault();
|
|
762
|
+
showError();
|
|
763
|
+
};
|
|
764
|
+
this.inputTarget.addEventListener("invalid", this.matchInvalidListener);
|
|
765
|
+
const other = document.querySelector(this.matchValue);
|
|
766
|
+
if (other) {
|
|
767
|
+
this.matchSourceElement = other;
|
|
768
|
+
this.matchSourceListener = validate;
|
|
769
|
+
other.addEventListener("input", validate);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// Reformats the input value on blur using a named formatter from FORMATTERS.
|
|
773
|
+
// Dispatches input + change events after reformatting so downstream
|
|
774
|
+
// listeners (counters, form state) stay in sync.
|
|
775
|
+
applyAutoformat() {
|
|
776
|
+
if (!this.autoformatValue)
|
|
777
|
+
return;
|
|
778
|
+
const fmt = FORMATTERS[this.autoformatValue];
|
|
779
|
+
if (!fmt)
|
|
780
|
+
return;
|
|
781
|
+
this.autoformatListener = () => {
|
|
782
|
+
const formatted = fmt(this.inputTarget.value);
|
|
783
|
+
if (formatted !== this.inputTarget.value) {
|
|
784
|
+
this.inputTarget.value = formatted;
|
|
785
|
+
this.inputTarget.dispatchEvent(new Event("input", { bubbles: true }));
|
|
786
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
this.inputTarget.addEventListener("blur", this.autoformatListener);
|
|
790
|
+
}
|
|
676
791
|
}
|
|
677
792
|
|
|
678
793
|
class File extends Controller {
|
|
@@ -798,41 +913,9 @@ function getAlignmentSides(placement, rects, rtl) {
|
|
|
798
913
|
}
|
|
799
914
|
return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
|
|
800
915
|
}
|
|
801
|
-
function getExpandedPlacements(placement) {
|
|
802
|
-
const oppositePlacement = getOppositePlacement(placement);
|
|
803
|
-
return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
|
|
804
|
-
}
|
|
805
916
|
function getOppositeAlignmentPlacement(placement) {
|
|
806
917
|
return placement.includes('start') ? placement.replace('start', 'end') : placement.replace('end', 'start');
|
|
807
918
|
}
|
|
808
|
-
const lrPlacement = ['left', 'right'];
|
|
809
|
-
const rlPlacement = ['right', 'left'];
|
|
810
|
-
const tbPlacement = ['top', 'bottom'];
|
|
811
|
-
const btPlacement = ['bottom', 'top'];
|
|
812
|
-
function getSideList(side, isStart, rtl) {
|
|
813
|
-
switch (side) {
|
|
814
|
-
case 'top':
|
|
815
|
-
case 'bottom':
|
|
816
|
-
if (rtl) return isStart ? rlPlacement : lrPlacement;
|
|
817
|
-
return isStart ? lrPlacement : rlPlacement;
|
|
818
|
-
case 'left':
|
|
819
|
-
case 'right':
|
|
820
|
-
return isStart ? tbPlacement : btPlacement;
|
|
821
|
-
default:
|
|
822
|
-
return [];
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
|
|
826
|
-
const alignment = getAlignment(placement);
|
|
827
|
-
let list = getSideList(getSide(placement), direction === 'start', rtl);
|
|
828
|
-
if (alignment) {
|
|
829
|
-
list = list.map(side => side + "-" + alignment);
|
|
830
|
-
if (flipAlignment) {
|
|
831
|
-
list = list.concat(list.map(getOppositeAlignmentPlacement));
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
return list;
|
|
835
|
-
}
|
|
836
919
|
function getOppositePlacement(placement) {
|
|
837
920
|
const side = getSide(placement);
|
|
838
921
|
return oppositeSideMap[side] + placement.slice(side.length);
|
|
@@ -1092,88 +1175,6 @@ const computePosition$1 = async (reference, floating, config) => {
|
|
|
1092
1175
|
};
|
|
1093
1176
|
};
|
|
1094
1177
|
|
|
1095
|
-
/**
|
|
1096
|
-
* Provides data to position an inner element of the floating element so that it
|
|
1097
|
-
* appears centered to the reference element.
|
|
1098
|
-
* @see https://floating-ui.com/docs/arrow
|
|
1099
|
-
*/
|
|
1100
|
-
const arrow = options => ({
|
|
1101
|
-
name: 'arrow',
|
|
1102
|
-
options,
|
|
1103
|
-
async fn(state) {
|
|
1104
|
-
const {
|
|
1105
|
-
x,
|
|
1106
|
-
y,
|
|
1107
|
-
placement,
|
|
1108
|
-
rects,
|
|
1109
|
-
platform,
|
|
1110
|
-
elements,
|
|
1111
|
-
middlewareData
|
|
1112
|
-
} = state;
|
|
1113
|
-
// Since `element` is required, we don't Partial<> the type.
|
|
1114
|
-
const {
|
|
1115
|
-
element,
|
|
1116
|
-
padding = 0
|
|
1117
|
-
} = evaluate(options, state) || {};
|
|
1118
|
-
if (element == null) {
|
|
1119
|
-
return {};
|
|
1120
|
-
}
|
|
1121
|
-
const paddingObject = getPaddingObject(padding);
|
|
1122
|
-
const coords = {
|
|
1123
|
-
x,
|
|
1124
|
-
y
|
|
1125
|
-
};
|
|
1126
|
-
const axis = getAlignmentAxis(placement);
|
|
1127
|
-
const length = getAxisLength(axis);
|
|
1128
|
-
const arrowDimensions = await platform.getDimensions(element);
|
|
1129
|
-
const isYAxis = axis === 'y';
|
|
1130
|
-
const minProp = isYAxis ? 'top' : 'left';
|
|
1131
|
-
const maxProp = isYAxis ? 'bottom' : 'right';
|
|
1132
|
-
const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
|
|
1133
|
-
const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
|
|
1134
|
-
const startDiff = coords[axis] - rects.reference[axis];
|
|
1135
|
-
const arrowOffsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(element));
|
|
1136
|
-
let clientSize = arrowOffsetParent ? arrowOffsetParent[clientProp] : 0;
|
|
1137
|
-
|
|
1138
|
-
// DOM platform can return `window` as the `offsetParent`.
|
|
1139
|
-
if (!clientSize || !(await (platform.isElement == null ? void 0 : platform.isElement(arrowOffsetParent)))) {
|
|
1140
|
-
clientSize = elements.floating[clientProp] || rects.floating[length];
|
|
1141
|
-
}
|
|
1142
|
-
const centerToReference = endDiff / 2 - startDiff / 2;
|
|
1143
|
-
|
|
1144
|
-
// If the padding is large enough that it causes the arrow to no longer be
|
|
1145
|
-
// centered, modify the padding so that it is centered.
|
|
1146
|
-
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
|
|
1147
|
-
const minPadding = min(paddingObject[minProp], largestPossiblePadding);
|
|
1148
|
-
const maxPadding = min(paddingObject[maxProp], largestPossiblePadding);
|
|
1149
|
-
|
|
1150
|
-
// Make sure the arrow doesn't overflow the floating element if the center
|
|
1151
|
-
// point is outside the floating element's bounds.
|
|
1152
|
-
const min$1 = minPadding;
|
|
1153
|
-
const max = clientSize - arrowDimensions[length] - maxPadding;
|
|
1154
|
-
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
|
|
1155
|
-
const offset = clamp(min$1, center, max);
|
|
1156
|
-
|
|
1157
|
-
// If the reference is small enough that the arrow's padding causes it to
|
|
1158
|
-
// to point to nothing for an aligned placement, adjust the offset of the
|
|
1159
|
-
// floating element itself. To ensure `shift()` continues to take action,
|
|
1160
|
-
// a single reset is performed when this is true.
|
|
1161
|
-
const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
|
|
1162
|
-
const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max : 0;
|
|
1163
|
-
return {
|
|
1164
|
-
[axis]: coords[axis] + alignmentOffset,
|
|
1165
|
-
data: {
|
|
1166
|
-
[axis]: offset,
|
|
1167
|
-
centerOffset: center - offset - alignmentOffset,
|
|
1168
|
-
...(shouldAddOffset && {
|
|
1169
|
-
alignmentOffset
|
|
1170
|
-
})
|
|
1171
|
-
},
|
|
1172
|
-
reset: shouldAddOffset
|
|
1173
|
-
};
|
|
1174
|
-
}
|
|
1175
|
-
});
|
|
1176
|
-
|
|
1177
1178
|
function getPlacementList(alignment, autoAlignment, allowedPlacements) {
|
|
1178
1179
|
const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);
|
|
1179
1180
|
return allowedPlacementsSortedByAlignment.filter(placement => {
|
|
@@ -1277,138 +1278,6 @@ const autoPlacement$1 = function (options) {
|
|
|
1277
1278
|
};
|
|
1278
1279
|
};
|
|
1279
1280
|
|
|
1280
|
-
/**
|
|
1281
|
-
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
1282
|
-
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
1283
|
-
* clipping boundary. Alternative to `autoPlacement`.
|
|
1284
|
-
* @see https://floating-ui.com/docs/flip
|
|
1285
|
-
*/
|
|
1286
|
-
const flip = function (options) {
|
|
1287
|
-
if (options === void 0) {
|
|
1288
|
-
options = {};
|
|
1289
|
-
}
|
|
1290
|
-
return {
|
|
1291
|
-
name: 'flip',
|
|
1292
|
-
options,
|
|
1293
|
-
async fn(state) {
|
|
1294
|
-
var _middlewareData$arrow, _middlewareData$flip;
|
|
1295
|
-
const {
|
|
1296
|
-
placement,
|
|
1297
|
-
middlewareData,
|
|
1298
|
-
rects,
|
|
1299
|
-
initialPlacement,
|
|
1300
|
-
platform,
|
|
1301
|
-
elements
|
|
1302
|
-
} = state;
|
|
1303
|
-
const {
|
|
1304
|
-
mainAxis: checkMainAxis = true,
|
|
1305
|
-
crossAxis: checkCrossAxis = true,
|
|
1306
|
-
fallbackPlacements: specifiedFallbackPlacements,
|
|
1307
|
-
fallbackStrategy = 'bestFit',
|
|
1308
|
-
fallbackAxisSideDirection = 'none',
|
|
1309
|
-
flipAlignment = true,
|
|
1310
|
-
...detectOverflowOptions
|
|
1311
|
-
} = evaluate(options, state);
|
|
1312
|
-
|
|
1313
|
-
// If a reset by the arrow was caused due to an alignment offset being
|
|
1314
|
-
// added, we should skip any logic now since `flip()` has already done its
|
|
1315
|
-
// work.
|
|
1316
|
-
// https://github.com/floating-ui/floating-ui/issues/2549#issuecomment-1719601643
|
|
1317
|
-
if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
|
|
1318
|
-
return {};
|
|
1319
|
-
}
|
|
1320
|
-
const side = getSide(placement);
|
|
1321
|
-
const initialSideAxis = getSideAxis(initialPlacement);
|
|
1322
|
-
const isBasePlacement = getSide(initialPlacement) === initialPlacement;
|
|
1323
|
-
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
|
|
1324
|
-
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
|
|
1325
|
-
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== 'none';
|
|
1326
|
-
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
|
|
1327
|
-
fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
|
|
1328
|
-
}
|
|
1329
|
-
const placements = [initialPlacement, ...fallbackPlacements];
|
|
1330
|
-
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
1331
|
-
const overflows = [];
|
|
1332
|
-
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
|
|
1333
|
-
if (checkMainAxis) {
|
|
1334
|
-
overflows.push(overflow[side]);
|
|
1335
|
-
}
|
|
1336
|
-
if (checkCrossAxis) {
|
|
1337
|
-
const sides = getAlignmentSides(placement, rects, rtl);
|
|
1338
|
-
overflows.push(overflow[sides[0]], overflow[sides[1]]);
|
|
1339
|
-
}
|
|
1340
|
-
overflowsData = [...overflowsData, {
|
|
1341
|
-
placement,
|
|
1342
|
-
overflows
|
|
1343
|
-
}];
|
|
1344
|
-
|
|
1345
|
-
// One or more sides is overflowing.
|
|
1346
|
-
if (!overflows.every(side => side <= 0)) {
|
|
1347
|
-
var _middlewareData$flip2, _overflowsData$filter;
|
|
1348
|
-
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
|
|
1349
|
-
const nextPlacement = placements[nextIndex];
|
|
1350
|
-
if (nextPlacement) {
|
|
1351
|
-
const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;
|
|
1352
|
-
if (!ignoreCrossAxisOverflow ||
|
|
1353
|
-
// We leave the current main axis only if every placement on that axis
|
|
1354
|
-
// overflows the main axis.
|
|
1355
|
-
overflowsData.every(d => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {
|
|
1356
|
-
// Try next placement and re-run the lifecycle.
|
|
1357
|
-
return {
|
|
1358
|
-
data: {
|
|
1359
|
-
index: nextIndex,
|
|
1360
|
-
overflows: overflowsData
|
|
1361
|
-
},
|
|
1362
|
-
reset: {
|
|
1363
|
-
placement: nextPlacement
|
|
1364
|
-
}
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// First, find the candidates that fit on the mainAxis side of overflow,
|
|
1370
|
-
// then find the placement that fits the best on the main crossAxis side.
|
|
1371
|
-
let resetPlacement = (_overflowsData$filter = overflowsData.filter(d => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
|
|
1372
|
-
|
|
1373
|
-
// Otherwise fallback.
|
|
1374
|
-
if (!resetPlacement) {
|
|
1375
|
-
switch (fallbackStrategy) {
|
|
1376
|
-
case 'bestFit':
|
|
1377
|
-
{
|
|
1378
|
-
var _overflowsData$filter2;
|
|
1379
|
-
const placement = (_overflowsData$filter2 = overflowsData.filter(d => {
|
|
1380
|
-
if (hasFallbackAxisSideDirection) {
|
|
1381
|
-
const currentSideAxis = getSideAxis(d.placement);
|
|
1382
|
-
return currentSideAxis === initialSideAxis ||
|
|
1383
|
-
// Create a bias to the `y` side axis due to horizontal
|
|
1384
|
-
// reading directions favoring greater width.
|
|
1385
|
-
currentSideAxis === 'y';
|
|
1386
|
-
}
|
|
1387
|
-
return true;
|
|
1388
|
-
}).map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
|
|
1389
|
-
if (placement) {
|
|
1390
|
-
resetPlacement = placement;
|
|
1391
|
-
}
|
|
1392
|
-
break;
|
|
1393
|
-
}
|
|
1394
|
-
case 'initialPlacement':
|
|
1395
|
-
resetPlacement = initialPlacement;
|
|
1396
|
-
break;
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
if (placement !== resetPlacement) {
|
|
1400
|
-
return {
|
|
1401
|
-
reset: {
|
|
1402
|
-
placement: resetPlacement
|
|
1403
|
-
}
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
return {};
|
|
1408
|
-
}
|
|
1409
|
-
};
|
|
1410
|
-
};
|
|
1411
|
-
|
|
1412
1281
|
function getSideOffsets(overflow, rect) {
|
|
1413
1282
|
return {
|
|
1414
1283
|
top: overflow.top - rect.height,
|
|
@@ -1479,137 +1348,6 @@ const hide$1 = function (options) {
|
|
|
1479
1348
|
};
|
|
1480
1349
|
};
|
|
1481
1350
|
|
|
1482
|
-
function getBoundingRect(rects) {
|
|
1483
|
-
const minX = min(...rects.map(rect => rect.left));
|
|
1484
|
-
const minY = min(...rects.map(rect => rect.top));
|
|
1485
|
-
const maxX = max(...rects.map(rect => rect.right));
|
|
1486
|
-
const maxY = max(...rects.map(rect => rect.bottom));
|
|
1487
|
-
return {
|
|
1488
|
-
x: minX,
|
|
1489
|
-
y: minY,
|
|
1490
|
-
width: maxX - minX,
|
|
1491
|
-
height: maxY - minY
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
function getRectsByLine(rects) {
|
|
1495
|
-
const sortedRects = rects.slice().sort((a, b) => a.y - b.y);
|
|
1496
|
-
const groups = [];
|
|
1497
|
-
let prevRect = null;
|
|
1498
|
-
for (let i = 0; i < sortedRects.length; i++) {
|
|
1499
|
-
const rect = sortedRects[i];
|
|
1500
|
-
if (!prevRect || rect.y - prevRect.y > prevRect.height / 2) {
|
|
1501
|
-
groups.push([rect]);
|
|
1502
|
-
} else {
|
|
1503
|
-
groups[groups.length - 1].push(rect);
|
|
1504
|
-
}
|
|
1505
|
-
prevRect = rect;
|
|
1506
|
-
}
|
|
1507
|
-
return groups.map(rect => rectToClientRect(getBoundingRect(rect)));
|
|
1508
|
-
}
|
|
1509
|
-
/**
|
|
1510
|
-
* Provides improved positioning for inline reference elements that can span
|
|
1511
|
-
* over multiple lines, such as hyperlinks or range selections.
|
|
1512
|
-
* @see https://floating-ui.com/docs/inline
|
|
1513
|
-
*/
|
|
1514
|
-
const inline = function (options) {
|
|
1515
|
-
if (options === void 0) {
|
|
1516
|
-
options = {};
|
|
1517
|
-
}
|
|
1518
|
-
return {
|
|
1519
|
-
name: 'inline',
|
|
1520
|
-
options,
|
|
1521
|
-
async fn(state) {
|
|
1522
|
-
const {
|
|
1523
|
-
placement,
|
|
1524
|
-
elements,
|
|
1525
|
-
rects,
|
|
1526
|
-
platform,
|
|
1527
|
-
strategy
|
|
1528
|
-
} = state;
|
|
1529
|
-
// A MouseEvent's client{X,Y} coords can be up to 2 pixels off a
|
|
1530
|
-
// ClientRect's bounds, despite the event listener being triggered. A
|
|
1531
|
-
// padding of 2 seems to handle this issue.
|
|
1532
|
-
const {
|
|
1533
|
-
padding = 2,
|
|
1534
|
-
x,
|
|
1535
|
-
y
|
|
1536
|
-
} = evaluate(options, state);
|
|
1537
|
-
const nativeClientRects = Array.from((await (platform.getClientRects == null ? void 0 : platform.getClientRects(elements.reference))) || []);
|
|
1538
|
-
const clientRects = getRectsByLine(nativeClientRects);
|
|
1539
|
-
const fallback = rectToClientRect(getBoundingRect(nativeClientRects));
|
|
1540
|
-
const paddingObject = getPaddingObject(padding);
|
|
1541
|
-
function getBoundingClientRect() {
|
|
1542
|
-
// There are two rects and they are disjoined.
|
|
1543
|
-
if (clientRects.length === 2 && clientRects[0].left > clientRects[1].right && x != null && y != null) {
|
|
1544
|
-
// Find the first rect in which the point is fully inside.
|
|
1545
|
-
return clientRects.find(rect => x > rect.left - paddingObject.left && x < rect.right + paddingObject.right && y > rect.top - paddingObject.top && y < rect.bottom + paddingObject.bottom) || fallback;
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
// There are 2 or more connected rects.
|
|
1549
|
-
if (clientRects.length >= 2) {
|
|
1550
|
-
if (getSideAxis(placement) === 'y') {
|
|
1551
|
-
const firstRect = clientRects[0];
|
|
1552
|
-
const lastRect = clientRects[clientRects.length - 1];
|
|
1553
|
-
const isTop = getSide(placement) === 'top';
|
|
1554
|
-
const top = firstRect.top;
|
|
1555
|
-
const bottom = lastRect.bottom;
|
|
1556
|
-
const left = isTop ? firstRect.left : lastRect.left;
|
|
1557
|
-
const right = isTop ? firstRect.right : lastRect.right;
|
|
1558
|
-
const width = right - left;
|
|
1559
|
-
const height = bottom - top;
|
|
1560
|
-
return {
|
|
1561
|
-
top,
|
|
1562
|
-
bottom,
|
|
1563
|
-
left,
|
|
1564
|
-
right,
|
|
1565
|
-
width,
|
|
1566
|
-
height,
|
|
1567
|
-
x: left,
|
|
1568
|
-
y: top
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
const isLeftSide = getSide(placement) === 'left';
|
|
1572
|
-
const maxRight = max(...clientRects.map(rect => rect.right));
|
|
1573
|
-
const minLeft = min(...clientRects.map(rect => rect.left));
|
|
1574
|
-
const measureRects = clientRects.filter(rect => isLeftSide ? rect.left === minLeft : rect.right === maxRight);
|
|
1575
|
-
const top = measureRects[0].top;
|
|
1576
|
-
const bottom = measureRects[measureRects.length - 1].bottom;
|
|
1577
|
-
const left = minLeft;
|
|
1578
|
-
const right = maxRight;
|
|
1579
|
-
const width = right - left;
|
|
1580
|
-
const height = bottom - top;
|
|
1581
|
-
return {
|
|
1582
|
-
top,
|
|
1583
|
-
bottom,
|
|
1584
|
-
left,
|
|
1585
|
-
right,
|
|
1586
|
-
width,
|
|
1587
|
-
height,
|
|
1588
|
-
x: left,
|
|
1589
|
-
y: top
|
|
1590
|
-
};
|
|
1591
|
-
}
|
|
1592
|
-
return fallback;
|
|
1593
|
-
}
|
|
1594
|
-
const resetRects = await platform.getElementRects({
|
|
1595
|
-
reference: {
|
|
1596
|
-
getBoundingClientRect
|
|
1597
|
-
},
|
|
1598
|
-
floating: elements.floating,
|
|
1599
|
-
strategy
|
|
1600
|
-
});
|
|
1601
|
-
if (rects.reference.x !== resetRects.reference.x || rects.reference.y !== resetRects.reference.y || rects.reference.width !== resetRects.reference.width || rects.reference.height !== resetRects.reference.height) {
|
|
1602
|
-
return {
|
|
1603
|
-
reset: {
|
|
1604
|
-
rects: resetRects
|
|
1605
|
-
}
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
return {};
|
|
1609
|
-
}
|
|
1610
|
-
};
|
|
1611
|
-
};
|
|
1612
|
-
|
|
1613
1351
|
const originSides = /*#__PURE__*/new Set(['left', 'top']);
|
|
1614
1352
|
|
|
1615
1353
|
// For type backwards-compatibility, the `OffsetOptions` type was also
|
|
@@ -1774,158 +1512,6 @@ const shift$1 = function (options) {
|
|
|
1774
1512
|
}
|
|
1775
1513
|
};
|
|
1776
1514
|
};
|
|
1777
|
-
/**
|
|
1778
|
-
* Built-in `limiter` that will stop `shift()` at a certain point.
|
|
1779
|
-
*/
|
|
1780
|
-
const limitShift = function (options) {
|
|
1781
|
-
if (options === void 0) {
|
|
1782
|
-
options = {};
|
|
1783
|
-
}
|
|
1784
|
-
return {
|
|
1785
|
-
options,
|
|
1786
|
-
fn(state) {
|
|
1787
|
-
const {
|
|
1788
|
-
x,
|
|
1789
|
-
y,
|
|
1790
|
-
placement,
|
|
1791
|
-
rects,
|
|
1792
|
-
middlewareData
|
|
1793
|
-
} = state;
|
|
1794
|
-
const {
|
|
1795
|
-
offset = 0,
|
|
1796
|
-
mainAxis: checkMainAxis = true,
|
|
1797
|
-
crossAxis: checkCrossAxis = true
|
|
1798
|
-
} = evaluate(options, state);
|
|
1799
|
-
const coords = {
|
|
1800
|
-
x,
|
|
1801
|
-
y
|
|
1802
|
-
};
|
|
1803
|
-
const crossAxis = getSideAxis(placement);
|
|
1804
|
-
const mainAxis = getOppositeAxis(crossAxis);
|
|
1805
|
-
let mainAxisCoord = coords[mainAxis];
|
|
1806
|
-
let crossAxisCoord = coords[crossAxis];
|
|
1807
|
-
const rawOffset = evaluate(offset, state);
|
|
1808
|
-
const computedOffset = typeof rawOffset === 'number' ? {
|
|
1809
|
-
mainAxis: rawOffset,
|
|
1810
|
-
crossAxis: 0
|
|
1811
|
-
} : {
|
|
1812
|
-
mainAxis: 0,
|
|
1813
|
-
crossAxis: 0,
|
|
1814
|
-
...rawOffset
|
|
1815
|
-
};
|
|
1816
|
-
if (checkMainAxis) {
|
|
1817
|
-
const len = mainAxis === 'y' ? 'height' : 'width';
|
|
1818
|
-
const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;
|
|
1819
|
-
const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;
|
|
1820
|
-
if (mainAxisCoord < limitMin) {
|
|
1821
|
-
mainAxisCoord = limitMin;
|
|
1822
|
-
} else if (mainAxisCoord > limitMax) {
|
|
1823
|
-
mainAxisCoord = limitMax;
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
if (checkCrossAxis) {
|
|
1827
|
-
var _middlewareData$offse, _middlewareData$offse2;
|
|
1828
|
-
const len = mainAxis === 'y' ? 'width' : 'height';
|
|
1829
|
-
const isOriginSide = originSides.has(getSide(placement));
|
|
1830
|
-
const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse[crossAxis]) || 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);
|
|
1831
|
-
const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : ((_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) || 0) - (isOriginSide ? computedOffset.crossAxis : 0);
|
|
1832
|
-
if (crossAxisCoord < limitMin) {
|
|
1833
|
-
crossAxisCoord = limitMin;
|
|
1834
|
-
} else if (crossAxisCoord > limitMax) {
|
|
1835
|
-
crossAxisCoord = limitMax;
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
return {
|
|
1839
|
-
[mainAxis]: mainAxisCoord,
|
|
1840
|
-
[crossAxis]: crossAxisCoord
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
};
|
|
1844
|
-
};
|
|
1845
|
-
|
|
1846
|
-
/**
|
|
1847
|
-
* Provides data that allows you to change the size of the floating element —
|
|
1848
|
-
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
1849
|
-
* width of the reference element.
|
|
1850
|
-
* @see https://floating-ui.com/docs/size
|
|
1851
|
-
*/
|
|
1852
|
-
const size = function (options) {
|
|
1853
|
-
if (options === void 0) {
|
|
1854
|
-
options = {};
|
|
1855
|
-
}
|
|
1856
|
-
return {
|
|
1857
|
-
name: 'size',
|
|
1858
|
-
options,
|
|
1859
|
-
async fn(state) {
|
|
1860
|
-
var _state$middlewareData, _state$middlewareData2;
|
|
1861
|
-
const {
|
|
1862
|
-
placement,
|
|
1863
|
-
rects,
|
|
1864
|
-
platform,
|
|
1865
|
-
elements
|
|
1866
|
-
} = state;
|
|
1867
|
-
const {
|
|
1868
|
-
apply = () => {},
|
|
1869
|
-
...detectOverflowOptions
|
|
1870
|
-
} = evaluate(options, state);
|
|
1871
|
-
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
|
|
1872
|
-
const side = getSide(placement);
|
|
1873
|
-
const alignment = getAlignment(placement);
|
|
1874
|
-
const isYAxis = getSideAxis(placement) === 'y';
|
|
1875
|
-
const {
|
|
1876
|
-
width,
|
|
1877
|
-
height
|
|
1878
|
-
} = rects.floating;
|
|
1879
|
-
let heightSide;
|
|
1880
|
-
let widthSide;
|
|
1881
|
-
if (side === 'top' || side === 'bottom') {
|
|
1882
|
-
heightSide = side;
|
|
1883
|
-
widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';
|
|
1884
|
-
} else {
|
|
1885
|
-
widthSide = side;
|
|
1886
|
-
heightSide = alignment === 'end' ? 'top' : 'bottom';
|
|
1887
|
-
}
|
|
1888
|
-
const maximumClippingHeight = height - overflow.top - overflow.bottom;
|
|
1889
|
-
const maximumClippingWidth = width - overflow.left - overflow.right;
|
|
1890
|
-
const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);
|
|
1891
|
-
const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);
|
|
1892
|
-
const noShift = !state.middlewareData.shift;
|
|
1893
|
-
let availableHeight = overflowAvailableHeight;
|
|
1894
|
-
let availableWidth = overflowAvailableWidth;
|
|
1895
|
-
if ((_state$middlewareData = state.middlewareData.shift) != null && _state$middlewareData.enabled.x) {
|
|
1896
|
-
availableWidth = maximumClippingWidth;
|
|
1897
|
-
}
|
|
1898
|
-
if ((_state$middlewareData2 = state.middlewareData.shift) != null && _state$middlewareData2.enabled.y) {
|
|
1899
|
-
availableHeight = maximumClippingHeight;
|
|
1900
|
-
}
|
|
1901
|
-
if (noShift && !alignment) {
|
|
1902
|
-
const xMin = max(overflow.left, 0);
|
|
1903
|
-
const xMax = max(overflow.right, 0);
|
|
1904
|
-
const yMin = max(overflow.top, 0);
|
|
1905
|
-
const yMax = max(overflow.bottom, 0);
|
|
1906
|
-
if (isYAxis) {
|
|
1907
|
-
availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right));
|
|
1908
|
-
} else {
|
|
1909
|
-
availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom));
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
await apply({
|
|
1913
|
-
...state,
|
|
1914
|
-
availableWidth,
|
|
1915
|
-
availableHeight
|
|
1916
|
-
});
|
|
1917
|
-
const nextDimensions = await platform.getDimensions(elements.floating);
|
|
1918
|
-
if (width !== nextDimensions.width || height !== nextDimensions.height) {
|
|
1919
|
-
return {
|
|
1920
|
-
reset: {
|
|
1921
|
-
rects: true
|
|
1922
|
-
}
|
|
1923
|
-
};
|
|
1924
|
-
}
|
|
1925
|
-
return {};
|
|
1926
|
-
}
|
|
1927
|
-
};
|
|
1928
|
-
};
|
|
1929
1515
|
|
|
1930
1516
|
function hasWindow() {
|
|
1931
1517
|
return typeof window !== 'undefined';
|
|
@@ -2791,22 +2377,6 @@ const autoPlacement = autoPlacement$1;
|
|
|
2791
2377
|
*/
|
|
2792
2378
|
const shift = shift$1;
|
|
2793
2379
|
|
|
2794
|
-
/**
|
|
2795
|
-
* Optimizes the visibility of the floating element by flipping the `placement`
|
|
2796
|
-
* in order to keep it in view when the preferred placement(s) will overflow the
|
|
2797
|
-
* clipping boundary. Alternative to `autoPlacement`.
|
|
2798
|
-
* @see https://floating-ui.com/docs/flip
|
|
2799
|
-
*/
|
|
2800
|
-
flip;
|
|
2801
|
-
|
|
2802
|
-
/**
|
|
2803
|
-
* Provides data that allows you to change the size of the floating element —
|
|
2804
|
-
* for instance, prevent it from overflowing the clipping boundary or match the
|
|
2805
|
-
* width of the reference element.
|
|
2806
|
-
* @see https://floating-ui.com/docs/size
|
|
2807
|
-
*/
|
|
2808
|
-
size;
|
|
2809
|
-
|
|
2810
2380
|
/**
|
|
2811
2381
|
* Provides data to hide the floating element in applicable situations, such as
|
|
2812
2382
|
* when it is not in the same clipping context as the reference element.
|
|
@@ -2814,25 +2384,6 @@ size;
|
|
|
2814
2384
|
*/
|
|
2815
2385
|
const hide = hide$1;
|
|
2816
2386
|
|
|
2817
|
-
/**
|
|
2818
|
-
* Provides data to position an inner element of the floating element so that it
|
|
2819
|
-
* appears centered to the reference element.
|
|
2820
|
-
* @see https://floating-ui.com/docs/arrow
|
|
2821
|
-
*/
|
|
2822
|
-
arrow;
|
|
2823
|
-
|
|
2824
|
-
/**
|
|
2825
|
-
* Provides improved positioning for inline reference elements that can span
|
|
2826
|
-
* over multiple lines, such as hyperlinks or range selections.
|
|
2827
|
-
* @see https://floating-ui.com/docs/inline
|
|
2828
|
-
*/
|
|
2829
|
-
inline;
|
|
2830
|
-
|
|
2831
|
-
/**
|
|
2832
|
-
* Built-in `limiter` that will stop `shift()` at a certain point.
|
|
2833
|
-
*/
|
|
2834
|
-
limitShift;
|
|
2835
|
-
|
|
2836
2387
|
/**
|
|
2837
2388
|
* Computes the `x` and `y` coordinates that will place the floating element
|
|
2838
2389
|
* next to a given reference element.
|
|
@@ -3290,11 +2841,12 @@ const NON_SUBMITTING_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
|
3290
2841
|
]);
|
|
3291
2842
|
const FORM_ELEMENT_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
|
|
3292
2843
|
class Carousel extends Controller {
|
|
3293
|
-
static targets = ["track", "prev", "next", "dot"];
|
|
2844
|
+
static targets = ["track", "prev", "next", "dot", "status"];
|
|
3294
2845
|
static values = {
|
|
3295
2846
|
wizard: { type: Boolean, default: false },
|
|
3296
2847
|
autoplay: { type: Number, default: 0 },
|
|
3297
|
-
loop: { type: Boolean, default: false }
|
|
2848
|
+
loop: { type: Boolean, default: false },
|
|
2849
|
+
fade: { type: Boolean, default: false }
|
|
3298
2850
|
};
|
|
3299
2851
|
observer = null;
|
|
3300
2852
|
_currentIndex = 0;
|
|
@@ -3302,7 +2854,11 @@ class Carousel extends Controller {
|
|
|
3302
2854
|
_lastTouchX = 0;
|
|
3303
2855
|
_autoplayTimer = null;
|
|
3304
2856
|
connect() {
|
|
3305
|
-
this.
|
|
2857
|
+
if (this.fadeValue) {
|
|
2858
|
+
this.initFade();
|
|
2859
|
+
} else {
|
|
2860
|
+
this.setupObserver();
|
|
2861
|
+
}
|
|
3306
2862
|
this.updateNavigation();
|
|
3307
2863
|
this.element.addEventListener("keydown", this.handleArrowKeys);
|
|
3308
2864
|
if (this.wizardValue) {
|
|
@@ -3316,6 +2872,8 @@ class Carousel extends Controller {
|
|
|
3316
2872
|
this.startAutoplay();
|
|
3317
2873
|
this.element.addEventListener("mouseenter", this.pauseAutoplay);
|
|
3318
2874
|
this.element.addEventListener("mouseleave", this.resumeAutoplay);
|
|
2875
|
+
this.element.addEventListener("focusin", this.pauseAutoplay);
|
|
2876
|
+
this.element.addEventListener("focusout", this.resumeAutoplay);
|
|
3319
2877
|
}
|
|
3320
2878
|
}
|
|
3321
2879
|
disconnect() {
|
|
@@ -3324,12 +2882,20 @@ class Carousel extends Controller {
|
|
|
3324
2882
|
this.element.removeEventListener("keydown", this.handleKeydown);
|
|
3325
2883
|
this.element.removeEventListener("mouseenter", this.pauseAutoplay);
|
|
3326
2884
|
this.element.removeEventListener("mouseleave", this.resumeAutoplay);
|
|
2885
|
+
this.element.removeEventListener("focusin", this.pauseAutoplay);
|
|
2886
|
+
this.element.removeEventListener("focusout", this.resumeAutoplay);
|
|
3327
2887
|
this.trackTarget.removeEventListener("wheel", this.handleWheel);
|
|
3328
2888
|
this.trackTarget.removeEventListener("touchstart", this.handleTouchStart);
|
|
3329
2889
|
this.trackTarget.removeEventListener("touchmove", this.handleTouchMove);
|
|
3330
2890
|
this.stopAutoplay();
|
|
3331
2891
|
}
|
|
3332
2892
|
next() {
|
|
2893
|
+
if (this.fadeValue) {
|
|
2894
|
+
const atEnd2 = this._currentIndex >= this.slides.length - 1;
|
|
2895
|
+
const nextIndex = this.loopValue && atEnd2 ? 0 : Math.min(this._currentIndex + 1, this.slides.length - 1);
|
|
2896
|
+
this.activateSlide(nextIndex);
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
3333
2899
|
const atEnd = this._currentIndex >= this.slides.length - 1;
|
|
3334
2900
|
if (this.loopValue && atEnd) {
|
|
3335
2901
|
this.slides[0]?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
@@ -3338,6 +2904,12 @@ class Carousel extends Controller {
|
|
|
3338
2904
|
}
|
|
3339
2905
|
}
|
|
3340
2906
|
previous() {
|
|
2907
|
+
if (this.fadeValue) {
|
|
2908
|
+
const atStart2 = this._currentIndex <= 0;
|
|
2909
|
+
const prevIndex = this.loopValue && atStart2 ? this.slides.length - 1 : Math.max(this._currentIndex - 1, 0);
|
|
2910
|
+
this.activateSlide(prevIndex);
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
3341
2913
|
const atStart = this._currentIndex <= 0;
|
|
3342
2914
|
if (this.loopValue && atStart) {
|
|
3343
2915
|
const last = this.slides[this.slides.length - 1];
|
|
@@ -3349,6 +2921,10 @@ class Carousel extends Controller {
|
|
|
3349
2921
|
goto(event) {
|
|
3350
2922
|
const button = event.currentTarget;
|
|
3351
2923
|
const index = parseInt(button.dataset.index ?? "0", 10);
|
|
2924
|
+
if (this.fadeValue) {
|
|
2925
|
+
this.activateSlide(index);
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
3352
2928
|
const slide = this.slides[index];
|
|
3353
2929
|
slide?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3354
2930
|
}
|
|
@@ -3368,10 +2944,13 @@ class Carousel extends Controller {
|
|
|
3368
2944
|
this.next();
|
|
3369
2945
|
}
|
|
3370
2946
|
scrolled() {
|
|
2947
|
+
if (this.fadeValue)
|
|
2948
|
+
return;
|
|
3371
2949
|
if (this.wizardValue)
|
|
3372
2950
|
this.clampToFrontier();
|
|
3373
2951
|
this.updateCurrentIndex();
|
|
3374
2952
|
this.updateNavigation();
|
|
2953
|
+
this.announceSlide();
|
|
3375
2954
|
}
|
|
3376
2955
|
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
3377
2956
|
// Handles ArrowLeft/ArrowRight for keyboard slide navigation. Skips form
|
|
@@ -3444,6 +3023,11 @@ class Carousel extends Controller {
|
|
|
3444
3023
|
this._autoplayTimer = null;
|
|
3445
3024
|
}
|
|
3446
3025
|
autoplayAdvance() {
|
|
3026
|
+
if (this.fadeValue) {
|
|
3027
|
+
const nextIndex = (this._currentIndex + 1) % this.slides.length;
|
|
3028
|
+
this.activateSlide(nextIndex);
|
|
3029
|
+
return;
|
|
3030
|
+
}
|
|
3447
3031
|
const atEnd = this._currentIndex >= this.slides.length - 1;
|
|
3448
3032
|
if (atEnd) {
|
|
3449
3033
|
const firstSlide = this.slides[0];
|
|
@@ -3455,6 +3039,53 @@ class Carousel extends Controller {
|
|
|
3455
3039
|
get slides() {
|
|
3456
3040
|
return Array.from(this.trackTarget.children);
|
|
3457
3041
|
}
|
|
3042
|
+
// Sets up the fade mode initial state. Marks the first slide active, hides
|
|
3043
|
+
// all others from the accessibility tree, and adds .fade-ready so CSS hands
|
|
3044
|
+
// control over to .is-active.
|
|
3045
|
+
initFade() {
|
|
3046
|
+
this.slides.forEach((slide, i) => {
|
|
3047
|
+
const active = i === 0;
|
|
3048
|
+
slide.classList.toggle("is-active", active);
|
|
3049
|
+
slide.toggleAttribute("inert", !active);
|
|
3050
|
+
slide.setAttribute("aria-hidden", String(!active));
|
|
3051
|
+
});
|
|
3052
|
+
this.element.classList.add("fade-ready");
|
|
3053
|
+
this.syncPagerDots();
|
|
3054
|
+
}
|
|
3055
|
+
// Transitions to the slide at `index` in fade mode by swapping .is-active and
|
|
3056
|
+
// hiding non-active slides from the accessibility tree.
|
|
3057
|
+
activateSlide(index) {
|
|
3058
|
+
this.slides.forEach((slide, i) => {
|
|
3059
|
+
const active = i === index;
|
|
3060
|
+
slide.classList.toggle("is-active", active);
|
|
3061
|
+
slide.toggleAttribute("inert", !active);
|
|
3062
|
+
slide.setAttribute("aria-hidden", String(!active));
|
|
3063
|
+
});
|
|
3064
|
+
this._currentIndex = index;
|
|
3065
|
+
this.updateNavigation();
|
|
3066
|
+
this.syncPagerDots();
|
|
3067
|
+
this.announceSlide();
|
|
3068
|
+
}
|
|
3069
|
+
// Syncs pager dot active state from _currentIndex. Used in fade mode where
|
|
3070
|
+
// IntersectionObserver is not set up (the track doesn't scroll).
|
|
3071
|
+
syncPagerDots() {
|
|
3072
|
+
if (!this.hasDotTarget)
|
|
3073
|
+
return;
|
|
3074
|
+
this.dotTargets.forEach((dot, i) => {
|
|
3075
|
+
dot.classList.toggle("active", i === this._currentIndex);
|
|
3076
|
+
if (i === this._currentIndex) {
|
|
3077
|
+
dot.setAttribute("aria-current", "true");
|
|
3078
|
+
} else {
|
|
3079
|
+
dot.removeAttribute("aria-current");
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
// Updates the sr-only live region so screen readers announce the new slide.
|
|
3084
|
+
announceSlide() {
|
|
3085
|
+
if (!this.hasStatusTarget)
|
|
3086
|
+
return;
|
|
3087
|
+
this.statusTarget.textContent = `Slide ${this._currentIndex + 1} of ${this.slides.length}`;
|
|
3088
|
+
}
|
|
3458
3089
|
// Snaps scroll position back to the frontier if the user somehow scrolled
|
|
3459
3090
|
// past it (e.g. momentum after a partially-blocked gesture).
|
|
3460
3091
|
clampToFrontier() {
|
|
@@ -3507,15 +3138,35 @@ class Carousel extends Controller {
|
|
|
3507
3138
|
this.slides.forEach((slide) => this.observer?.observe(slide));
|
|
3508
3139
|
}
|
|
3509
3140
|
updateNavigation() {
|
|
3141
|
+
if (this.fadeValue) {
|
|
3142
|
+
const atStart2 = this._currentIndex <= 0;
|
|
3143
|
+
const atEnd2 = this._currentIndex >= this.slides.length - 1;
|
|
3144
|
+
if (this.hasPrevTarget) {
|
|
3145
|
+
const hide = atStart2 && !this.loopValue;
|
|
3146
|
+
this.prevTarget.classList.toggle("hide", hide);
|
|
3147
|
+
this.prevTarget.disabled = hide;
|
|
3148
|
+
}
|
|
3149
|
+
if (this.hasNextTarget) {
|
|
3150
|
+
const hide = atEnd2 && !this.loopValue;
|
|
3151
|
+
this.nextTarget.classList.toggle("hide", hide);
|
|
3152
|
+
this.nextTarget.disabled = hide;
|
|
3153
|
+
}
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3510
3156
|
const track = this.trackTarget;
|
|
3511
3157
|
const atStart = track.scrollLeft <= 0;
|
|
3512
3158
|
const atEnd = track.scrollLeft >= track.scrollWidth - track.clientWidth - 1;
|
|
3513
|
-
if (this.hasPrevTarget)
|
|
3514
|
-
|
|
3159
|
+
if (this.hasPrevTarget) {
|
|
3160
|
+
const hide = atStart && !this.loopValue;
|
|
3161
|
+
this.prevTarget.classList.toggle("hide", hide);
|
|
3162
|
+
this.prevTarget.disabled = hide;
|
|
3163
|
+
}
|
|
3515
3164
|
if (this.hasNextTarget) {
|
|
3516
3165
|
const atLastSlide = this._currentIndex >= this.slides.length - 1;
|
|
3517
3166
|
const frontierReached = this.wizardValue && this._currentIndex >= this._maxUnlocked;
|
|
3518
|
-
|
|
3167
|
+
const hide = (atEnd || atLastSlide || frontierReached) && !this.loopValue;
|
|
3168
|
+
this.nextTarget.classList.toggle("hide", hide);
|
|
3169
|
+
this.nextTarget.disabled = hide;
|
|
3519
3170
|
}
|
|
3520
3171
|
if (this.wizardValue && this.hasDotTarget) {
|
|
3521
3172
|
this.dotTargets.forEach((dot, i) => {
|
|
@@ -5105,6 +4756,108 @@ class Notification extends Controller {
|
|
|
5105
4756
|
}
|
|
5106
4757
|
}
|
|
5107
4758
|
|
|
4759
|
+
class HorizontalScroll extends Controller {
|
|
4760
|
+
resizeObserver = null;
|
|
4761
|
+
connect() {
|
|
4762
|
+
this.updateOverflow();
|
|
4763
|
+
this.element.addEventListener("scroll", this.updateOverflow);
|
|
4764
|
+
this.resizeObserver = new ResizeObserver(this.updateOverflow);
|
|
4765
|
+
this.resizeObserver.observe(this.element);
|
|
4766
|
+
}
|
|
4767
|
+
disconnect() {
|
|
4768
|
+
this.element.removeEventListener("scroll", this.updateOverflow);
|
|
4769
|
+
this.resizeObserver?.disconnect();
|
|
4770
|
+
this.resizeObserver = null;
|
|
4771
|
+
}
|
|
4772
|
+
updateOverflow = () => {
|
|
4773
|
+
const el = this.element;
|
|
4774
|
+
el.classList.toggle("can-scroll-left", el.scrollLeft > 0);
|
|
4775
|
+
el.classList.toggle("can-scroll-right", el.scrollLeft < el.scrollWidth - el.clientWidth - 1);
|
|
4776
|
+
};
|
|
4777
|
+
}
|
|
4778
|
+
|
|
4779
|
+
class Table extends Controller {
|
|
4780
|
+
static targets = ["selectAll", "rowCheckbox"];
|
|
4781
|
+
toggleAll() {
|
|
4782
|
+
const checked = this.selectAllTarget.checked;
|
|
4783
|
+
this.rowCheckboxTargets.forEach((cb) => {
|
|
4784
|
+
cb.checked = checked;
|
|
4785
|
+
});
|
|
4786
|
+
}
|
|
4787
|
+
updateSelectAll() {
|
|
4788
|
+
if (!this.hasSelectAllTarget)
|
|
4789
|
+
return;
|
|
4790
|
+
const total = this.rowCheckboxTargets.length;
|
|
4791
|
+
const checkedCount = this.rowCheckboxTargets.filter((cb) => cb.checked).length;
|
|
4792
|
+
if (checkedCount === 0) {
|
|
4793
|
+
this.selectAllTarget.checked = false;
|
|
4794
|
+
this.selectAllTarget.indeterminate = false;
|
|
4795
|
+
} else if (checkedCount === total) {
|
|
4796
|
+
this.selectAllTarget.checked = true;
|
|
4797
|
+
this.selectAllTarget.indeterminate = false;
|
|
4798
|
+
} else {
|
|
4799
|
+
this.selectAllTarget.checked = false;
|
|
4800
|
+
this.selectAllTarget.indeterminate = true;
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4805
|
+
class LoadMore extends Controller {
|
|
4806
|
+
static values = {
|
|
4807
|
+
url: String,
|
|
4808
|
+
tbodyId: String
|
|
4809
|
+
};
|
|
4810
|
+
observer = null;
|
|
4811
|
+
loading = false;
|
|
4812
|
+
connect() {
|
|
4813
|
+
if (!this.urlValue)
|
|
4814
|
+
return;
|
|
4815
|
+
this.observer = new IntersectionObserver(
|
|
4816
|
+
(entries) => {
|
|
4817
|
+
if (entries[0].isIntersecting)
|
|
4818
|
+
this.load();
|
|
4819
|
+
},
|
|
4820
|
+
// Start fetching 300px before the sentinel enters the viewport so rows
|
|
4821
|
+
// appear before the user actually reaches the bottom.
|
|
4822
|
+
{ rootMargin: "0px 0px 300px 0px" }
|
|
4823
|
+
);
|
|
4824
|
+
this.observer.observe(this.element);
|
|
4825
|
+
}
|
|
4826
|
+
disconnect() {
|
|
4827
|
+
this.observer?.disconnect();
|
|
4828
|
+
this.observer = null;
|
|
4829
|
+
}
|
|
4830
|
+
async load() {
|
|
4831
|
+
if (this.loading)
|
|
4832
|
+
return;
|
|
4833
|
+
this.loading = true;
|
|
4834
|
+
this.observer?.disconnect();
|
|
4835
|
+
try {
|
|
4836
|
+
const response = await fetch(this.urlValue, {
|
|
4837
|
+
headers: {
|
|
4838
|
+
Accept: "text/html",
|
|
4839
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
4840
|
+
},
|
|
4841
|
+
credentials: "same-origin"
|
|
4842
|
+
});
|
|
4843
|
+
if (!response.ok)
|
|
4844
|
+
return;
|
|
4845
|
+
const html = await response.text();
|
|
4846
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
4847
|
+
const tbody = document.getElementById(this.tbodyIdValue);
|
|
4848
|
+
const newRows = Array.from(
|
|
4849
|
+
doc.querySelectorAll(".midwest-table-body tr")
|
|
4850
|
+
);
|
|
4851
|
+
if (!tbody || newRows.length === 0)
|
|
4852
|
+
return;
|
|
4853
|
+
this.element.remove();
|
|
4854
|
+
newRows.forEach((row) => tbody.appendChild(document.importNode(row, true)));
|
|
4855
|
+
} catch {
|
|
4856
|
+
this.loading = false;
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
|
|
5108
4861
|
function registerMidwestControllers(application) {
|
|
5109
4862
|
application.register("midwest-card", Card);
|
|
5110
4863
|
application.register("midwest-banner", Banner);
|
|
@@ -5129,6 +4882,9 @@ function registerMidwestControllers(application) {
|
|
|
5129
4882
|
application.register("midwest-image", Image);
|
|
5130
4883
|
application.register("midwest-color-picker", ColorPicker);
|
|
5131
4884
|
application.register("midwest-notification", Notification);
|
|
4885
|
+
application.register("midwest-horizontal-scroll", HorizontalScroll);
|
|
4886
|
+
application.register("midwest-table", Table);
|
|
4887
|
+
application.register("midwest-load-more", LoadMore);
|
|
5132
4888
|
}
|
|
5133
4889
|
|
|
5134
4890
|
export { Banner, Card, Chart, CountdownTimer, registerMidwestControllers };
|