carbon-react 144.9.9 → 144.9.11

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.
@@ -36,8 +36,6 @@ export const MultiActionButton = ({
36
36
  } = useChildButtons(buttonRef);
37
37
  const handleInsideClick = useClickAwayListener(hideButtons);
38
38
  const handleClick = ev => {
39
- // ensure button is focused when clicked (Safari)
40
- buttonRef.current?.focus();
41
39
  showButtons();
42
40
  handleInsideClick();
43
41
  if (onClick) {
@@ -56,6 +54,7 @@ export const MultiActionButton = ({
56
54
  ...filterOutStyledSystemSpacingProps(rest)
57
55
  };
58
56
  const renderAdditionalButtons = () => /*#__PURE__*/React.createElement(Popover, {
57
+ disablePortal: true,
59
58
  placement: position === "left" ? "bottom-start" : /* istanbul ignore next */"bottom-end",
60
59
  reference: buttonNode,
61
60
  middleware: [offset(6), flip({
@@ -68,8 +68,6 @@ export const SplitButton = ({
68
68
  ...filterOutStyledSystemSpacingProps(rest)
69
69
  };
70
70
  const handleToggleClick = () => {
71
- // ensure button is focused when clicked (Safari)
72
- toggleButton.current?.focus();
73
71
  showButtons();
74
72
  };
75
73
  const toggleButtonProps = {
@@ -119,6 +117,7 @@ export const SplitButton = ({
119
117
  function renderAdditionalButtons() {
120
118
  if (!showAdditionalButtons) return null;
121
119
  return /*#__PURE__*/React.createElement(Popover, {
120
+ disablePortal: true,
122
121
  placement: position === "left" ? /* istanbul ignore next */"bottom-start" : "bottom-end",
123
122
  reference: buttonNode,
124
123
  middleware: [offset(6), flip({
@@ -7,7 +7,7 @@ const StyledSplitButton = styled.div`
7
7
  display: inline-block;
8
8
  position: relative;
9
9
 
10
- ${StyledButton}:first-of-type {
10
+ & > ${StyledButton}:first-of-type {
11
11
  border-top-right-radius: var(--borderRadius000);
12
12
  border-bottom-right-radius: var(--borderRadius000);
13
13
  }
@@ -39,7 +39,7 @@ export const StyledHintText = styled.div`
39
39
  ${({
40
40
  isDarkBackground
41
41
  }) => css`
42
- color: ${isDarkBackground ? "var(--colorsUtilityYang065)" : "var(--colorsUtilityYin055)"};
42
+ color: ${isDarkBackground ? "var(--colorsUtilityYang080)" : "var(--colorsUtilityYin055)"};
43
43
  `}
44
44
  `;
45
45
  const StyledSwitch = styled.div`
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useCallback } from "react";
1
+ import { useState, useRef, useCallback, useEffect } from "react";
2
2
  import Events from "../../../__internal__/utils/helpers/events";
3
3
  import useMenuKeyboardNavigation from "../useMenuKeyboardNavigation";
4
4
  const useChildButtons = (toggleButtonRef, widthRatio = 1) => {
@@ -18,16 +18,18 @@ const useChildButtons = (toggleButtonRef, widthRatio = 1) => {
18
18
  }
19
19
  }
20
20
  const getButtonChildren = useCallback(() => childrenContainer.current?.querySelectorAll('[data-component="button"]'), []);
21
+
22
+ // focus first child button when opened
23
+ useEffect(() => {
24
+ if (showAdditionalButtons) {
25
+ getButtonChildren()?.[0]?.focus();
26
+ }
27
+ }, [showAdditionalButtons, getButtonChildren]);
21
28
  const handleToggleButtonKeyDown = ev => {
22
- const isToggleKey = Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev) || Events.isUpKey(ev) || showAdditionalButtons && Events.isTabKey(ev);
29
+ const isToggleKey = Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev) || Events.isUpKey(ev);
23
30
  if (isToggleKey) {
24
31
  ev.preventDefault();
25
- if (!showAdditionalButtons) {
26
- showButtons();
27
- }
28
- setTimeout(() => {
29
- getButtonChildren()?.[0]?.focus();
30
- });
32
+ showButtons();
31
33
  }
32
34
  };
33
35
  const handleKeyDown = useMenuKeyboardNavigation(toggleButtonRef, getButtonChildren, hideButtons, showAdditionalButtons);
@@ -1,6 +1,5 @@
1
- import { useCallback } from "react";
1
+ import { useCallback, useEffect } from "react";
2
2
  import Events from "../../../__internal__/utils/helpers/events";
3
- import { defaultFocusableSelectors } from "../../../__internal__/focus-trap/focus-trap-utils";
4
3
  import useModalManager from "../useModalManager";
5
4
  export default (mainControlRef, getButtonChildren, hide, isOpen) => {
6
5
  const refocusMainControl = useCallback(() => {
@@ -22,7 +21,7 @@ export default (mainControlRef, getButtonChildren, hide, isOpen) => {
22
21
  modalRef: mainControlRef
23
22
  });
24
23
  const handleKeyDown = useCallback(ev => {
25
- if (!(Events.isEnterKey(ev) || Events.isSpaceKey(ev))) {
24
+ if (!(Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isTabKey(ev))) {
26
25
  ev.preventDefault();
27
26
  }
28
27
  const buttonChildren = getButtonChildren();
@@ -42,28 +41,29 @@ export default (mainControlRef, getButtonChildren, hide, isOpen) => {
42
41
  if (!arrowModifierPressed && Events.isDownKey(ev) && currentIndex < childrenLength - 1) {
43
42
  nextIndex = currentIndex + 1;
44
43
  }
45
- const tabPressed = Events.isTabKey(ev);
46
- const tabShiftPressed = tabPressed && Events.isShiftKey(ev);
47
- if (tabShiftPressed) {
48
- if (currentIndex === 0) {
49
- refocusMainControl();
50
- } else {
51
- nextIndex = currentIndex - 1;
52
- }
53
- } else if (tabPressed) {
54
- if (currentIndex === childrenLength - 1) {
55
- const elements = Array.from(document.querySelectorAll(defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
56
- const indexOf = elements.indexOf(mainControlRef.current);
57
- elements[indexOf + 1]?.focus();
58
- // timeout enforces that the "hide" method will be run after browser focuses on the next element
59
- setTimeout(hide, 0);
60
- } else {
61
- nextIndex = currentIndex + 1;
62
- }
63
- }
64
44
  if (nextIndex > -1) {
65
45
  buttonChildren?.[nextIndex]?.focus();
66
46
  }
67
- }, [hide, refocusMainControl, mainControlRef, getButtonChildren]);
47
+ }, [getButtonChildren]);
48
+
49
+ // check if a child button is focused, if not hide the menu
50
+ const checkFocus = useCallback(() => {
51
+ const buttonChildren = getButtonChildren();
52
+ if (!buttonChildren) {
53
+ return;
54
+ }
55
+ const buttonChildrenFocused = Array.from(buttonChildren).some(button => button === document.activeElement);
56
+ if (!buttonChildrenFocused) {
57
+ hide();
58
+ }
59
+ }, [getButtonChildren, hide]);
60
+ useEffect(() => {
61
+ document.addEventListener("focusin", checkFocus);
62
+ window.addEventListener("blur", hide);
63
+ return () => {
64
+ document.removeEventListener("focusin", checkFocus);
65
+ window.removeEventListener("blur", hide);
66
+ };
67
+ }, [checkFocus, hide]);
68
68
  return handleKeyDown;
69
69
  };
@@ -45,8 +45,6 @@ const MultiActionButton = ({
45
45
  } = (0, _useChildButtons.default)(buttonRef);
46
46
  const handleInsideClick = (0, _useClickAwayListener.default)(hideButtons);
47
47
  const handleClick = ev => {
48
- // ensure button is focused when clicked (Safari)
49
- buttonRef.current?.focus();
50
48
  showButtons();
51
49
  handleInsideClick();
52
50
  if (onClick) {
@@ -65,6 +63,7 @@ const MultiActionButton = ({
65
63
  ...(0, _utils.filterOutStyledSystemSpacingProps)(rest)
66
64
  };
67
65
  const renderAdditionalButtons = () => /*#__PURE__*/_react.default.createElement(_popover.default, {
66
+ disablePortal: true,
68
67
  placement: position === "left" ? "bottom-start" : /* istanbul ignore next */"bottom-end",
69
68
  reference: buttonNode,
70
69
  middleware: [(0, _dom.offset)(6), (0, _dom.flip)({
@@ -77,8 +77,6 @@ const SplitButton = ({
77
77
  ...(0, _utils.filterOutStyledSystemSpacingProps)(rest)
78
78
  };
79
79
  const handleToggleClick = () => {
80
- // ensure button is focused when clicked (Safari)
81
- toggleButton.current?.focus();
82
80
  showButtons();
83
81
  };
84
82
  const toggleButtonProps = {
@@ -128,6 +126,7 @@ const SplitButton = ({
128
126
  function renderAdditionalButtons() {
129
127
  if (!showAdditionalButtons) return null;
130
128
  return /*#__PURE__*/_react.default.createElement(_popover.default, {
129
+ disablePortal: true,
131
130
  placement: position === "left" ? /* istanbul ignore next */"bottom-start" : "bottom-end",
132
131
  reference: buttonNode,
133
132
  middleware: [(0, _dom.offset)(6), (0, _dom.flip)({
@@ -16,7 +16,7 @@ const StyledSplitButton = _styledComponents.default.div`
16
16
  display: inline-block;
17
17
  position: relative;
18
18
 
19
- ${_button.default}:first-of-type {
19
+ & > ${_button.default}:first-of-type {
20
20
  border-top-right-radius: var(--borderRadius000);
21
21
  border-bottom-right-radius: var(--borderRadius000);
22
22
  }
@@ -48,7 +48,7 @@ const StyledHintText = exports.StyledHintText = _styledComponents.default.div`
48
48
  ${({
49
49
  isDarkBackground
50
50
  }) => (0, _styledComponents.css)`
51
- color: ${isDarkBackground ? "var(--colorsUtilityYang065)" : "var(--colorsUtilityYin055)"};
51
+ color: ${isDarkBackground ? "var(--colorsUtilityYang080)" : "var(--colorsUtilityYin055)"};
52
52
  `}
53
53
  `;
54
54
  const StyledSwitch = _styledComponents.default.div`
@@ -25,16 +25,18 @@ const useChildButtons = (toggleButtonRef, widthRatio = 1) => {
25
25
  }
26
26
  }
27
27
  const getButtonChildren = (0, _react.useCallback)(() => childrenContainer.current?.querySelectorAll('[data-component="button"]'), []);
28
+
29
+ // focus first child button when opened
30
+ (0, _react.useEffect)(() => {
31
+ if (showAdditionalButtons) {
32
+ getButtonChildren()?.[0]?.focus();
33
+ }
34
+ }, [showAdditionalButtons, getButtonChildren]);
28
35
  const handleToggleButtonKeyDown = ev => {
29
- const isToggleKey = _events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev) || _events.default.isUpKey(ev) || showAdditionalButtons && _events.default.isTabKey(ev);
36
+ const isToggleKey = _events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev) || _events.default.isUpKey(ev);
30
37
  if (isToggleKey) {
31
38
  ev.preventDefault();
32
- if (!showAdditionalButtons) {
33
- showButtons();
34
- }
35
- setTimeout(() => {
36
- getButtonChildren()?.[0]?.focus();
37
- });
39
+ showButtons();
38
40
  }
39
41
  };
40
42
  const handleKeyDown = (0, _useMenuKeyboardNavigation.default)(toggleButtonRef, getButtonChildren, hideButtons, showAdditionalButtons);
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _react = require("react");
8
8
  var _events = _interopRequireDefault(require("../../../__internal__/utils/helpers/events"));
9
- var _focusTrapUtils = require("../../../__internal__/focus-trap/focus-trap-utils");
10
9
  var _useModalManager = _interopRequireDefault(require("../useModalManager"));
11
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
11
  var _default = (mainControlRef, getButtonChildren, hide, isOpen) => {
@@ -29,7 +28,7 @@ var _default = (mainControlRef, getButtonChildren, hide, isOpen) => {
29
28
  modalRef: mainControlRef
30
29
  });
31
30
  const handleKeyDown = (0, _react.useCallback)(ev => {
32
- if (!(_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev))) {
31
+ if (!(_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isTabKey(ev))) {
33
32
  ev.preventDefault();
34
33
  }
35
34
  const buttonChildren = getButtonChildren();
@@ -49,29 +48,30 @@ var _default = (mainControlRef, getButtonChildren, hide, isOpen) => {
49
48
  if (!arrowModifierPressed && _events.default.isDownKey(ev) && currentIndex < childrenLength - 1) {
50
49
  nextIndex = currentIndex + 1;
51
50
  }
52
- const tabPressed = _events.default.isTabKey(ev);
53
- const tabShiftPressed = tabPressed && _events.default.isShiftKey(ev);
54
- if (tabShiftPressed) {
55
- if (currentIndex === 0) {
56
- refocusMainControl();
57
- } else {
58
- nextIndex = currentIndex - 1;
59
- }
60
- } else if (tabPressed) {
61
- if (currentIndex === childrenLength - 1) {
62
- const elements = Array.from(document.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
63
- const indexOf = elements.indexOf(mainControlRef.current);
64
- elements[indexOf + 1]?.focus();
65
- // timeout enforces that the "hide" method will be run after browser focuses on the next element
66
- setTimeout(hide, 0);
67
- } else {
68
- nextIndex = currentIndex + 1;
69
- }
70
- }
71
51
  if (nextIndex > -1) {
72
52
  buttonChildren?.[nextIndex]?.focus();
73
53
  }
74
- }, [hide, refocusMainControl, mainControlRef, getButtonChildren]);
54
+ }, [getButtonChildren]);
55
+
56
+ // check if a child button is focused, if not hide the menu
57
+ const checkFocus = (0, _react.useCallback)(() => {
58
+ const buttonChildren = getButtonChildren();
59
+ if (!buttonChildren) {
60
+ return;
61
+ }
62
+ const buttonChildrenFocused = Array.from(buttonChildren).some(button => button === document.activeElement);
63
+ if (!buttonChildrenFocused) {
64
+ hide();
65
+ }
66
+ }, [getButtonChildren, hide]);
67
+ (0, _react.useEffect)(() => {
68
+ document.addEventListener("focusin", checkFocus);
69
+ window.addEventListener("blur", hide);
70
+ return () => {
71
+ document.removeEventListener("focusin", checkFocus);
72
+ window.removeEventListener("blur", hide);
73
+ };
74
+ }, [checkFocus, hide]);
75
75
  return handleKeyDown;
76
76
  };
77
77
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "144.9.9",
3
+ "version": "144.9.11",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",