carbon-react 106.4.1 → 106.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,15 +35,22 @@ const MultiActionButton = ({
35
35
  const ref = useRef();
36
36
  const buttonRef = useRef();
37
37
  const buttonContainer = useRef();
38
- const userInputType = "ontouchstart" in document.documentElement ? "touchstart" : "click";
39
38
  const buttonChildren = React.Children.toArray(children);
40
39
  const additionalButtons = useRef(buttonChildren.map(() => /*#__PURE__*/React.createRef()));
41
40
  const listening = useRef(false);
42
41
  const isMainButtonFocused = useRef(false);
42
+ const isFocusedAfterClosing = useRef(false);
43
43
  const [showAdditionalButtons, setShowAdditionalButtons] = useState(false);
44
- const [removeHandleClickOutside, setRemoveHandleClickOutside] = useState(false);
45
- const [removeHandleKeyDown, setRemoveHandleKeyDown] = useState(false);
46
44
  const [minWidth, setMinWidth] = useState(0);
45
+ const hideButtons = useCallback(() => {
46
+ if (isMainButtonFocused.current) return;
47
+ setShowAdditionalButtons(false);
48
+ }, []);
49
+
50
+ const showButtons = () => {
51
+ setShowAdditionalButtons(true);
52
+ setMinWidth(ref.current.getBoundingClientRect().width);
53
+ };
47
54
 
48
55
  const childrenWithProps = () => {
49
56
  return buttonChildren.map((child, index) => {
@@ -51,7 +58,16 @@ const MultiActionButton = ({
51
58
  key: index.toString(),
52
59
  role: "menuitem",
53
60
  ref: additionalButtons.current[index],
54
- tabIndex: -1
61
+ tabIndex: -1,
62
+ onClick: ev => {
63
+ var _buttonRef$current;
64
+
65
+ if (child.props.onClick) child.props.onClick(ev);
66
+ isMainButtonFocused.current = false;
67
+ hideButtons();
68
+ isFocusedAfterClosing.current = true;
69
+ (_buttonRef$current = buttonRef.current) === null || _buttonRef$current === void 0 ? void 0 : _buttonRef$current.focus();
70
+ }
55
71
  };
56
72
 
57
73
  if (child.type === Button) {
@@ -62,17 +78,6 @@ const MultiActionButton = ({
62
78
  });
63
79
  };
64
80
 
65
- const hideButtons = useCallback(() => {
66
- if (isMainButtonFocused.current) return;
67
- setShowAdditionalButtons(false);
68
- setRemoveHandleClickOutside(true);
69
- /* istanbul ignore else */
70
-
71
- if (listening.current) {
72
- setRemoveHandleKeyDown(true);
73
- listening.current = false;
74
- }
75
- }, []);
76
81
  const handleKeyDown = useCallback(ev => {
77
82
  const currentIndex = additionalButtons.current.findIndex(node => node.current === document.activeElement);
78
83
  let nextIndex = -1;
@@ -85,7 +90,9 @@ const MultiActionButton = ({
85
90
  if (Events.isDownKey(ev)) {
86
91
  nextIndex = currentIndex < children.length - 1 ? currentIndex + 1 : 0;
87
92
  ev.preventDefault();
88
- } else if (Events.isTabKey(ev)) {
93
+ }
94
+
95
+ if (Events.isTabKey(ev)) {
89
96
  var _elements$indexOf;
90
97
 
91
98
  const elements = Array.from(document.querySelectorAll(defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
@@ -98,47 +105,79 @@ const MultiActionButton = ({
98
105
  if (nextIndex > -1) {
99
106
  additionalButtons.current[nextIndex].current.focus();
100
107
  }
101
- }, [children.length, hideButtons]);
108
+ }, [children, hideButtons]);
102
109
  const handleClickOutside = useCallback(({
103
110
  target
104
111
  }) => {
105
112
  if (!ref.current.contains(target) && buttonContainer.current && !buttonContainer.current.contains(target)) {
106
- hideButtons(handleClickOutside, undefined);
113
+ hideButtons();
107
114
  }
108
115
  }, [hideButtons]);
109
-
110
- const showButtons = () => {
111
- document.addEventListener(userInputType, handleClickOutside);
112
- setShowAdditionalButtons(true);
113
- setMinWidth(ref.current.getBoundingClientRect().width);
116
+ const addListeners = useCallback(() => {
114
117
  /* istanbul ignore else */
115
-
116
118
  if (!listening.current) {
119
+ document.addEventListener("click", handleClickOutside);
117
120
  document.addEventListener("keydown", handleKeyDown);
118
121
  listening.current = true;
119
122
  }
120
- };
123
+ }, [handleKeyDown, handleClickOutside]);
124
+ const removeListeners = useCallback(() => {
125
+ /* istanbul ignore else */
126
+ if (listening.current) {
127
+ document.removeEventListener("click", handleClickOutside);
128
+ document.removeEventListener("keydown", handleKeyDown);
129
+ listening.current = false;
130
+ }
131
+ }, [handleKeyDown, handleClickOutside]);
132
+ useEffect(() => {
133
+ if (showAdditionalButtons) {
134
+ addListeners();
135
+ }
136
+
137
+ return () => {
138
+ removeListeners();
139
+ };
140
+ }, [showAdditionalButtons, addListeners, removeListeners]);
121
141
 
122
142
  const handleMainButtonKeyDown = ev => {
123
- if (Events.isEnterKey(ev) || Events.isSpaceKey(ev)) {
124
- additionalButtons.current[0].current.focus();
143
+ if (Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev)) {
144
+ ev.preventDefault();
145
+
146
+ if (!showAdditionalButtons) {
147
+ showButtons();
148
+ } // see if setTimeout could be removed after we update react to v18 thanks to the concurrent mode
149
+
150
+
151
+ setTimeout(() => {
152
+ var _additionalButtons$cu, _additionalButtons$cu2;
153
+
154
+ (_additionalButtons$cu = additionalButtons.current[0]) === null || _additionalButtons$cu === void 0 ? void 0 : (_additionalButtons$cu2 = _additionalButtons$cu.current) === null || _additionalButtons$cu2 === void 0 ? void 0 : _additionalButtons$cu2.focus();
155
+ }, 0);
125
156
  }
126
157
  };
127
158
 
128
159
  const focusMainButton = () => {
129
160
  isMainButtonFocused.current = true;
161
+
162
+ if (isFocusedAfterClosing.current) {
163
+ isFocusedAfterClosing.current = false;
164
+ return;
165
+ }
166
+
130
167
  showButtons();
131
168
  };
132
169
 
170
+ const blurMainButton = () => {
171
+ isMainButtonFocused.current = false;
172
+ };
173
+
133
174
  const mainButtonProps = () => {
134
175
  const opts = {
135
176
  disabled,
136
177
  displayed: showAdditionalButtons,
137
178
  onTouchStart: showButtons,
138
179
  onFocus: focusMainButton,
139
- onBlur: () => {
140
- isMainButtonFocused.current = false;
141
- },
180
+ onBlur: blurMainButton,
142
181
  onKeyDown: handleMainButtonKeyDown,
143
182
  buttonType: buttonType || as,
144
183
  size,
@@ -165,23 +204,6 @@ const MultiActionButton = ({
165
204
  ref: buttonContainer
166
205
  }, childrenWithProps()));
167
206
 
168
- useEffect(() => {
169
- if (removeHandleClickOutside) {
170
- setRemoveHandleClickOutside(false);
171
- document.removeEventListener(userInputType, handleClickOutside);
172
- }
173
-
174
- if (removeHandleKeyDown) {
175
- setRemoveHandleKeyDown(false);
176
- document.removeEventListener("keydown", handleKeyDown);
177
- }
178
- }, [handleClickOutside, handleKeyDown, removeHandleClickOutside, removeHandleKeyDown, userInputType]);
179
- useEffect(() => {
180
- return () => {
181
- document.removeEventListener(userInputType, handleClickOutside);
182
- document.removeEventListener("keydown", handleKeyDown);
183
- };
184
- }, [handleClickOutside, handleKeyDown, userInputType]);
185
207
  return /*#__PURE__*/React.createElement(StyledMultiActionButton, _extends({
186
208
  "aria-haspopup": "true",
187
209
  onMouseLeave: hideButtons,
@@ -18,9 +18,15 @@ const StyledMultiActionButton = styled.div`
18
18
  }
19
19
 
20
20
  &:focus {
21
+ background-color: var(--colorsActionMajor700);
21
22
  border: 3px solid var(--colorsSemanticFocus500);
22
23
  outline: none;
23
- margin: -1px;
24
+ margin: 0 -1px;
25
+
26
+ &,
27
+ ${StyledIcon} {
28
+ color: var(--colorsActionMajorYang100);
29
+ }
24
30
  }
25
31
 
26
32
  ${({
@@ -58,7 +58,8 @@ const PortraitInitials = ({
58
58
  return /*#__PURE__*/React.createElement(StyledPortraitInitials, _extends({
59
59
  "data-element": "initials",
60
60
  size: size,
61
- shape: shape
61
+ shape: shape,
62
+ initials: initials
62
63
  }, rest), /*#__PURE__*/React.createElement(StyledPortraitInitialsImg, {
63
64
  src: generateDataUrl(),
64
65
  alt: alt
@@ -7,7 +7,8 @@ import Icon from "../icon";
7
7
  import { PORTRAIT_SHAPES, PORTRAIT_SIZES, PORTRAIT_SIZE_PARAMS } from "./portrait.config";
8
8
 
9
9
  function stylingForSize({
10
- size
10
+ size,
11
+ initials
11
12
  }) {
12
13
  const params = PORTRAIT_SIZE_PARAMS[size];
13
14
 
@@ -15,6 +16,14 @@ function stylingForSize({
15
16
  return css``;
16
17
  }
17
18
 
19
+ if (initials) {
20
+ return css`
21
+ width: inherit;
22
+ height: inherit;
23
+ margin: 1px;
24
+ `;
25
+ }
26
+
18
27
  return css`
19
28
  width: ${params.dimensions}px;
20
29
  height: ${params.dimensions}px;
@@ -72,7 +81,16 @@ export const StyledPortraitInitials = styled.div`
72
81
  box-sizing: border-box;
73
82
  ${stylingForSize}
74
83
  ${stylingForShape}
75
- border: 1px solid var(--colorsUtilityMajor200);
84
+ outline: 1px solid var(--colorsUtilityMajor200);
85
+
86
+ /* Styling for safari. This ensures that there is no outline on the component but that a border is still present
87
+ to achieve the same styling as Chrome and Firefox */
88
+ @media not all and (min-resolution: 0.001dpcm) {
89
+ @supports (-webkit-appearance: none) and (stroke-color: transparent) {
90
+ border: 1px solid var(--colorsUtilityMajor200);
91
+ outline: none;
92
+ }
93
+ }
76
94
  `;
77
95
  StyledPortraitInitials.propTypes = {
78
96
  size: PropTypes.oneOf(PORTRAIT_SIZES).isRequired,
@@ -53,6 +53,15 @@ const StyledSplitButtonToggle = styled(StyledButton)`
53
53
  ${StyledButton} + & ${StyledIcon} {
54
54
  margin-left: 0;
55
55
  }
56
+
57
+ &:focus {
58
+ background-color: var(--colorsActionMajor500);
59
+
60
+ &,
61
+ ${StyledIcon} {
62
+ color: var(--colorsActionMajorYang100);
63
+ }
64
+ }
56
65
  `}
57
66
  `;
58
67
  export default StyledSplitButtonToggle;
@@ -44,14 +44,16 @@ const SplitButton = ({
44
44
 
45
45
  const theme = useContext(ThemeContext) || baseTheme;
46
46
  const isToggleButtonFocused = useRef(false);
47
+ const isFocusedAfterClosing = useRef(false);
47
48
  const buttonLabelId = useRef(guid());
48
- const additionalButtons = useRef([]);
49
+ const buttonChildren = React.Children.toArray(children);
50
+ const additionalButtons = useRef(buttonChildren.map(() => /*#__PURE__*/React.createRef()));
49
51
  const splitButtonNode = useRef();
50
52
  const toggleButton = useRef();
51
53
  const buttonContainer = useRef();
52
54
  const [showAdditionalButtons, setShowAdditionalButtons] = useState(false);
53
55
  const [minWidth, setMinWidth] = useState(0);
54
- const userInputType = useRef("ontouchstart" in document.documentElement ? "touchstart" : "click");
56
+ const listening = useRef(false);
55
57
  const hideButtons = useCallback(() => {
56
58
  if (isToggleButtonFocused.current) return;
57
59
  setShowAdditionalButtons(false);
@@ -64,12 +66,8 @@ const SplitButton = ({
64
66
  }
65
67
  }, [hideButtons]);
66
68
  const handleKeyDown = useCallback(ev => {
67
- if (!showAdditionalButtons) {
68
- return;
69
- }
70
-
71
69
  const numOfChildren = children.length - 1;
72
- const currentIndex = additionalButtons.current.findIndex(isActiveElement);
70
+ const currentIndex = additionalButtons.current.findIndex(node => node.current === document.activeElement);
73
71
  let nextIndex = -1;
74
72
 
75
73
  if (Events.isUpKey(ev)) {
@@ -80,7 +78,9 @@ const SplitButton = ({
80
78
  if (Events.isDownKey(ev)) {
81
79
  nextIndex = currentIndex < numOfChildren ? currentIndex + 1 : 0;
82
80
  ev.preventDefault();
83
- } else if (Events.isTabKey(ev)) {
81
+ }
82
+
83
+ if (Events.isTabKey(ev)) {
84
84
  var _elements$indexOf;
85
85
 
86
86
  const elements = Array.from(document.querySelectorAll(defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
@@ -91,18 +91,34 @@ const SplitButton = ({
91
91
  }
92
92
 
93
93
  if (nextIndex > -1) {
94
- additionalButtons.current[nextIndex].focus();
94
+ additionalButtons.current[nextIndex].current.focus();
95
95
  }
96
- }, [hideButtons, children, showAdditionalButtons]);
97
- useEffect(() => {
98
- const inputType = userInputType.current;
99
- document.addEventListener(inputType, handleClickOutside);
100
- document.addEventListener("keydown", handleKeyDown);
101
- return function cleanup() {
102
- document.removeEventListener(inputType, handleClickOutside);
96
+ }, [hideButtons, children]);
97
+ const addListeners = useCallback(() => {
98
+ /* istanbul ignore else */
99
+ if (!listening.current) {
100
+ document.addEventListener("click", handleClickOutside);
101
+ document.addEventListener("keydown", handleKeyDown);
102
+ listening.current = true;
103
+ }
104
+ }, [handleKeyDown, handleClickOutside]);
105
+ const removeListeners = useCallback(() => {
106
+ /* istanbul ignore else */
107
+ if (listening.current) {
108
+ document.removeEventListener("click", handleClickOutside);
103
109
  document.removeEventListener("keydown", handleKeyDown);
110
+ listening.current = false;
111
+ }
112
+ }, [handleKeyDown, handleClickOutside]);
113
+ useEffect(() => {
114
+ if (showAdditionalButtons) {
115
+ addListeners();
116
+ }
117
+
118
+ return () => {
119
+ removeListeners();
104
120
  };
105
- }, [handleClickOutside, handleKeyDown]);
121
+ }, [showAdditionalButtons, addListeners, removeListeners]);
106
122
 
107
123
  function mainButtonProps() {
108
124
  return {
@@ -150,11 +166,6 @@ const SplitButton = ({
150
166
  };
151
167
  }
152
168
 
153
- function addRef(ref, index) {
154
- if (!ref) return;
155
- additionalButtons.current[index] = ref;
156
- }
157
-
158
169
  function getIconColor() {
159
170
  const colorsMap = {
160
171
  primary: theme.colors.white,
@@ -191,8 +202,18 @@ const SplitButton = ({
191
202
  }
192
203
 
193
204
  function handleToggleButtonKeyDown(ev) {
194
- if (Events.isEnterKey(ev) || Events.isSpaceKey(ev)) {
195
- additionalButtons.current[0].focus();
205
+ if (Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev)) {
206
+ ev.preventDefault();
207
+
208
+ if (!showAdditionalButtons) {
209
+ showButtons();
210
+ }
211
+
212
+ setTimeout(() => {
213
+ var _additionalButtons$cu, _additionalButtons$cu2;
214
+
215
+ (_additionalButtons$cu = additionalButtons.current[0]) === null || _additionalButtons$cu === void 0 ? void 0 : (_additionalButtons$cu2 = _additionalButtons$cu.current) === null || _additionalButtons$cu2 === void 0 ? void 0 : _additionalButtons$cu2.focus();
216
+ }, 0);
196
217
  }
197
218
  }
198
219
 
@@ -202,8 +223,17 @@ const SplitButton = ({
202
223
  const childProps = {
203
224
  key: index.toString(),
204
225
  role: "menuitem",
205
- ref: button => addRef(button, index),
206
- tabIndex: -1
226
+ ref: additionalButtons.current[index],
227
+ tabIndex: -1,
228
+ onClick: ev => {
229
+ var _toggleButton$current;
230
+
231
+ if (child.props.onClick) child.props.onClick(ev);
232
+ isToggleButtonFocused.current = false;
233
+ hideButtons();
234
+ isFocusedAfterClosing.current = true;
235
+ (_toggleButton$current = toggleButton.current) === null || _toggleButton$current === void 0 ? void 0 : _toggleButton$current.focus();
236
+ }
207
237
  };
208
238
 
209
239
  if (child.type === Button) {
@@ -216,11 +246,13 @@ const SplitButton = ({
216
246
 
217
247
  function focusToggleButton() {
218
248
  isToggleButtonFocused.current = true;
219
- showButtons();
220
- }
221
249
 
222
- function isActiveElement(node) {
223
- return node === document.activeElement;
250
+ if (isFocusedAfterClosing.current) {
251
+ isFocusedAfterClosing.current = false;
252
+ return;
253
+ }
254
+
255
+ showButtons();
224
256
  }
225
257
 
226
258
  function renderAdditionalButtons() {
@@ -103,7 +103,7 @@ export default {
103
103
  inputWidth: 100,
104
104
  warnOverLimit: false,
105
105
  enforceCharacterLimit: true,
106
- label: "",
106
+ label: "Textarea",
107
107
  labelHelp: "",
108
108
  labelInline: false,
109
109
  labelWidth: 30,
@@ -1,5 +1,6 @@
1
1
  import styled, { css } from "styled-components";
2
2
  import { margin } from "styled-system";
3
+ import InputPresentationStyle from "../../__internal__/input/input-presentation.style";
3
4
  import StyledInput from "../../__internal__/input/input.style";
4
5
  import { StyledLabelContainer } from "../../__internal__/label/label.style";
5
6
  import InputIconToggleStyle from "../../__internal__/input-icon-toggle/input-icon-toggle.style";
@@ -11,8 +12,10 @@ const StyledTextarea = styled.div`
11
12
  ${StyledInput} {
12
13
  resize: none;
13
14
  min-height: ${MIN_HEIGHT}px;
14
- margin-top: 5px;
15
- margin-bottom: 5px;
15
+ }
16
+
17
+ ${InputPresentationStyle} {
18
+ padding: var(--spacing150) var(--spacing200);
16
19
  }
17
20
 
18
21
  ${({
@@ -59,17 +59,24 @@ const MultiActionButton = ({
59
59
  const ref = (0, _react.useRef)();
60
60
  const buttonRef = (0, _react.useRef)();
61
61
  const buttonContainer = (0, _react.useRef)();
62
- const userInputType = "ontouchstart" in document.documentElement ? "touchstart" : "click";
63
62
 
64
63
  const buttonChildren = _react.default.Children.toArray(children);
65
64
 
66
65
  const additionalButtons = (0, _react.useRef)(buttonChildren.map(() => /*#__PURE__*/_react.default.createRef()));
67
66
  const listening = (0, _react.useRef)(false);
68
67
  const isMainButtonFocused = (0, _react.useRef)(false);
68
+ const isFocusedAfterClosing = (0, _react.useRef)(false);
69
69
  const [showAdditionalButtons, setShowAdditionalButtons] = (0, _react.useState)(false);
70
- const [removeHandleClickOutside, setRemoveHandleClickOutside] = (0, _react.useState)(false);
71
- const [removeHandleKeyDown, setRemoveHandleKeyDown] = (0, _react.useState)(false);
72
70
  const [minWidth, setMinWidth] = (0, _react.useState)(0);
71
+ const hideButtons = (0, _react.useCallback)(() => {
72
+ if (isMainButtonFocused.current) return;
73
+ setShowAdditionalButtons(false);
74
+ }, []);
75
+
76
+ const showButtons = () => {
77
+ setShowAdditionalButtons(true);
78
+ setMinWidth(ref.current.getBoundingClientRect().width);
79
+ };
73
80
 
74
81
  const childrenWithProps = () => {
75
82
  return buttonChildren.map((child, index) => {
@@ -77,7 +84,16 @@ const MultiActionButton = ({
77
84
  key: index.toString(),
78
85
  role: "menuitem",
79
86
  ref: additionalButtons.current[index],
80
- tabIndex: -1
87
+ tabIndex: -1,
88
+ onClick: ev => {
89
+ var _buttonRef$current;
90
+
91
+ if (child.props.onClick) child.props.onClick(ev);
92
+ isMainButtonFocused.current = false;
93
+ hideButtons();
94
+ isFocusedAfterClosing.current = true;
95
+ (_buttonRef$current = buttonRef.current) === null || _buttonRef$current === void 0 ? void 0 : _buttonRef$current.focus();
96
+ }
81
97
  };
82
98
 
83
99
  if (child.type === _button.default) {
@@ -88,17 +104,6 @@ const MultiActionButton = ({
88
104
  });
89
105
  };
90
106
 
91
- const hideButtons = (0, _react.useCallback)(() => {
92
- if (isMainButtonFocused.current) return;
93
- setShowAdditionalButtons(false);
94
- setRemoveHandleClickOutside(true);
95
- /* istanbul ignore else */
96
-
97
- if (listening.current) {
98
- setRemoveHandleKeyDown(true);
99
- listening.current = false;
100
- }
101
- }, []);
102
107
  const handleKeyDown = (0, _react.useCallback)(ev => {
103
108
  const currentIndex = additionalButtons.current.findIndex(node => node.current === document.activeElement);
104
109
  let nextIndex = -1;
@@ -111,7 +116,9 @@ const MultiActionButton = ({
111
116
  if (_events.default.isDownKey(ev)) {
112
117
  nextIndex = currentIndex < children.length - 1 ? currentIndex + 1 : 0;
113
118
  ev.preventDefault();
114
- } else if (_events.default.isTabKey(ev)) {
119
+ }
120
+
121
+ if (_events.default.isTabKey(ev)) {
115
122
  var _elements$indexOf;
116
123
 
117
124
  const elements = Array.from(document.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
@@ -124,47 +131,79 @@ const MultiActionButton = ({
124
131
  if (nextIndex > -1) {
125
132
  additionalButtons.current[nextIndex].current.focus();
126
133
  }
127
- }, [children.length, hideButtons]);
134
+ }, [children, hideButtons]);
128
135
  const handleClickOutside = (0, _react.useCallback)(({
129
136
  target
130
137
  }) => {
131
138
  if (!ref.current.contains(target) && buttonContainer.current && !buttonContainer.current.contains(target)) {
132
- hideButtons(handleClickOutside, undefined);
139
+ hideButtons();
133
140
  }
134
141
  }, [hideButtons]);
135
-
136
- const showButtons = () => {
137
- document.addEventListener(userInputType, handleClickOutside);
138
- setShowAdditionalButtons(true);
139
- setMinWidth(ref.current.getBoundingClientRect().width);
142
+ const addListeners = (0, _react.useCallback)(() => {
140
143
  /* istanbul ignore else */
141
-
142
144
  if (!listening.current) {
145
+ document.addEventListener("click", handleClickOutside);
143
146
  document.addEventListener("keydown", handleKeyDown);
144
147
  listening.current = true;
145
148
  }
146
- };
149
+ }, [handleKeyDown, handleClickOutside]);
150
+ const removeListeners = (0, _react.useCallback)(() => {
151
+ /* istanbul ignore else */
152
+ if (listening.current) {
153
+ document.removeEventListener("click", handleClickOutside);
154
+ document.removeEventListener("keydown", handleKeyDown);
155
+ listening.current = false;
156
+ }
157
+ }, [handleKeyDown, handleClickOutside]);
158
+ (0, _react.useEffect)(() => {
159
+ if (showAdditionalButtons) {
160
+ addListeners();
161
+ }
162
+
163
+ return () => {
164
+ removeListeners();
165
+ };
166
+ }, [showAdditionalButtons, addListeners, removeListeners]);
147
167
 
148
168
  const handleMainButtonKeyDown = ev => {
149
- if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev)) {
150
- additionalButtons.current[0].current.focus();
169
+ if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev)) {
170
+ ev.preventDefault();
171
+
172
+ if (!showAdditionalButtons) {
173
+ showButtons();
174
+ } // see if setTimeout could be removed after we update react to v18 thanks to the concurrent mode
175
+
176
+
177
+ setTimeout(() => {
178
+ var _additionalButtons$cu, _additionalButtons$cu2;
179
+
180
+ (_additionalButtons$cu = additionalButtons.current[0]) === null || _additionalButtons$cu === void 0 ? void 0 : (_additionalButtons$cu2 = _additionalButtons$cu.current) === null || _additionalButtons$cu2 === void 0 ? void 0 : _additionalButtons$cu2.focus();
181
+ }, 0);
151
182
  }
152
183
  };
153
184
 
154
185
  const focusMainButton = () => {
155
186
  isMainButtonFocused.current = true;
187
+
188
+ if (isFocusedAfterClosing.current) {
189
+ isFocusedAfterClosing.current = false;
190
+ return;
191
+ }
192
+
156
193
  showButtons();
157
194
  };
158
195
 
196
+ const blurMainButton = () => {
197
+ isMainButtonFocused.current = false;
198
+ };
199
+
159
200
  const mainButtonProps = () => {
160
201
  const opts = {
161
202
  disabled,
162
203
  displayed: showAdditionalButtons,
163
204
  onTouchStart: showButtons,
164
205
  onFocus: focusMainButton,
165
- onBlur: () => {
166
- isMainButtonFocused.current = false;
167
- },
206
+ onBlur: blurMainButton,
168
207
  onKeyDown: handleMainButtonKeyDown,
169
208
  buttonType: buttonType || as,
170
209
  size,
@@ -191,23 +230,6 @@ const MultiActionButton = ({
191
230
  ref: buttonContainer
192
231
  }, childrenWithProps()));
193
232
 
194
- (0, _react.useEffect)(() => {
195
- if (removeHandleClickOutside) {
196
- setRemoveHandleClickOutside(false);
197
- document.removeEventListener(userInputType, handleClickOutside);
198
- }
199
-
200
- if (removeHandleKeyDown) {
201
- setRemoveHandleKeyDown(false);
202
- document.removeEventListener("keydown", handleKeyDown);
203
- }
204
- }, [handleClickOutside, handleKeyDown, removeHandleClickOutside, removeHandleKeyDown, userInputType]);
205
- (0, _react.useEffect)(() => {
206
- return () => {
207
- document.removeEventListener(userInputType, handleClickOutside);
208
- document.removeEventListener("keydown", handleKeyDown);
209
- };
210
- }, [handleClickOutside, handleKeyDown, userInputType]);
211
233
  return /*#__PURE__*/_react.default.createElement(_multiActionButton.StyledMultiActionButton, _extends({
212
234
  "aria-haspopup": "true",
213
235
  onMouseLeave: hideButtons,
@@ -36,9 +36,15 @@ const StyledMultiActionButton = _styledComponents.default.div`
36
36
  }
37
37
 
38
38
  &:focus {
39
+ background-color: var(--colorsActionMajor700);
39
40
  border: 3px solid var(--colorsSemanticFocus500);
40
41
  outline: none;
41
- margin: -1px;
42
+ margin: 0 -1px;
43
+
44
+ &,
45
+ ${_icon.default} {
46
+ color: var(--colorsActionMajorYang100);
47
+ }
42
48
  }
43
49
 
44
50
  ${({
@@ -78,7 +78,8 @@ const PortraitInitials = ({
78
78
  return /*#__PURE__*/_react.default.createElement(_portrait.StyledPortraitInitials, _extends({
79
79
  "data-element": "initials",
80
80
  size: size,
81
- shape: shape
81
+ shape: shape,
82
+ initials: initials
82
83
  }, rest), /*#__PURE__*/_react.default.createElement(_portrait.StyledPortraitInitialsImg, {
83
84
  src: generateDataUrl(),
84
85
  alt: alt
@@ -27,7 +27,8 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
27
27
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
28
28
 
29
29
  function stylingForSize({
30
- size
30
+ size,
31
+ initials
31
32
  }) {
32
33
  const params = _portrait.PORTRAIT_SIZE_PARAMS[size];
33
34
 
@@ -35,6 +36,14 @@ function stylingForSize({
35
36
  return (0, _styledComponents.css)``;
36
37
  }
37
38
 
39
+ if (initials) {
40
+ return (0, _styledComponents.css)`
41
+ width: inherit;
42
+ height: inherit;
43
+ margin: 1px;
44
+ `;
45
+ }
46
+
38
47
  return (0, _styledComponents.css)`
39
48
  width: ${params.dimensions}px;
40
49
  height: ${params.dimensions}px;
@@ -93,7 +102,16 @@ const StyledPortraitInitials = _styledComponents.default.div`
93
102
  box-sizing: border-box;
94
103
  ${stylingForSize}
95
104
  ${stylingForShape}
96
- border: 1px solid var(--colorsUtilityMajor200);
105
+ outline: 1px solid var(--colorsUtilityMajor200);
106
+
107
+ /* Styling for safari. This ensures that there is no outline on the component but that a border is still present
108
+ to achieve the same styling as Chrome and Firefox */
109
+ @media not all and (min-resolution: 0.001dpcm) {
110
+ @supports (-webkit-appearance: none) and (stroke-color: transparent) {
111
+ border: 1px solid var(--colorsUtilityMajor200);
112
+ outline: none;
113
+ }
114
+ }
97
115
  `;
98
116
  exports.StyledPortraitInitials = StyledPortraitInitials;
99
117
  StyledPortraitInitials.propTypes = {
@@ -69,6 +69,15 @@ const StyledSplitButtonToggle = (0, _styledComponents.default)(_button.default)`
69
69
  ${_button.default} + & ${_icon.default} {
70
70
  margin-left: 0;
71
71
  }
72
+
73
+ &:focus {
74
+ background-color: var(--colorsActionMajor500);
75
+
76
+ &,
77
+ ${_icon.default} {
78
+ color: var(--colorsActionMajorYang100);
79
+ }
80
+ }
72
81
  `}
73
82
  `;
74
83
  var _default = StyledSplitButtonToggle;
@@ -75,14 +75,18 @@ const SplitButton = ({
75
75
  const theme = (0, _react.useContext)(_styledComponents.ThemeContext) || _themes.baseTheme;
76
76
 
77
77
  const isToggleButtonFocused = (0, _react.useRef)(false);
78
+ const isFocusedAfterClosing = (0, _react.useRef)(false);
78
79
  const buttonLabelId = (0, _react.useRef)((0, _guid.default)());
79
- const additionalButtons = (0, _react.useRef)([]);
80
+
81
+ const buttonChildren = _react.default.Children.toArray(children);
82
+
83
+ const additionalButtons = (0, _react.useRef)(buttonChildren.map(() => /*#__PURE__*/_react.default.createRef()));
80
84
  const splitButtonNode = (0, _react.useRef)();
81
85
  const toggleButton = (0, _react.useRef)();
82
86
  const buttonContainer = (0, _react.useRef)();
83
87
  const [showAdditionalButtons, setShowAdditionalButtons] = (0, _react.useState)(false);
84
88
  const [minWidth, setMinWidth] = (0, _react.useState)(0);
85
- const userInputType = (0, _react.useRef)("ontouchstart" in document.documentElement ? "touchstart" : "click");
89
+ const listening = (0, _react.useRef)(false);
86
90
  const hideButtons = (0, _react.useCallback)(() => {
87
91
  if (isToggleButtonFocused.current) return;
88
92
  setShowAdditionalButtons(false);
@@ -95,12 +99,8 @@ const SplitButton = ({
95
99
  }
96
100
  }, [hideButtons]);
97
101
  const handleKeyDown = (0, _react.useCallback)(ev => {
98
- if (!showAdditionalButtons) {
99
- return;
100
- }
101
-
102
102
  const numOfChildren = children.length - 1;
103
- const currentIndex = additionalButtons.current.findIndex(isActiveElement);
103
+ const currentIndex = additionalButtons.current.findIndex(node => node.current === document.activeElement);
104
104
  let nextIndex = -1;
105
105
 
106
106
  if (_events.default.isUpKey(ev)) {
@@ -111,7 +111,9 @@ const SplitButton = ({
111
111
  if (_events.default.isDownKey(ev)) {
112
112
  nextIndex = currentIndex < numOfChildren ? currentIndex + 1 : 0;
113
113
  ev.preventDefault();
114
- } else if (_events.default.isTabKey(ev)) {
114
+ }
115
+
116
+ if (_events.default.isTabKey(ev)) {
115
117
  var _elements$indexOf;
116
118
 
117
119
  const elements = Array.from(document.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
@@ -122,18 +124,34 @@ const SplitButton = ({
122
124
  }
123
125
 
124
126
  if (nextIndex > -1) {
125
- additionalButtons.current[nextIndex].focus();
127
+ additionalButtons.current[nextIndex].current.focus();
126
128
  }
127
- }, [hideButtons, children, showAdditionalButtons]);
128
- (0, _react.useEffect)(() => {
129
- const inputType = userInputType.current;
130
- document.addEventListener(inputType, handleClickOutside);
131
- document.addEventListener("keydown", handleKeyDown);
132
- return function cleanup() {
133
- document.removeEventListener(inputType, handleClickOutside);
129
+ }, [hideButtons, children]);
130
+ const addListeners = (0, _react.useCallback)(() => {
131
+ /* istanbul ignore else */
132
+ if (!listening.current) {
133
+ document.addEventListener("click", handleClickOutside);
134
+ document.addEventListener("keydown", handleKeyDown);
135
+ listening.current = true;
136
+ }
137
+ }, [handleKeyDown, handleClickOutside]);
138
+ const removeListeners = (0, _react.useCallback)(() => {
139
+ /* istanbul ignore else */
140
+ if (listening.current) {
141
+ document.removeEventListener("click", handleClickOutside);
134
142
  document.removeEventListener("keydown", handleKeyDown);
143
+ listening.current = false;
144
+ }
145
+ }, [handleKeyDown, handleClickOutside]);
146
+ (0, _react.useEffect)(() => {
147
+ if (showAdditionalButtons) {
148
+ addListeners();
149
+ }
150
+
151
+ return () => {
152
+ removeListeners();
135
153
  };
136
- }, [handleClickOutside, handleKeyDown]);
154
+ }, [showAdditionalButtons, addListeners, removeListeners]);
137
155
 
138
156
  function mainButtonProps() {
139
157
  return {
@@ -181,11 +199,6 @@ const SplitButton = ({
181
199
  };
182
200
  }
183
201
 
184
- function addRef(ref, index) {
185
- if (!ref) return;
186
- additionalButtons.current[index] = ref;
187
- }
188
-
189
202
  function getIconColor() {
190
203
  const colorsMap = {
191
204
  primary: theme.colors.white,
@@ -222,8 +235,18 @@ const SplitButton = ({
222
235
  }
223
236
 
224
237
  function handleToggleButtonKeyDown(ev) {
225
- if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev)) {
226
- additionalButtons.current[0].focus();
238
+ if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev)) {
239
+ ev.preventDefault();
240
+
241
+ if (!showAdditionalButtons) {
242
+ showButtons();
243
+ }
244
+
245
+ setTimeout(() => {
246
+ var _additionalButtons$cu, _additionalButtons$cu2;
247
+
248
+ (_additionalButtons$cu = additionalButtons.current[0]) === null || _additionalButtons$cu === void 0 ? void 0 : (_additionalButtons$cu2 = _additionalButtons$cu.current) === null || _additionalButtons$cu2 === void 0 ? void 0 : _additionalButtons$cu2.focus();
249
+ }, 0);
227
250
  }
228
251
  }
229
252
 
@@ -233,8 +256,17 @@ const SplitButton = ({
233
256
  const childProps = {
234
257
  key: index.toString(),
235
258
  role: "menuitem",
236
- ref: button => addRef(button, index),
237
- tabIndex: -1
259
+ ref: additionalButtons.current[index],
260
+ tabIndex: -1,
261
+ onClick: ev => {
262
+ var _toggleButton$current;
263
+
264
+ if (child.props.onClick) child.props.onClick(ev);
265
+ isToggleButtonFocused.current = false;
266
+ hideButtons();
267
+ isFocusedAfterClosing.current = true;
268
+ (_toggleButton$current = toggleButton.current) === null || _toggleButton$current === void 0 ? void 0 : _toggleButton$current.focus();
269
+ }
238
270
  };
239
271
 
240
272
  if (child.type === _button.default) {
@@ -247,11 +279,13 @@ const SplitButton = ({
247
279
 
248
280
  function focusToggleButton() {
249
281
  isToggleButtonFocused.current = true;
250
- showButtons();
251
- }
252
282
 
253
- function isActiveElement(node) {
254
- return node === document.activeElement;
283
+ if (isFocusedAfterClosing.current) {
284
+ isFocusedAfterClosing.current = false;
285
+ return;
286
+ }
287
+
288
+ showButtons();
255
289
  }
256
290
 
257
291
  function renderAdditionalButtons() {
@@ -118,7 +118,7 @@ var _default = {
118
118
  inputWidth: 100,
119
119
  warnOverLimit: false,
120
120
  enforceCharacterLimit: true,
121
- label: "",
121
+ label: "Textarea",
122
122
  labelHelp: "",
123
123
  labelInline: false,
124
124
  labelWidth: 30,
@@ -9,6 +9,8 @@ var _styledComponents = _interopRequireWildcard(require("styled-components"));
9
9
 
10
10
  var _styledSystem = require("styled-system");
11
11
 
12
+ var _inputPresentation = _interopRequireDefault(require("../../__internal__/input/input-presentation.style"));
13
+
12
14
  var _input = _interopRequireDefault(require("../../__internal__/input/input.style"));
13
15
 
14
16
  var _label = require("../../__internal__/label/label.style");
@@ -31,8 +33,10 @@ const StyledTextarea = _styledComponents.default.div`
31
33
  ${_input.default} {
32
34
  resize: none;
33
35
  min-height: ${MIN_HEIGHT}px;
34
- margin-top: 5px;
35
- margin-bottom: 5px;
36
+ }
37
+
38
+ ${_inputPresentation.default} {
39
+ padding: var(--spacing150) var(--spacing200);
36
40
  }
37
41
 
38
42
  ${({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "106.4.1",
3
+ "version": "106.6.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "engineStrict": true,
6
6
  "engines": {
@@ -164,7 +164,7 @@
164
164
  },
165
165
  "dependencies": {
166
166
  "@octokit/rest": "^18.12.0",
167
- "@popperjs/core": "^2.11.2",
167
+ "@popperjs/core": "^2.11.5",
168
168
  "@styled-system/prop-types": "^5.1.5",
169
169
  "@tippyjs/react": "^4.2.5",
170
170
  "@types/styled-system": "^5.1.11",