@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
@@ -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.setupObserver();
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
- this.prevTarget.classList.toggle("hide", atStart && !this.loopValue);
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
- this.nextTarget.classList.toggle("hide", (atEnd || atLastSlide || frontierReached) && !this.loopValue);
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 };