carbon-react 109.2.3 → 109.3.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 (127) hide show
  1. package/esm/__internal__/field-help/field-help.component.d.ts +10 -0
  2. package/esm/__internal__/field-help/field-help.component.js +12 -16
  3. package/esm/__internal__/field-help/field-help.style.d.ts +8 -0
  4. package/esm/__internal__/field-help/field-help.style.js +2 -10
  5. package/esm/__internal__/field-help/index.d.ts +2 -1
  6. package/esm/__internal__/focus-trap/focus-trap-utils.d.ts +1 -2
  7. package/esm/__internal__/focus-trap/focus-trap-utils.js +57 -8
  8. package/esm/__internal__/focus-trap/focus-trap.component.js +35 -25
  9. package/esm/__internal__/validations/validation-icon.component.js +1 -1
  10. package/esm/__spec_helper__/index.d.ts +1 -0
  11. package/esm/__spec_helper__/index.js +4 -10
  12. package/esm/__spec_helper__/mock-match-media.d.ts +2 -2
  13. package/esm/__spec_helper__/mock-match-media.js +2 -2
  14. package/esm/__spec_helper__/mock-resize-observer.d.ts +2 -0
  15. package/esm/components/accordion/accordion-group/accordion-group.component.js +1 -1
  16. package/esm/components/action-popover/action-popover-item/action-popover-item.component.js +2 -2
  17. package/esm/components/action-popover/action-popover-menu/action-popover-menu.component.js +3 -3
  18. package/esm/components/action-popover/action-popover.component.js +1 -1
  19. package/esm/components/alert/alert.component.js +9 -0
  20. package/esm/components/anchor-navigation/anchor-navigation.component.js +2 -2
  21. package/esm/components/button/button.component.js +2 -2
  22. package/esm/components/button-bar/button-bar.component.js +1 -1
  23. package/esm/components/decimal/decimal.component.js +3 -3
  24. package/esm/components/dialog/dialog.component.js +9 -2
  25. package/esm/components/dialog/dialog.d.ts +2 -0
  26. package/esm/components/dialog-full-screen/dialog-full-screen.component.js +9 -2
  27. package/esm/components/dialog-full-screen/dialog-full-screen.d.ts +2 -0
  28. package/esm/components/drawer/drawer.component.js +1 -1
  29. package/esm/components/grid/grid-container/grid-container.component.d.ts +8 -0
  30. package/esm/components/grid/grid-container/grid-container.component.js +1821 -21
  31. package/esm/components/grid/grid-container/grid-container.style.d.ts +3 -0
  32. package/esm/components/grid/grid-container/grid-container.style.js +2 -2
  33. package/esm/components/grid/grid-container/index.d.ts +2 -1
  34. package/esm/components/grid/grid-item/grid-item.component.d.ts +11 -0
  35. package/esm/components/grid/grid-item/grid-item.component.js +1221 -45
  36. package/esm/components/grid/grid-item/grid-item.style.d.ts +17 -0
  37. package/esm/components/grid/grid-item/grid-item.style.js +38 -62
  38. package/esm/components/grid/grid-item/index.d.ts +2 -1
  39. package/esm/components/grid/index.d.ts +2 -0
  40. package/esm/components/grid/index.js +2 -3
  41. package/esm/components/icon/icon.component.js +1 -1
  42. package/esm/components/multi-action-button/multi-action-button.component.js +14 -84
  43. package/esm/components/note/note.component.js +6 -6
  44. package/esm/components/numeral-date/numeral-date.component.js +1 -1
  45. package/esm/components/search/search.component.js +1 -1
  46. package/esm/components/select/filterable-select/filterable-select.component.js +3 -3
  47. package/esm/components/select/multi-select/multi-select.component.js +2 -2
  48. package/esm/components/select/simple-select/simple-select.component.js +2 -2
  49. package/esm/components/sidebar/sidebar.component.js +9 -2
  50. package/esm/components/sidebar/sidebar.d.ts +2 -0
  51. package/esm/components/split-button/split-button.component.js +15 -82
  52. package/esm/components/toast/toast.component.js +35 -9
  53. package/esm/components/toast/toast.d.ts +5 -1
  54. package/esm/components/tooltip/tooltip.component.js +1 -1
  55. package/esm/hooks/__internal__/useMenuKeyboardNavigation/index.d.ts +1 -0
  56. package/esm/hooks/__internal__/useMenuKeyboardNavigation/index.js +1 -0
  57. package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +2 -0
  58. package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +70 -0
  59. package/esm/hooks/__internal__/useScrollBlock/useScrollBlock.js +39 -37
  60. package/lib/__internal__/field-help/field-help.component.d.ts +10 -0
  61. package/lib/__internal__/field-help/field-help.component.js +12 -16
  62. package/lib/__internal__/field-help/field-help.style.d.ts +8 -0
  63. package/lib/__internal__/field-help/field-help.style.js +2 -13
  64. package/lib/__internal__/field-help/index.d.ts +2 -1
  65. package/lib/__internal__/focus-trap/focus-trap-utils.d.ts +1 -2
  66. package/lib/__internal__/focus-trap/focus-trap-utils.js +57 -10
  67. package/lib/__internal__/focus-trap/focus-trap.component.js +34 -24
  68. package/lib/__internal__/validations/validation-icon.component.js +1 -1
  69. package/lib/__spec_helper__/index.d.ts +1 -0
  70. package/lib/__spec_helper__/index.js +3 -10
  71. package/lib/__spec_helper__/mock-match-media.d.ts +2 -2
  72. package/lib/__spec_helper__/mock-match-media.js +4 -4
  73. package/lib/__spec_helper__/mock-resize-observer.d.ts +2 -0
  74. package/lib/components/accordion/accordion-group/accordion-group.component.js +1 -1
  75. package/lib/components/action-popover/action-popover-item/action-popover-item.component.js +2 -2
  76. package/lib/components/action-popover/action-popover-menu/action-popover-menu.component.js +3 -3
  77. package/lib/components/action-popover/action-popover.component.js +1 -1
  78. package/lib/components/alert/alert.component.js +9 -0
  79. package/lib/components/anchor-navigation/anchor-navigation.component.js +2 -2
  80. package/lib/components/button/button.component.js +2 -2
  81. package/lib/components/button-bar/button-bar.component.js +1 -1
  82. package/lib/components/decimal/decimal.component.js +3 -3
  83. package/lib/components/dialog/dialog.component.js +9 -2
  84. package/lib/components/dialog/dialog.d.ts +2 -0
  85. package/lib/components/dialog-full-screen/dialog-full-screen.component.js +9 -2
  86. package/lib/components/dialog-full-screen/dialog-full-screen.d.ts +2 -0
  87. package/lib/components/drawer/drawer.component.js +1 -1
  88. package/lib/components/grid/grid-container/grid-container.component.d.ts +8 -0
  89. package/lib/components/grid/grid-container/grid-container.component.js +1826 -22
  90. package/lib/components/grid/grid-container/grid-container.style.d.ts +3 -0
  91. package/lib/components/grid/grid-container/grid-container.style.js +2 -2
  92. package/lib/components/grid/grid-container/index.d.ts +2 -1
  93. package/lib/components/grid/grid-item/grid-item.component.d.ts +11 -0
  94. package/lib/components/grid/grid-item/grid-item.component.js +1221 -46
  95. package/lib/components/grid/grid-item/grid-item.style.d.ts +17 -0
  96. package/lib/components/grid/grid-item/grid-item.style.js +37 -67
  97. package/lib/components/grid/grid-item/index.d.ts +2 -1
  98. package/lib/components/grid/index.d.ts +2 -0
  99. package/lib/components/icon/icon.component.js +1 -1
  100. package/lib/components/multi-action-button/multi-action-button.component.js +13 -83
  101. package/lib/components/note/note.component.js +6 -6
  102. package/lib/components/numeral-date/numeral-date.component.js +1 -1
  103. package/lib/components/search/search.component.js +1 -1
  104. package/lib/components/select/filterable-select/filterable-select.component.js +3 -3
  105. package/lib/components/select/multi-select/multi-select.component.js +2 -2
  106. package/lib/components/select/simple-select/simple-select.component.js +2 -2
  107. package/lib/components/sidebar/sidebar.component.js +9 -2
  108. package/lib/components/sidebar/sidebar.d.ts +2 -0
  109. package/lib/components/split-button/split-button.component.js +14 -83
  110. package/lib/components/toast/toast.component.js +35 -7
  111. package/lib/components/toast/toast.d.ts +5 -1
  112. package/lib/components/tooltip/tooltip.component.js +1 -1
  113. package/lib/hooks/__internal__/useMenuKeyboardNavigation/index.d.ts +1 -0
  114. package/lib/hooks/__internal__/useMenuKeyboardNavigation/index.js +15 -0
  115. package/lib/hooks/__internal__/useMenuKeyboardNavigation/package.json +6 -0
  116. package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +2 -0
  117. package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +85 -0
  118. package/lib/hooks/__internal__/useScrollBlock/useScrollBlock.js +38 -36
  119. package/package.json +9 -7
  120. package/scripts/{check_carbon_version.js → check_carbon_version/check_carbon_version.js} +10 -2
  121. package/scripts/{check_rfcs.js → check_rfcs/check_rfcs.js} +8 -1
  122. package/esm/__internal__/field-help/field-help.d.ts +0 -14
  123. package/esm/components/grid/grid-container/grid-container.d.ts +0 -18
  124. package/esm/components/grid/grid-item/grid-item.d.ts +0 -42
  125. package/lib/__internal__/field-help/field-help.d.ts +0 -14
  126. package/lib/components/grid/grid-container/grid-container.d.ts +0 -18
  127. package/lib/components/grid/grid-item/grid-item.d.ts +0 -42
@@ -11,8 +11,7 @@ import IconButton from "../icon-button";
11
11
  import Events from "../../__internal__/utils/helpers/events";
12
12
  import useLocale from "../../hooks/__internal__/useLocale";
13
13
  import useModalManager from "../../hooks/__internal__/useModalManager";
14
-
15
- const Toast = ({
14
+ const Toast = /*#__PURE__*/React.forwardRef(({
16
15
  children,
17
16
  className,
18
17
  id,
@@ -23,12 +22,16 @@ const Toast = ({
23
22
  targetPortalId,
24
23
  timeout,
25
24
  variant,
25
+ disableAutoFocus,
26
26
  ...restProps
27
- }) => {
27
+ }, ref) => {
28
28
  const locale = useLocale();
29
29
  const toastRef = useRef();
30
30
  const timer = useRef();
31
31
  const toastContentNodeRef = useRef();
32
+ const closeIconRef = useRef();
33
+ const focusedElementBeforeOpening = useRef();
34
+ const refToPass = ref || toastRef;
32
35
  const componentClasses = useMemo(() => {
33
36
  return classNames(className);
34
37
  }, [className]);
@@ -38,7 +41,7 @@ const Toast = ({
38
41
  onDismiss(ev);
39
42
  }
40
43
  }, [onDismiss]);
41
- useModalManager(open, dismissToast, toastRef);
44
+ useModalManager(open, dismissToast, refToPass);
42
45
  useEffect(() => {
43
46
  clearTimeout(timer.current);
44
47
 
@@ -48,13 +51,34 @@ const Toast = ({
48
51
 
49
52
  timer.current = setTimeout(() => onDismiss(), timeout);
50
53
  }, [onDismiss, open, timeout]);
54
+ useEffect(() => {
55
+ if (onDismiss && !disableAutoFocus) {
56
+ if (open) {
57
+ var _closeIconRef$current;
58
+
59
+ focusedElementBeforeOpening.current = document.activeElement;
60
+ (_closeIconRef$current = closeIconRef.current) === null || _closeIconRef$current === void 0 ? void 0 : _closeIconRef$current.focus();
61
+ } else if (focusedElementBeforeOpening.current) {
62
+ focusedElementBeforeOpening.current.focus();
63
+ focusedElementBeforeOpening.current = undefined;
64
+ }
65
+ }
66
+ }, [open, onDismiss, disableAutoFocus]);
67
+ useEffect(() => {
68
+ return () => {
69
+ if (focusedElementBeforeOpening.current) {
70
+ focusedElementBeforeOpening.current.focus();
71
+ }
72
+ };
73
+ }, []);
51
74
 
52
75
  function renderCloseIcon() {
53
76
  if (!onDismiss) return null;
54
77
  return /*#__PURE__*/React.createElement(IconButton, {
55
78
  "aria-label": locale.toast.ariaLabels.close(),
56
79
  "data-element": "close",
57
- onAction: onDismiss
80
+ onAction: onDismiss,
81
+ ref: closeIconRef
58
82
  }, /*#__PURE__*/React.createElement(Icon, {
59
83
  type: "close"
60
84
  }));
@@ -96,10 +120,9 @@ const Toast = ({
96
120
  isCenter: isCenter
97
121
  }, /*#__PURE__*/React.createElement(ToastWrapper, {
98
122
  isCenter: isCenter,
99
- ref: toastRef
123
+ ref: refToPass
100
124
  }, /*#__PURE__*/React.createElement(TransitionGroup, null, renderToastContent())));
101
- };
102
-
125
+ });
103
126
  Toast.propTypes = {
104
127
  /** Customizes the appearance in the DLS theme */
105
128
  variant: PropTypes.oneOf(["error", "info", "success", "warning"]),
@@ -132,6 +155,9 @@ Toast.propTypes = {
132
155
  targetPortalId: PropTypes.string,
133
156
 
134
157
  /** Maximum toast width */
135
- maxWidth: PropTypes.string
158
+ maxWidth: PropTypes.string,
159
+
160
+ /** Disables auto focus functionality when the Toast has a close icon */
161
+ disableAutoFocus: PropTypes.bool
136
162
  };
137
163
  export default Toast;
@@ -25,8 +25,12 @@ export interface ToastPropTypes {
25
25
  targetPortalId?: string;
26
26
  /** Maximum toast width */
27
27
  maxWidth?: string;
28
+ /** Disables auto focus functionality when the Toast has a close icon */
29
+ disableAutoFocus?: boolean;
28
30
  }
29
31
 
30
- declare class Toast extends React.Component<ToastPropTypes> {}
32
+ declare function Toast(
33
+ props: ToastPropTypes & React.RefAttributes<HTMLDivElement>
34
+ ): JSX.Element;
31
35
 
32
36
  export default Toast;
@@ -29,7 +29,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef(({
29
29
  ...rest
30
30
  }, ref) => {
31
31
  const isFlipOverridesValid = !flipOverrides || Array.isArray(flipOverrides) && flipOverrides.every(placement => TOOLTIP_POSITIONS.includes(placement));
32
- invariant(isFlipOverridesValid, `The flipOverrides prop supplied to Tooltip must be an array containing some or all of ["top", "bottom", "left", "right"].`);
32
+ !isFlipOverridesValid ? process.env.NODE_ENV !== "production" ? invariant(false, `The flipOverrides prop supplied to Tooltip must be an array containing some or all of ["top", "bottom", "left", "right"].`) : invariant(false) : void 0;
33
33
 
34
34
  const tooltip = (attrs, content) => {
35
35
  const currentPosition = attrs["data-placement"] || position;
@@ -0,0 +1 @@
1
+ export { default } from "./useMenuKeyboardNavigation";
@@ -0,0 +1 @@
1
+ export { default } from "./useMenuKeyboardNavigation";
@@ -0,0 +1,2 @@
1
+ declare const _default: (mainControlRef: React.RefObject<HTMLButtonElement>, childrenRefs: React.RefObject<HTMLButtonElement>[], hide: () => void) => (ev: any) => void;
2
+ export default _default;
@@ -0,0 +1,70 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import Events from "../../../__internal__/utils/helpers/events";
3
+ import { defaultFocusableSelectors } from "../../../__internal__/focus-trap/focus-trap-utils";
4
+ export default ((mainControlRef, childrenRefs, hide) => {
5
+ const childrenLength = useMemo(() => childrenRefs.length, [childrenRefs]);
6
+ const handleKeyDown = useCallback(ev => {
7
+ ev.preventDefault();
8
+ const currentIndex = childrenRefs === null || childrenRefs === void 0 ? void 0 : childrenRefs.findIndex(node => node.current === document.activeElement);
9
+ let nextIndex = -1;
10
+
11
+ const refocusMainControl = () => {
12
+ var _mainControlRef$curre;
13
+
14
+ hide();
15
+ (_mainControlRef$curre = mainControlRef.current) === null || _mainControlRef$curre === void 0 ? void 0 : _mainControlRef$curre.focus();
16
+ };
17
+
18
+ const arrowModifierPressed = ev.ctrlKey || ev.metaKey;
19
+
20
+ if (Events.isEndKey(ev) || arrowModifierPressed && Events.isDownKey(ev)) {
21
+ nextIndex = childrenLength - 1;
22
+ }
23
+
24
+ if (Events.isHomeKey(ev) || arrowModifierPressed && Events.isUpKey(ev)) {
25
+ nextIndex = 0;
26
+ }
27
+
28
+ if (!arrowModifierPressed && Events.isUpKey(ev) && currentIndex > 0) {
29
+ nextIndex = currentIndex - 1;
30
+ }
31
+
32
+ if (!arrowModifierPressed && Events.isDownKey(ev) && currentIndex < childrenLength - 1) {
33
+ nextIndex = currentIndex + 1;
34
+ }
35
+
36
+ const tabPressed = Events.isTabKey(ev);
37
+ const tabShiftPressed = tabPressed && Events.isShiftKey(ev);
38
+
39
+ if (tabShiftPressed) {
40
+ if (currentIndex === 0) {
41
+ refocusMainControl();
42
+ } else {
43
+ nextIndex = currentIndex - 1;
44
+ }
45
+ } else if (tabPressed) {
46
+ if (currentIndex === childrenLength - 1) {
47
+ var _elements;
48
+
49
+ const elements = Array.from(document.querySelectorAll(defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
50
+ const indexOf = elements.indexOf(mainControlRef.current);
51
+ (_elements = elements[indexOf + 1]) === null || _elements === void 0 ? void 0 : _elements.focus(); // // timeout enforces that the "hide" method will be run after browser focuses on the next element
52
+
53
+ setTimeout(hide, 0);
54
+ } else {
55
+ nextIndex = currentIndex + 1;
56
+ }
57
+ }
58
+
59
+ if (nextIndex > -1) {
60
+ var _childrenRefs$nextInd;
61
+
62
+ (_childrenRefs$nextInd = childrenRefs[nextIndex].current) === null || _childrenRefs$nextInd === void 0 ? void 0 : _childrenRefs$nextInd.focus();
63
+ }
64
+
65
+ if (Events.isEscKey(ev)) {
66
+ refocusMainControl();
67
+ }
68
+ }, [childrenLength, hide, childrenRefs, mainControlRef]);
69
+ return handleKeyDown;
70
+ });
@@ -1,55 +1,57 @@
1
- import { useRef, useCallback, useMemo } from "react";
1
+ import { useRef, useCallback } from "react";
2
2
  import guid from "../../../__internal__/utils/helpers/guid";
3
3
  import ScrollBlockManager from "./scroll-block-manager"; // TODO: This component can be refactored to remove redundant code after
4
4
  // we can confirm that all Sage products use version 105.0.0^
5
5
 
6
6
  const scrollBlockManager = new ScrollBlockManager();
7
7
 
8
+ const getRules = () => {
9
+ /* istanbul ignore next */
10
+ const {
11
+ documentElement,
12
+ body
13
+ } = document || {};
14
+ const scrollBarWidth = window.innerWidth - documentElement.clientWidth;
15
+ const bodyPaddingRight = parseInt(window.getComputedStyle(body).getPropertyValue("padding-right")) || 0;
16
+ return [// TODO: First two entries of this array with the documentElement can be removed
17
+ {
18
+ element: documentElement,
19
+ property: "position",
20
+ blockingValue: "relative"
21
+ }, {
22
+ element: documentElement,
23
+ property: "overflow",
24
+ blockingValue: "hidden"
25
+ }, {
26
+ element: body,
27
+ property: "position",
28
+ blockingValue: "relative"
29
+ }, {
30
+ element: body,
31
+ property: "overflow",
32
+ blockingValue: "hidden"
33
+ }, {
34
+ element: body,
35
+ property: "paddingRight",
36
+ blockingValue: `${bodyPaddingRight + scrollBarWidth}px`
37
+ }];
38
+ };
39
+
8
40
  const useScrollBlock = () => {
9
41
  const {
10
42
  current: containerGuid
11
43
  } = useRef(guid());
12
44
  const originalValuesRef = useRef([]);
13
- const rules = useMemo(() => {
14
- /* istanbul ignore next */
15
- const {
16
- documentElement,
17
- body
18
- } = document || {};
19
- const scrollBarWidth = window.innerWidth - documentElement.clientWidth;
20
- const bodyPaddingRight = parseInt(window.getComputedStyle(body).getPropertyValue("padding-right")) || 0;
21
- return [// TODO: First two entries of this array with the documentElement can be removed
22
- {
23
- element: documentElement,
24
- property: "position",
25
- blockingValue: "relative"
26
- }, {
27
- element: documentElement,
28
- property: "overflow",
29
- blockingValue: "hidden"
30
- }, {
31
- element: body,
32
- property: "position",
33
- blockingValue: "relative"
34
- }, {
35
- element: body,
36
- property: "overflow",
37
- blockingValue: "hidden"
38
- }, {
39
- element: body,
40
- property: "paddingRight",
41
- blockingValue: `${bodyPaddingRight + scrollBarWidth}px`
42
- }];
43
- }, []);
44
45
  const restoreValues = useCallback(() => {
45
- rules.forEach(({
46
+ getRules().forEach(({
46
47
  element,
47
48
  property
48
49
  }, index) => {
49
50
  element.style[property] = originalValuesRef.current[index];
50
51
  });
51
- }, [rules]);
52
+ }, []);
52
53
  const blockScroll = useCallback(() => {
54
+ const rules = getRules();
53
55
  const isBlocked = scrollBlockManager.isBlocked();
54
56
  scrollBlockManager.registerComponent(containerGuid);
55
57
 
@@ -73,7 +75,7 @@ const useScrollBlock = () => {
73
75
  }) => {
74
76
  element.style[property] = blockingValue;
75
77
  });
76
- }, [restoreValues, containerGuid, rules]);
78
+ }, [restoreValues, containerGuid]);
77
79
  const allowScroll = useCallback(() => {
78
80
  scrollBlockManager.unregisterComponent(containerGuid);
79
81
  const isBlocked = scrollBlockManager.isBlocked();
@@ -88,14 +90,14 @@ const useScrollBlock = () => {
88
90
 
89
91
 
90
92
  const originalValues = scrollBlockManager.getOriginalValues();
91
- rules.forEach(({
93
+ getRules().forEach(({
92
94
  element,
93
95
  property
94
96
  }, index) => {
95
97
  element.style[property] = originalValues[index];
96
98
  });
97
99
  scrollBlockManager.saveOriginalValues([]);
98
- }, [containerGuid, rules]);
100
+ }, [containerGuid]);
99
101
  return {
100
102
  blockScroll,
101
103
  allowScroll
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { StyledFieldHelpProps } from "./field-help.style";
3
+ export interface FieldHelpProps extends StyledFieldHelpProps {
4
+ /** Child elements */
5
+ children?: React.ReactNode;
6
+ /** The unique id of the FieldHelp component */
7
+ id?: string;
8
+ }
9
+ export declare const FieldHelp: ({ children, labelInline, labelWidth, id, }: FieldHelpProps) => JSX.Element;
10
+ export default FieldHelp;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.default = exports.FieldHelp = void 0;
7
7
 
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
 
@@ -13,28 +13,24 @@ var _fieldHelp = _interopRequireDefault(require("./field-help.style"));
13
13
 
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
 
16
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
17
-
18
16
  const FieldHelp = ({
19
17
  children,
20
18
  labelInline,
21
- labelWidth,
22
- ...rest
23
- }) => /*#__PURE__*/_react.default.createElement(_fieldHelp.default, _extends({
19
+ labelWidth = 30,
20
+ id
21
+ }) => /*#__PURE__*/_react.default.createElement(_fieldHelp.default, {
24
22
  "data-element": "help",
25
23
  labelInline: labelInline,
26
- labelWidth: labelWidth
27
- }, rest), children);
24
+ labelWidth: labelWidth,
25
+ id: id
26
+ }, children);
28
27
 
28
+ exports.FieldHelp = FieldHelp;
29
29
  FieldHelp.propTypes = {
30
- /** Child elements */
31
- children: _propTypes.default.node,
32
-
33
- /** When true, label is placed in line an input */
34
- labelInline: _propTypes.default.bool,
35
-
36
- /** Width of a label in percentage. Works only when labelInline is true */
37
- labelWidth: _propTypes.default.number
30
+ "children": _propTypes.default.node,
31
+ "id": _propTypes.default.string,
32
+ "labelInline": _propTypes.default.bool,
33
+ "labelWidth": _propTypes.default.number
38
34
  };
39
35
  var _default = FieldHelp;
40
36
  exports.default = _default;
@@ -0,0 +1,8 @@
1
+ export interface StyledFieldHelpProps {
2
+ /** When true, label is placed in line an input */
3
+ labelInline?: boolean;
4
+ /** Width of a label in percentage. Works only when labelInline is true */
5
+ labelWidth?: number;
6
+ }
7
+ declare const StyledFieldHelp: import("styled-components").StyledComponent<"span", any, StyledFieldHelpProps, never>;
8
+ export default StyledFieldHelp;
@@ -7,15 +7,11 @@ exports.default = void 0;
7
7
 
8
8
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
9
9
 
10
- var _propTypes = _interopRequireDefault(require("prop-types"));
11
-
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
10
  function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
15
11
 
16
12
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
13
 
18
- const FieldHelpStyle = _styledComponents.default.span`
14
+ const StyledFieldHelp = _styledComponents.default.span`
19
15
  display: block;
20
16
  flex: 1;
21
17
  margin-top: 8px;
@@ -29,12 +25,5 @@ const FieldHelpStyle = _styledComponents.default.span`
29
25
  padding-left: 0;
30
26
  `}
31
27
  `;
32
- FieldHelpStyle.defaultProps = {
33
- labelWidth: 30
34
- };
35
- FieldHelpStyle.propTypes = {
36
- labelWidth: _propTypes.default.number,
37
- labelInline: _propTypes.default.bool
38
- };
39
- var _default = FieldHelpStyle;
28
+ var _default = StyledFieldHelp;
40
29
  exports.default = _default;
@@ -1 +1,2 @@
1
- export { default } from "./field-help";
1
+ export { default } from "./field-help.component";
2
+ export type { FieldHelpProps } from "./field-help.component";
@@ -1,4 +1,3 @@
1
1
  export const defaultFocusableSelectors: "button:not([disabled]), [href], input:not([type=\"hidden\"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]";
2
- export function nextNonRadioElementIndex(element: any, focusableElements: any): number;
3
- export function isRadio(element: any): any;
2
+ export function getNextElement(element: any, focusableElements: any, shiftKey: any): any;
4
3
  export function setElementFocus(element: any): void;
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.setElementFocus = setElementFocus;
7
- exports.isRadio = exports.nextNonRadioElementIndex = exports.defaultFocusableSelectors = void 0;
7
+ exports.getNextElement = exports.defaultFocusableSelectors = void 0;
8
8
  const defaultFocusableSelectors = 'button:not([disabled]), [href], input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]';
9
9
  exports.defaultFocusableSelectors = defaultFocusableSelectors;
10
10
 
@@ -45,19 +45,66 @@ const isRadio = element => {
45
45
  return element.hasAttribute("type") && element.getAttribute("type") === "radio";
46
46
  };
47
47
 
48
- exports.isRadio = isRadio;
48
+ const getRadioElementToFocus = (groupName, shiftKey) => {
49
+ const buttonsInGroup = document.querySelectorAll(`input[type="radio"][name="${groupName}"]`);
50
+ const selectedButton = [...buttonsInGroup].find(button => button.checked);
49
51
 
50
- const nextNonRadioElementIndex = (element, focusableElements) => {
52
+ if (selectedButton) {
53
+ return selectedButton;
54
+ }
55
+
56
+ return buttonsInGroup[shiftKey ? buttonsInGroup.length - 1 : 0];
57
+ };
58
+
59
+ const getNextElement = (element, focusableElements, shiftKey) => {
51
60
  const currentIndex = focusableElements.indexOf(element);
52
- let nextIndex = currentIndex - 1;
53
- if (currentIndex === 0) return focusableElements.length - 1;
54
- const isNextRadio = isRadio(focusableElements[nextIndex]);
61
+ const increment = shiftKey ? -1 : 1;
62
+ let nextIndex = currentIndex;
63
+ let foundElement;
64
+
65
+ while (!foundElement) {
66
+ nextIndex += increment;
67
+
68
+ if (nextIndex < 0) {
69
+ nextIndex += focusableElements.length;
70
+ }
71
+
72
+ if (nextIndex >= focusableElements.length) {
73
+ nextIndex -= focusableElements.length;
74
+ }
75
+
76
+ const nextElement = focusableElements[nextIndex];
77
+
78
+ if (nextElement === element) {
79
+ // guard in case there is only one focusable element (or only a single radio group) in the trap.
80
+ // If this happens we don't want to freeze the browser by looping forever, and it's OK to just focus
81
+ // the same element we're already on
82
+ return element;
83
+ }
84
+
85
+ if (isRadio(nextElement)) {
86
+ // if we've reached a radio element we need to ensure we focus the correct button in its group
87
+ const nextElementGroupName = nextElement.getAttribute("name");
88
+
89
+ if (isRadio(element)) {
90
+ const groupName = element.getAttribute("name"); // if the name is different we're in a new group so can focus the appropriate button in it*/
91
+
92
+ if (nextElementGroupName !== groupName) {
93
+ foundElement = getRadioElementToFocus(nextElementGroupName, shiftKey);
94
+ } // otherwise we're still in the same radio group so need to continue the loop
55
95
 
56
- if (isNextRadio) {
57
- nextIndex = nextNonRadioElementIndex(focusableElements[nextIndex], focusableElements);
96
+ } else {
97
+ // if we've moved into a radio group from a non-radio starting point, we still have to ensure we focus
98
+ // the correct button in the group
99
+ foundElement = getRadioElementToFocus(nextElementGroupName, shiftKey);
100
+ }
101
+ } else {
102
+ // if we've reached a non-radio element, we can focus it with no issues
103
+ foundElement = nextElement;
104
+ }
58
105
  }
59
106
 
60
- return nextIndex;
107
+ return foundElement;
61
108
  };
62
109
 
63
- exports.nextNonRadioElementIndex = nextNonRadioElementIndex;
110
+ exports.getNextElement = getNextElement;
@@ -27,7 +27,8 @@ const FocusTrap = ({
27
27
  focusFirstElement,
28
28
  bespokeTrap,
29
29
  wrapperRef,
30
- isOpen
30
+ isOpen,
31
+ additionalWrapperRefs
31
32
  }) => {
32
33
  const trapRef = (0, _react.useRef)(null);
33
34
  const [focusableElements, setFocusableElements] = (0, _react.useState)();
@@ -45,19 +46,21 @@ const FocusTrap = ({
45
46
 
46
47
  return Array.from(candidate).some((el, i) => el !== focusableElements[i]);
47
48
  }, [focusableElements]);
49
+ const allRefs = [wrapperRef, ...additionalWrapperRefs].map(ref => ref === null || ref === void 0 ? void 0 : ref.current);
48
50
  const updateFocusableElements = (0, _react.useCallback)(() => {
49
- const ref = wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current;
50
-
51
- if (ref) {
52
- const elements = Array.from(ref.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
53
-
54
- if (hasNewInputs(elements)) {
55
- setFocusableElements(Array.from(elements));
56
- setFirstElement(elements[0]);
57
- setLastElement(elements[elements.length - 1]);
51
+ const elements = [];
52
+ allRefs.forEach(ref => {
53
+ if (ref) {
54
+ elements.push(...Array.from(ref.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1));
58
55
  }
56
+ });
57
+
58
+ if (hasNewInputs(elements)) {
59
+ setFocusableElements(Array.from(elements));
60
+ setFirstElement(elements[0]);
61
+ setLastElement(elements[elements.length - 1]);
59
62
  }
60
- }, [hasNewInputs, wrapperRef]);
63
+ }, [hasNewInputs, allRefs]);
61
64
  (0, _react.useEffect)(() => {
62
65
  const observer = new MutationObserver(updateFocusableElements);
63
66
  observer.observe(trapRef.current, {
@@ -95,20 +98,19 @@ const FocusTrap = ({
95
98
  ev.preventDefault();
96
99
  } else if (ev.shiftKey) {
97
100
  /* shift + tab */
98
- if (activeElement === firstElement || activeElement === wrapperRef.current) {
99
- lastElement.focus();
100
- ev.preventDefault();
101
- } // If current element is radio button -
102
- // find next non radio button element
103
-
101
+ let elementToFocus;
104
102
 
105
- if ((0, _focusTrapUtils.isRadio)(activeElement)) {
106
- const nextIndex = (0, _focusTrapUtils.nextNonRadioElementIndex)(activeElement, focusableElements);
107
- (0, _focusTrapUtils.setElementFocus)(focusableElements[nextIndex]);
108
- ev.preventDefault();
103
+ if (activeElement === wrapperRef.current) {
104
+ elementToFocus = (0, _focusTrapUtils.getNextElement)(firstElement, focusableElements, ev.shiftKey);
105
+ } else {
106
+ elementToFocus = (0, _focusTrapUtils.getNextElement)(activeElement, focusableElements, ev.shiftKey);
109
107
  }
110
- } else if (activeElement === lastElement) {
111
- firstElement.focus();
108
+
109
+ (0, _focusTrapUtils.setElementFocus)(elementToFocus);
110
+ ev.preventDefault();
111
+ } else {
112
+ const elementToFocus = (0, _focusTrapUtils.getNextElement)(activeElement, focusableElements, ev.shiftKey);
113
+ (0, _focusTrapUtils.setElementFocus)(elementToFocus);
112
114
  ev.preventDefault();
113
115
  }
114
116
  }
@@ -196,7 +198,15 @@ FocusTrap.propTypes = {
196
198
  }),
197
199
 
198
200
  /* whether the modal (etc.) component that the focus trap is inside is open or not */
199
- isOpen: _propTypes.default.bool
201
+ isOpen: _propTypes.default.bool,
202
+
203
+ /** an optional array of refs to containers whose content should also be reachable from the FocusTrap */
204
+ additionalWrapperRefs: _propTypes.default.arrayOf(_propTypes.default.shape({
205
+ current: _propTypes.default.any
206
+ }))
207
+ };
208
+ FocusTrap.defaultProps = {
209
+ additionalWrapperRefs: []
200
210
  };
201
211
  var _default = FocusTrap;
202
212
  exports.default = _default;
@@ -57,7 +57,7 @@ const ValidationIcon = ({
57
57
  const flipBehaviourCheck = Array.isArray(tooltipFlipOverrides) && tooltipFlipOverrides.every(override => ["bottom", "left", "right", "top"].includes(override));
58
58
 
59
59
  if (tooltipFlipOverrides) {
60
- (0, _invariant.default)(flipBehaviourCheck, `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`);
60
+ !flipBehaviourCheck ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, `The tooltipFlipOverrides prop supplied to ValidationIcon must be an array containing some or all of ["top", "bottom", "left", "right"].`) : (0, _invariant.default)(false) : void 0;
61
61
  }
62
62
 
63
63
  const {
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
 
3
- var _enzyme = _interopRequireDefault(require("enzyme"));
4
-
5
- var _enzymeAdapterReact = _interopRequireDefault(require("@wojtekmaj/enzyme-adapter-react-17"));
3
+ var _jestFetchMock = require("jest-fetch-mock");
6
4
 
7
5
  var _mockMatchMedia = require("./mock-match-media");
8
6
 
@@ -10,11 +8,6 @@ var _mockResizeObserver = _interopRequireDefault(require("./mock-resize-observer
10
8
 
11
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
10
 
13
- require("jest-fetch-mock").enableMocks();
14
-
11
+ (0, _jestFetchMock.enableFetchMocks)();
15
12
  (0, _mockResizeObserver.default)();
16
- (0, _mockMatchMedia.setup)();
17
-
18
- _enzyme.default.configure({
19
- adapter: new _enzymeAdapterReact.default()
20
- });
13
+ (0, _mockMatchMedia.setupMatchMediaMock)();
@@ -1,6 +1,6 @@
1
- declare function setup(): void;
1
+ declare function setupMatchMediaMock(): void;
2
2
  declare function mockMatchMedia(
3
3
  matches?: boolean
4
4
  ): { removeListener: jest.Mock };
5
5
 
6
- export { setup, mockMatchMedia };
6
+ export { setupMatchMediaMock, mockMatchMedia };