@haiilo/catalyst 6.3.0 → 6.3.2

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 (60) hide show
  1. package/dist/catalyst/catalyst.esm.js +1 -1
  2. package/dist/catalyst/catalyst.esm.js.map +1 -1
  3. package/dist/catalyst/p-2257ac13.entry.js +10 -0
  4. package/dist/catalyst/p-2257ac13.entry.js.map +1 -0
  5. package/dist/catalyst/scss/fonts/_fonts.mixins.lato.scss +36 -18
  6. package/dist/catalyst/scss/utils/_color.scss +3 -1
  7. package/dist/catalyst/scss/utils/_typography.mixins.scss +10 -2
  8. package/dist/catalyst/scss/vendor/_flatpickr.scss +5 -2
  9. package/dist/cjs/cat-alert_26.cjs.entry.js +539 -261
  10. package/dist/cjs/cat-alert_26.cjs.entry.js.map +1 -1
  11. package/dist/cjs/catalyst.cjs.js +1 -1
  12. package/dist/cjs/loader.cjs.js +1 -1
  13. package/dist/collection/components/cat-button/cat-button.css +0 -1
  14. package/dist/collection/components/cat-datepicker/cat-datepicker.config.js +6 -0
  15. package/dist/collection/components/cat-datepicker/cat-datepicker.config.js.map +1 -1
  16. package/dist/collection/components/cat-datepicker/cat-datepicker.js +42 -9
  17. package/dist/collection/components/cat-datepicker/cat-datepicker.js.map +1 -1
  18. package/dist/collection/components/cat-datepicker-inline/cat-datepicker-inline.js +32 -11
  19. package/dist/collection/components/cat-datepicker-inline/cat-datepicker-inline.js.map +1 -1
  20. package/dist/collection/components/cat-dropdown/cat-dropdown.js +10 -5
  21. package/dist/collection/components/cat-dropdown/cat-dropdown.js.map +1 -1
  22. package/dist/collection/components/cat-select/cat-select.js +22 -11
  23. package/dist/collection/components/cat-select/cat-select.js.map +1 -1
  24. package/dist/collection/components/cat-tabs/cat-tabs.css +7 -1
  25. package/dist/collection/components/cat-tooltip/cat-tooltip.js +1 -1
  26. package/dist/collection/scss/fonts/_fonts.mixins.lato.scss +36 -18
  27. package/dist/collection/scss/utils/_color.scss +3 -1
  28. package/dist/collection/scss/utils/_typography.mixins.scss +10 -2
  29. package/dist/collection/scss/vendor/_flatpickr.scss +5 -2
  30. package/dist/components/cat-button2.js +1 -1
  31. package/dist/components/cat-button2.js.map +1 -1
  32. package/dist/components/cat-checkbox2.js.map +1 -1
  33. package/dist/components/cat-datepicker-inline.js +18 -13
  34. package/dist/components/cat-datepicker-inline.js.map +1 -1
  35. package/dist/components/cat-datepicker.js +28 -9
  36. package/dist/components/cat-datepicker.js.map +1 -1
  37. package/dist/components/cat-datepicker.locale.js +6 -0
  38. package/dist/components/cat-datepicker.locale.js.map +1 -1
  39. package/dist/components/cat-dropdown2.js +252 -99
  40. package/dist/components/cat-dropdown2.js.map +1 -1
  41. package/dist/components/cat-input2.js.map +1 -1
  42. package/dist/components/cat-select2.js +21 -10
  43. package/dist/components/cat-select2.js.map +1 -1
  44. package/dist/components/cat-tabs.js +1 -1
  45. package/dist/components/cat-tabs.js.map +1 -1
  46. package/dist/components/cat-textarea.js.map +1 -1
  47. package/dist/components/cat-tooltip.js.map +1 -1
  48. package/dist/components/floating-ui.dom.esm.js +215 -129
  49. package/dist/components/floating-ui.dom.esm.js.map +1 -1
  50. package/dist/esm/cat-alert_26.entry.js +539 -261
  51. package/dist/esm/cat-alert_26.entry.js.map +1 -1
  52. package/dist/esm/catalyst.js +1 -1
  53. package/dist/esm/loader.js +1 -1
  54. package/dist/types/components/cat-datepicker/cat-datepicker.config.d.ts +3 -0
  55. package/dist/types/components/cat-datepicker/cat-datepicker.d.ts +8 -2
  56. package/dist/types/components/cat-datepicker-inline/cat-datepicker-inline.d.ts +7 -1
  57. package/dist/types/components.d.ts +16 -0
  58. package/package.json +11 -11
  59. package/dist/catalyst/p-90e9d18f.entry.js +0 -10
  60. package/dist/catalyst/p-90e9d18f.entry.js.map +0 -1
@@ -576,7 +576,7 @@ var isFocusable = function isFocusable(node, options) {
576
576
  };
577
577
 
578
578
  /*!
579
- * focus-trap 7.4.3
579
+ * focus-trap 7.5.2
580
580
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
581
581
  */
582
582
 
@@ -661,10 +661,10 @@ var isSelectableInput = function isSelectableInput(node) {
661
661
  return node.tagName && node.tagName.toLowerCase() === 'input' && typeof node.select === 'function';
662
662
  };
663
663
  var isEscapeEvent = function isEscapeEvent(e) {
664
- return e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27;
664
+ return (e === null || e === void 0 ? void 0 : e.key) === 'Escape' || (e === null || e === void 0 ? void 0 : e.key) === 'Esc' || (e === null || e === void 0 ? void 0 : e.keyCode) === 27;
665
665
  };
666
666
  var isTabEvent = function isTabEvent(e) {
667
- return e.key === 'Tab' || e.keyCode === 9;
667
+ return (e === null || e === void 0 ? void 0 : e.key) === 'Tab' || (e === null || e === void 0 ? void 0 : e.keyCode) === 9;
668
668
  };
669
669
 
670
670
  // checks for TAB by default
@@ -748,8 +748,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
748
748
  // container: HTMLElement,
749
749
  // tabbableNodes: Array<HTMLElement>, // empty if none
750
750
  // focusableNodes: Array<HTMLElement>, // empty if none
751
- // firstTabbableNode: HTMLElement|null,
752
- // lastTabbableNode: HTMLElement|null,
751
+ // posTabIndexesFound: boolean,
752
+ // firstTabbableNode: HTMLElement|undefined,
753
+ // lastTabbableNode: HTMLElement|undefined,
754
+ // firstDomTabbableNode: HTMLElement|undefined,
755
+ // lastDomTabbableNode: HTMLElement|undefined,
753
756
  // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
754
757
  // }>}
755
758
  containerGroups: [],
@@ -766,7 +769,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
766
769
  paused: false,
767
770
  // timer ID for when delayInitialFocus is true and initial focus in this trap
768
771
  // has been delayed during activation
769
- delayInitialFocusTimer: undefined
772
+ delayInitialFocusTimer: undefined,
773
+ // the most recent KeyboardEvent for the configured nav key (typically [SHIFT+]TAB), if any
774
+ recentNavEvent: undefined
770
775
  };
771
776
  var trap; // eslint-disable-line prefer-const -- some private functions reference it, and its methods reference private functions, so we must declare here and define later
772
777
 
@@ -785,7 +790,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
785
790
  /**
786
791
  * Finds the index of the container that contains the element.
787
792
  * @param {HTMLElement} element
788
- * @param {Event} [event]
793
+ * @param {Event} [event] If available, and `element` isn't directly found in any container,
794
+ * the event's composed path is used to see if includes any known trap containers in the
795
+ * case where the element is inside a Shadow DOM.
789
796
  * @returns {number} Index of the container in either `state.containers` or
790
797
  * `state.containerGroups` (the order/length of these lists are the same); -1
791
798
  * if the element isn't found.
@@ -880,14 +887,41 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
880
887
  var tabbableNodes = tabbable(container, config.tabbableOptions);
881
888
 
882
889
  // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes
883
- // are a superset of tabbable nodes
890
+ // are a superset of tabbable nodes since nodes with negative `tabindex` attributes
891
+ // are focusable but not tabbable
884
892
  var focusableNodes = focusable(container, config.tabbableOptions);
893
+ var firstTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[0] : undefined;
894
+ var lastTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : undefined;
895
+ var firstDomTabbableNode = focusableNodes.find(function (node) {
896
+ return isTabbable(node);
897
+ });
898
+ var lastDomTabbableNode = focusableNodes.slice().reverse().find(function (node) {
899
+ return isTabbable(node);
900
+ });
901
+ var posTabIndexesFound = !!tabbableNodes.find(function (node) {
902
+ return getTabIndex(node) > 0;
903
+ });
885
904
  return {
886
905
  container: container,
887
906
  tabbableNodes: tabbableNodes,
888
907
  focusableNodes: focusableNodes,
889
- firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null,
890
- lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null,
908
+ /** True if at least one node with positive `tabindex` was found in this container. */
909
+ posTabIndexesFound: posTabIndexesFound,
910
+ /** First tabbable node in container, __tabindex__ order; `undefined` if none. */
911
+ firstTabbableNode: firstTabbableNode,
912
+ /** Last tabbable node in container, __tabindex__ order; `undefined` if none. */
913
+ lastTabbableNode: lastTabbableNode,
914
+ // NOTE: DOM order is NOT NECESSARILY "document position" order, but figuring that out
915
+ // would require more than just https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
916
+ // because that API doesn't work with Shadow DOM as well as it should (@see
917
+ // https://github.com/whatwg/dom/issues/320) and since this first/last is only needed, so far,
918
+ // to address an edge case related to positive tabindex support, this seems like a much easier,
919
+ // "close enough most of the time" alternative for positive tabindexes which should generally
920
+ // be avoided anyway...
921
+ /** First tabbable node in container, __DOM__ order; `undefined` if none. */
922
+ firstDomTabbableNode: firstDomTabbableNode,
923
+ /** Last tabbable node in container, __DOM__ order; `undefined` if none. */
924
+ lastDomTabbableNode: lastDomTabbableNode,
891
925
  /**
892
926
  * Finds the __tabbable__ node that follows the given node in the specified direction,
893
927
  * in this container, if any.
@@ -898,30 +932,24 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
898
932
  */
899
933
  nextTabbableNode: function nextTabbableNode(node) {
900
934
  var forward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
901
- // NOTE: If tabindex is positive (in order to manipulate the tab order separate
902
- // from the DOM order), this __will not work__ because the list of focusableNodes,
903
- // while it contains tabbable nodes, does not sort its nodes in any order other
904
- // than DOM order, because it can't: Where would you place focusable (but not
905
- // tabbable) nodes in that order? They have no order, because they aren't tabbale...
906
- // Support for positive tabindex is already broken and hard to manage (possibly
907
- // not supportable, TBD), so this isn't going to make things worse than they
908
- // already are, and at least makes things better for the majority of cases where
909
- // tabindex is either 0/unset or negative.
910
- // FYI, positive tabindex issue: https://github.com/focus-trap/focus-trap/issues/375
911
- var nodeIdx = focusableNodes.findIndex(function (n) {
912
- return n === node;
913
- });
935
+ var nodeIdx = tabbableNodes.indexOf(node);
914
936
  if (nodeIdx < 0) {
915
- return undefined;
916
- }
917
- if (forward) {
918
- return focusableNodes.slice(nodeIdx + 1).find(function (n) {
919
- return isTabbable(n, config.tabbableOptions);
937
+ // either not tabbable nor focusable, or was focused but not tabbable (negative tabindex):
938
+ // since `node` should at least have been focusable, we assume that's the case and mimic
939
+ // what browsers do, which is set focus to the next node in __document position order__,
940
+ // regardless of positive tabindexes, if any -- and for reasons explained in the NOTE
941
+ // above related to `firstDomTabbable` and `lastDomTabbable` properties, we fall back to
942
+ // basic DOM order
943
+ if (forward) {
944
+ return focusableNodes.slice(focusableNodes.indexOf(node) + 1).find(function (el) {
945
+ return isTabbable(el);
946
+ });
947
+ }
948
+ return focusableNodes.slice(0, focusableNodes.indexOf(node)).reverse().find(function (el) {
949
+ return isTabbable(el);
920
950
  });
921
951
  }
922
- return focusableNodes.slice(0, nodeIdx).reverse().find(function (n) {
923
- return isTabbable(n, config.tabbableOptions);
924
- });
952
+ return tabbableNodes[nodeIdx + (forward ? 1 : -1)];
925
953
  }
926
954
  };
927
955
  });
@@ -934,6 +962,19 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
934
962
  ) {
935
963
  throw new Error('Your focus-trap must have at least one container with at least one tabbable node in it at all times');
936
964
  }
965
+
966
+ // NOTE: Positive tabindexes are only properly supported in single-container traps because
967
+ // doing it across multiple containers where tabindexes could be all over the place
968
+ // would require Tabbable to support multiple containers, would require additional
969
+ // specialized Shadow DOM support, and would require Tabbable's multi-container support
970
+ // to look at those containers in document position order rather than user-provided
971
+ // order (as they are treated in Focus-trap, for legacy reasons). See discussion on
972
+ // https://github.com/focus-trap/focus-trap/issues/375 for more details.
973
+ if (state.containerGroups.find(function (g) {
974
+ return g.posTabIndexesFound;
975
+ }) && state.containerGroups.length > 1) {
976
+ throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.");
977
+ }
937
978
  };
938
979
  var tryFocus = function tryFocus(node) {
939
980
  if (node === false) {
@@ -949,6 +990,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
949
990
  node.focus({
950
991
  preventScroll: !!config.preventScroll
951
992
  });
993
+ // NOTE: focus() API does not trigger focusIn event so set MRU node manually
952
994
  state.mostRecentlyFocusedNode = node;
953
995
  if (isSelectableInput(node)) {
954
996
  node.select();
@@ -959,64 +1001,23 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
959
1001
  return node ? node : node === false ? false : previousActiveElement;
960
1002
  };
961
1003
 
962
- // This needs to be done on mousedown and touchstart instead of click
963
- // so that it precedes the focus event.
964
- var checkPointerDown = function checkPointerDown(e) {
965
- var target = getActualTarget(e);
966
- if (findContainerIndex(target, e) >= 0) {
967
- // allow the click since it ocurred inside the trap
968
- return;
969
- }
970
- if (valueOrHandler(config.clickOutsideDeactivates, e)) {
971
- // immediately deactivate the trap
972
- trap.deactivate({
973
- // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
974
- // which will result in the outside click setting focus to the node
975
- // that was clicked (and if not focusable, to "nothing"); by setting
976
- // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
977
- // on activation (or the configured `setReturnFocus` node), whether the
978
- // outside click was on a focusable node or not
979
- returnFocus: config.returnFocusOnDeactivate
980
- });
981
- return;
982
- }
983
-
984
- // This is needed for mobile devices.
985
- // (If we'll only let `click` events through,
986
- // then on mobile they will be blocked anyways if `touchstart` is blocked.)
987
- if (valueOrHandler(config.allowOutsideClick, e)) {
988
- // allow the click outside the trap to take place
989
- return;
990
- }
991
-
992
- // otherwise, prevent the click
993
- e.preventDefault();
994
- };
995
-
996
- // In case focus escapes the trap for some strange reason, pull it back in.
997
- var checkFocusIn = function checkFocusIn(e) {
998
- var target = getActualTarget(e);
999
- var targetContained = findContainerIndex(target, e) >= 0;
1000
-
1001
- // In Firefox when you Tab out of an iframe the Document is briefly focused.
1002
- if (targetContained || target instanceof Document) {
1003
- if (targetContained) {
1004
- state.mostRecentlyFocusedNode = target;
1005
- }
1006
- } else {
1007
- // escaped! pull it back in to where it just left
1008
- e.stopImmediatePropagation();
1009
- tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
1010
- }
1011
- };
1012
-
1013
- // Hijack key nav events on the first and last focusable nodes of the trap,
1014
- // in order to prevent focus from escaping. If it escapes for even a
1015
- // moment it can end up scrolling the page and causing confusion so we
1016
- // kind of need to capture the action at the keydown phase.
1017
- var checkKeyNav = function checkKeyNav(event) {
1018
- var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1019
- var target = getActualTarget(event);
1004
+ /**
1005
+ * Finds the next node (in either direction) where focus should move according to a
1006
+ * keyboard focus-in event.
1007
+ * @param {Object} params
1008
+ * @param {Node} [params.target] Known target __from which__ to navigate, if any.
1009
+ * @param {KeyboardEvent|FocusEvent} [params.event] Event to use if `target` isn't known (event
1010
+ * will be used to determine the `target`). Ignored if `target` is specified.
1011
+ * @param {boolean} [params.isBackward] True if focus should move backward.
1012
+ * @returns {Node|undefined} The next node, or `undefined` if a next node couldn't be
1013
+ * determined given the current state of the trap.
1014
+ */
1015
+ var findNextNavNode = function findNextNavNode(_ref2) {
1016
+ var target = _ref2.target,
1017
+ event = _ref2.event,
1018
+ _ref2$isBackward = _ref2.isBackward,
1019
+ isBackward = _ref2$isBackward === void 0 ? false : _ref2$isBackward;
1020
+ target = target || getActualTarget(event);
1020
1021
  updateTabbableNodes();
1021
1022
  var destinationNode = null;
1022
1023
  if (state.tabbableGroups.length > 0) {
@@ -1039,8 +1040,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1039
1040
  // REVERSE
1040
1041
 
1041
1042
  // is the target the first tabbable node in a group?
1042
- var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref2) {
1043
- var firstTabbableNode = _ref2.firstTabbableNode;
1043
+ var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
1044
+ var firstTabbableNode = _ref3.firstTabbableNode;
1044
1045
  return target === firstTabbableNode;
1045
1046
  });
1046
1047
  if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) {
@@ -1058,7 +1059,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1058
1059
  // the LAST group if it's the first tabbable node of the FIRST group)
1059
1060
  var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1;
1060
1061
  var destinationGroup = state.tabbableGroups[destinationGroupIndex];
1061
- destinationNode = destinationGroup.lastTabbableNode;
1062
+ destinationNode = getTabIndex(target) >= 0 ? destinationGroup.lastTabbableNode : destinationGroup.lastDomTabbableNode;
1062
1063
  } else if (!isTabEvent(event)) {
1063
1064
  // user must have customized the nav keys so we have to move focus manually _within_
1064
1065
  // the active group: do this based on the order determined by tabbable()
@@ -1068,8 +1069,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1068
1069
  // FORWARD
1069
1070
 
1070
1071
  // is the target the last tabbable node in a group?
1071
- var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
1072
- var lastTabbableNode = _ref3.lastTabbableNode;
1072
+ var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref4) {
1073
+ var lastTabbableNode = _ref4.lastTabbableNode;
1073
1074
  return target === lastTabbableNode;
1074
1075
  });
1075
1076
  if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) {
@@ -1087,7 +1088,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1087
1088
  // group if it's the last tabbable node of the LAST group)
1088
1089
  var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1;
1089
1090
  var _destinationGroup = state.tabbableGroups[_destinationGroupIndex];
1090
- destinationNode = _destinationGroup.firstTabbableNode;
1091
+ destinationNode = getTabIndex(target) >= 0 ? _destinationGroup.firstTabbableNode : _destinationGroup.firstDomTabbableNode;
1091
1092
  } else if (!isTabEvent(event)) {
1092
1093
  // user must have customized the nav keys so we have to move focus manually _within_
1093
1094
  // the active group: do this based on the order determined by tabbable()
@@ -1099,6 +1100,153 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
1099
1100
  // NOTE: the fallbackFocus option does not support returning false to opt-out
1100
1101
  destinationNode = getNodeForOption('fallbackFocus');
1101
1102
  }
1103
+ return destinationNode;
1104
+ };
1105
+
1106
+ // This needs to be done on mousedown and touchstart instead of click
1107
+ // so that it precedes the focus event.
1108
+ var checkPointerDown = function checkPointerDown(e) {
1109
+ var target = getActualTarget(e);
1110
+ if (findContainerIndex(target, e) >= 0) {
1111
+ // allow the click since it ocurred inside the trap
1112
+ return;
1113
+ }
1114
+ if (valueOrHandler(config.clickOutsideDeactivates, e)) {
1115
+ // immediately deactivate the trap
1116
+ trap.deactivate({
1117
+ // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
1118
+ // which will result in the outside click setting focus to the node
1119
+ // that was clicked (and if not focusable, to "nothing"); by setting
1120
+ // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
1121
+ // on activation (or the configured `setReturnFocus` node), whether the
1122
+ // outside click was on a focusable node or not
1123
+ returnFocus: config.returnFocusOnDeactivate
1124
+ });
1125
+ return;
1126
+ }
1127
+
1128
+ // This is needed for mobile devices.
1129
+ // (If we'll only let `click` events through,
1130
+ // then on mobile they will be blocked anyways if `touchstart` is blocked.)
1131
+ if (valueOrHandler(config.allowOutsideClick, e)) {
1132
+ // allow the click outside the trap to take place
1133
+ return;
1134
+ }
1135
+
1136
+ // otherwise, prevent the click
1137
+ e.preventDefault();
1138
+ };
1139
+
1140
+ // In case focus escapes the trap for some strange reason, pull it back in.
1141
+ // NOTE: the focusIn event is NOT cancelable, so if focus escapes, it may cause unexpected
1142
+ // scrolling if the node that got focused was out of view; there's nothing we can do to
1143
+ // prevent that from happening by the time we discover that focus escaped
1144
+ var checkFocusIn = function checkFocusIn(event) {
1145
+ var target = getActualTarget(event);
1146
+ var targetContained = findContainerIndex(target, event) >= 0;
1147
+
1148
+ // In Firefox when you Tab out of an iframe the Document is briefly focused.
1149
+ if (targetContained || target instanceof Document) {
1150
+ if (targetContained) {
1151
+ state.mostRecentlyFocusedNode = target;
1152
+ }
1153
+ } else {
1154
+ // escaped! pull it back in to where it just left
1155
+ event.stopImmediatePropagation();
1156
+
1157
+ // focus will escape if the MRU node had a positive tab index and user tried to nav forward;
1158
+ // it will also escape if the MRU node had a 0 tab index and user tried to nav backward
1159
+ // toward a node with a positive tab index
1160
+ var nextNode; // next node to focus, if we find one
1161
+ var navAcrossContainers = true;
1162
+ if (state.mostRecentlyFocusedNode) {
1163
+ if (getTabIndex(state.mostRecentlyFocusedNode) > 0) {
1164
+ // MRU container index must be >=0 otherwise we wouldn't have it as an MRU node...
1165
+ var mruContainerIdx = findContainerIndex(state.mostRecentlyFocusedNode);
1166
+ // there MAY not be any tabbable nodes in the container if there are at least 2 containers
1167
+ // and the MRU node is focusable but not tabbable (focus-trap requires at least 1 container
1168
+ // with at least one tabbable node in order to function, so this could be the other container
1169
+ // with nothing tabbable in it)
1170
+ var tabbableNodes = state.containerGroups[mruContainerIdx].tabbableNodes;
1171
+ if (tabbableNodes.length > 0) {
1172
+ // MRU tab index MAY not be found if the MRU node is focusable but not tabbable
1173
+ var mruTabIdx = tabbableNodes.findIndex(function (node) {
1174
+ return node === state.mostRecentlyFocusedNode;
1175
+ });
1176
+ if (mruTabIdx >= 0) {
1177
+ if (config.isKeyForward(state.recentNavEvent)) {
1178
+ if (mruTabIdx + 1 < tabbableNodes.length) {
1179
+ nextNode = tabbableNodes[mruTabIdx + 1];
1180
+ navAcrossContainers = false;
1181
+ }
1182
+ // else, don't wrap within the container as focus should move to next/previous
1183
+ // container
1184
+ } else {
1185
+ if (mruTabIdx - 1 >= 0) {
1186
+ nextNode = tabbableNodes[mruTabIdx - 1];
1187
+ navAcrossContainers = false;
1188
+ }
1189
+ // else, don't wrap within the container as focus should move to next/previous
1190
+ // container
1191
+ }
1192
+ // else, don't find in container order without considering direction too
1193
+ }
1194
+ }
1195
+ // else, no tabbable nodes in that container (which means we must have at least one other
1196
+ // container with at least one tabbable node in it, otherwise focus-trap would've thrown
1197
+ // an error the last time updateTabbableNodes() was run): find next node among all known
1198
+ // containers
1199
+ } else {
1200
+ // check to see if there's at least one tabbable node with a positive tab index inside
1201
+ // the trap because focus seems to escape when navigating backward from a tabbable node
1202
+ // with tabindex=0 when this is the case (instead of wrapping to the tabbable node with
1203
+ // the greatest positive tab index like it should)
1204
+ if (!state.containerGroups.some(function (g) {
1205
+ return g.tabbableNodes.some(function (n) {
1206
+ return getTabIndex(n) > 0;
1207
+ });
1208
+ })) {
1209
+ // no containers with tabbable nodes with positive tab indexes which means the focus
1210
+ // escaped for some other reason and we should just execute the fallback to the
1211
+ // MRU node or initial focus node, if any
1212
+ navAcrossContainers = false;
1213
+ }
1214
+ }
1215
+ } else {
1216
+ // no MRU node means we're likely in some initial condition when the trap has just
1217
+ // been activated and initial focus hasn't been given yet, in which case we should
1218
+ // fall through to trying to focus the initial focus node, which is what should
1219
+ // happen below at this point in the logic
1220
+ navAcrossContainers = false;
1221
+ }
1222
+ if (navAcrossContainers) {
1223
+ nextNode = findNextNavNode({
1224
+ // move FROM the MRU node, not event-related node (which will be the node that is
1225
+ // outside the trap causing the focus escape we're trying to fix)
1226
+ target: state.mostRecentlyFocusedNode,
1227
+ isBackward: config.isKeyBackward(state.recentNavEvent)
1228
+ });
1229
+ }
1230
+ if (nextNode) {
1231
+ tryFocus(nextNode);
1232
+ } else {
1233
+ tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
1234
+ }
1235
+ }
1236
+ state.recentNavEvent = undefined; // clear
1237
+ };
1238
+
1239
+ // Hijack key nav events on the first and last focusable nodes of the trap,
1240
+ // in order to prevent focus from escaping. If it escapes for even a
1241
+ // moment it can end up scrolling the page and causing confusion so we
1242
+ // kind of need to capture the action at the keydown phase.
1243
+ var checkKeyNav = function checkKeyNav(event) {
1244
+ var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1245
+ state.recentNavEvent = event;
1246
+ var destinationNode = findNextNavNode({
1247
+ event: event,
1248
+ isBackward: isBackward
1249
+ });
1102
1250
  if (destinationNode) {
1103
1251
  if (isTabEvent(event)) {
1104
1252
  // since tab natively moves focus, we wouldn't have a destination node unless we
@@ -1371,9 +1519,11 @@ const CatDropdown = /*@__PURE__*/ proxyCustomElement(class CatDropdown extends H
1371
1519
  this.initTrigger();
1372
1520
  this.toggle();
1373
1521
  }
1374
- const button = event.target;
1375
- // hide dropdown on button click
1376
- if (!this.noAutoClose && event.composedPath().includes(this.content) && button.slot !== 'trigger') {
1522
+ // hide dropdown on button clicks inside the dropdown content
1523
+ if (!this.noAutoClose &&
1524
+ event.composedPath().includes(this.content) &&
1525
+ event.target instanceof Element &&
1526
+ event.target.slot !== 'trigger') {
1377
1527
  this.close();
1378
1528
  }
1379
1529
  }
@@ -1408,6 +1558,9 @@ const CatDropdown = /*@__PURE__*/ proxyCustomElement(class CatDropdown extends H
1408
1558
  clickOutsideDeactivates: event => {
1409
1559
  const shouldClose = !this.noAutoClose &&
1410
1560
  !event.composedPath().includes(this.content) &&
1561
+ !event
1562
+ .composedPath()
1563
+ .find(el => el instanceof HTMLElement && el.hasAttribute('data-dropdown-no-close')) &&
1411
1564
  (!this.trigger || !event.composedPath().includes(this.trigger));
1412
1565
  if (shouldClose) {
1413
1566
  this.close();
@@ -1423,7 +1576,7 @@ const CatDropdown = /*@__PURE__*/ proxyCustomElement(class CatDropdown extends H
1423
1576
  * Closes the dropdown.
1424
1577
  */
1425
1578
  async close() {
1426
- if (this.isOpen === null || !this.isOpen) {
1579
+ if (this.isOpen === null) {
1427
1580
  return; // busy
1428
1581
  }
1429
1582
  this.isOpen = null;