carbon-react 119.9.2 → 119.9.3
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.
- package/esm/components/button/button.component.js +8 -1
- package/esm/components/multi-action-button/multi-action-button.component.js +21 -68
- package/esm/components/split-button/__internal__/split-button.context.d.ts +7 -0
- package/esm/components/split-button/__internal__/split-button.context.js +4 -0
- package/esm/components/split-button/split-button.component.js +20 -61
- package/esm/hooks/__internal__/useChildButtons/index.d.ts +1 -0
- package/esm/hooks/__internal__/useChildButtons/index.js +1 -0
- package/esm/hooks/__internal__/useChildButtons/useChildButtons.d.ts +21 -0
- package/esm/hooks/__internal__/useChildButtons/useChildButtons.js +71 -0
- package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +1 -1
- package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +8 -7
- package/lib/components/button/button.component.js +8 -1
- package/lib/components/multi-action-button/multi-action-button.component.js +20 -67
- package/lib/components/split-button/__internal__/split-button.context.d.ts +7 -0
- package/lib/components/split-button/__internal__/split-button.context.js +12 -0
- package/lib/components/split-button/split-button.component.js +19 -60
- package/lib/hooks/__internal__/useChildButtons/index.d.ts +1 -0
- package/lib/hooks/__internal__/useChildButtons/index.js +13 -0
- package/lib/hooks/__internal__/useChildButtons/package.json +6 -0
- package/lib/hooks/__internal__/useChildButtons/useChildButtons.d.ts +21 -0
- package/lib/hooks/__internal__/useChildButtons/useChildButtons.js +79 -0
- package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +1 -1
- package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +7 -6
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import tagComponent from "../../__internal__/utils/helpers/tags/tags";
|
|
|
8
8
|
import { TooltipProvider } from "../../__internal__/tooltip-provider";
|
|
9
9
|
import Logger from "../../__internal__/utils/logger";
|
|
10
10
|
import { ButtonBarContext } from "../button-bar/button-bar.component";
|
|
11
|
+
import SplitButtonContext from "../split-button/__internal__/split-button.context";
|
|
11
12
|
function renderChildren(_ref) {
|
|
12
13
|
let {
|
|
13
14
|
/* eslint-disable react/prop-types */
|
|
@@ -79,6 +80,7 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
79
80
|
iconTooltipMessage,
|
|
80
81
|
iconTooltipPosition,
|
|
81
82
|
fullWidth: fullWidthProp = false,
|
|
83
|
+
onClick,
|
|
82
84
|
...rest
|
|
83
85
|
} = _ref2;
|
|
84
86
|
const {
|
|
@@ -104,6 +106,10 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
104
106
|
Logger.deprecate("The `dashed` variant of the `buttonType` prop for `Button` component is deprecated and will soon be removed.");
|
|
105
107
|
}
|
|
106
108
|
const [internalRef, setInternalRef] = useState();
|
|
109
|
+
const {
|
|
110
|
+
inSplitButton,
|
|
111
|
+
onChildButtonClick
|
|
112
|
+
} = useContext(SplitButtonContext);
|
|
107
113
|
let paddingX;
|
|
108
114
|
const handleLinkKeyDown = event => {
|
|
109
115
|
// If space key click link
|
|
@@ -134,11 +140,12 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
134
140
|
"aria-label": !isValidChildren && iconType ? ariaLabel || iconType : ariaLabel,
|
|
135
141
|
as: !disabled && href ? "a" : "button",
|
|
136
142
|
onKeyDown: href ? handleLinkKeyDown : undefined,
|
|
143
|
+
onClick: inSplitButton ? onChildButtonClick?.(onClick) : onClick,
|
|
137
144
|
draggable: false,
|
|
138
145
|
buttonType: buttonType,
|
|
139
146
|
disabled: disabled,
|
|
140
147
|
destructive: destructive,
|
|
141
|
-
role: "button",
|
|
148
|
+
role: inSplitButton ? "menu-item" : "button",
|
|
142
149
|
type: href ? undefined : "button",
|
|
143
150
|
iconType: iconType,
|
|
144
151
|
size: size,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); }
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useRef } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import useClickAwayListener from "../../hooks/__internal__/useClickAwayListener";
|
|
5
|
+
import SplitButtonContext from "../split-button/__internal__/split-button.context";
|
|
5
6
|
import { StyledMultiActionButton, StyledButtonChildrenContainer } from "./multi-action-button.style";
|
|
6
7
|
import Button from "../button";
|
|
7
|
-
import Events from "../../__internal__/utils/helpers/events";
|
|
8
8
|
import Popover from "../../__internal__/popover";
|
|
9
9
|
import { filterStyledSystemMarginProps, filterOutStyledSystemSpacingProps } from "../../style/utils";
|
|
10
|
-
import
|
|
10
|
+
import useChildButtons from "../../hooks/__internal__/useChildButtons";
|
|
11
11
|
export const MultiActionButton = _ref => {
|
|
12
12
|
let {
|
|
13
13
|
align = "left",
|
|
@@ -23,57 +23,17 @@ export const MultiActionButton = _ref => {
|
|
|
23
23
|
"data-role": dataRole,
|
|
24
24
|
...rest
|
|
25
25
|
} = _ref;
|
|
26
|
-
const ref = useRef(null);
|
|
27
26
|
const buttonRef = useRef(null);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/* istanbul ignore else */
|
|
40
|
-
if (ref.current) {
|
|
41
|
-
setMinWidth(ref.current.getBoundingClientRect().width);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const childrenWithProps = () => {
|
|
45
|
-
return buttonChildren.map((child, index) => {
|
|
46
|
-
if (! /*#__PURE__*/React.isValidElement(child)) {
|
|
47
|
-
return child;
|
|
48
|
-
}
|
|
49
|
-
const props = {
|
|
50
|
-
key: index.toString(),
|
|
51
|
-
role: "menuitem",
|
|
52
|
-
ref: buttonChildrenRefs[index],
|
|
53
|
-
tabIndex: -1,
|
|
54
|
-
onClick: ev => {
|
|
55
|
-
if (child.props.onClick) child.props.onClick(ev);
|
|
56
|
-
hideButtons();
|
|
57
|
-
buttonRef.current?.focus();
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
return /*#__PURE__*/React.cloneElement(child, props);
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
const handleKeyDown = useMenuKeyboardNavigation(buttonRef, buttonChildrenRefs, hideButtons, showAdditionalButtons);
|
|
64
|
-
const handleMainButtonKeyDown = ev => {
|
|
65
|
-
if (Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev) || Events.isUpKey(ev)) {
|
|
66
|
-
ev.preventDefault();
|
|
67
|
-
if (!showAdditionalButtons) {
|
|
68
|
-
showButtons();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// see if setTimeout could be removed after we update react to v18 thanks to the concurrent mode
|
|
72
|
-
setTimeout(() => {
|
|
73
|
-
buttonChildrenRefs[0]?.current?.focus();
|
|
74
|
-
}, 0);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
27
|
+
const {
|
|
28
|
+
showAdditionalButtons,
|
|
29
|
+
showButtons,
|
|
30
|
+
hideButtons,
|
|
31
|
+
buttonNode,
|
|
32
|
+
hideButtonsIfTriggerNotFocused,
|
|
33
|
+
handleToggleButtonKeyDown,
|
|
34
|
+
wrapperProps,
|
|
35
|
+
contextValue
|
|
36
|
+
} = useChildButtons(buttonRef);
|
|
77
37
|
const handleInsideClick = useClickAwayListener(hideButtons);
|
|
78
38
|
const handleClick = ev => {
|
|
79
39
|
showButtons();
|
|
@@ -86,7 +46,7 @@ export const MultiActionButton = _ref => {
|
|
|
86
46
|
disabled,
|
|
87
47
|
displayed: showAdditionalButtons,
|
|
88
48
|
onTouchStart: showButtons,
|
|
89
|
-
onKeyDown:
|
|
49
|
+
onKeyDown: handleToggleButtonKeyDown,
|
|
90
50
|
onClick: handleClick,
|
|
91
51
|
buttonType,
|
|
92
52
|
size,
|
|
@@ -98,24 +58,17 @@ export const MultiActionButton = _ref => {
|
|
|
98
58
|
};
|
|
99
59
|
const renderAdditionalButtons = () => /*#__PURE__*/React.createElement(Popover, {
|
|
100
60
|
placement: "bottom-end",
|
|
101
|
-
reference:
|
|
102
|
-
}, /*#__PURE__*/React.createElement(StyledButtonChildrenContainer, {
|
|
103
|
-
role: "menu",
|
|
61
|
+
reference: buttonNode
|
|
62
|
+
}, /*#__PURE__*/React.createElement(StyledButtonChildrenContainer, _extends({}, wrapperProps, {
|
|
104
63
|
"aria-label": text,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
onKeyDown: handleKeyDown
|
|
110
|
-
}, childrenWithProps()));
|
|
111
|
-
const hideButtonsIfTriggerNotFocused = useCallback(() => {
|
|
112
|
-
if (buttonRef.current === document.activeElement) return;
|
|
113
|
-
setShowAdditionalButtons(false);
|
|
114
|
-
}, []);
|
|
64
|
+
align: align
|
|
65
|
+
}), /*#__PURE__*/React.createElement(SplitButtonContext.Provider, {
|
|
66
|
+
value: contextValue
|
|
67
|
+
}, children)));
|
|
115
68
|
const marginProps = filterStyledSystemMarginProps(rest);
|
|
116
69
|
return /*#__PURE__*/React.createElement(StyledMultiActionButton, _extends({
|
|
117
70
|
onMouseLeave: hideButtonsIfTriggerNotFocused,
|
|
118
|
-
ref:
|
|
71
|
+
ref: buttonNode,
|
|
119
72
|
"data-component": "multi-action-button",
|
|
120
73
|
"data-element": dataElement,
|
|
121
74
|
"data-role": dataRole,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface SplitButtonContextProps {
|
|
3
|
+
inSplitButton: boolean;
|
|
4
|
+
onChildButtonClick?: (childOnClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>) => React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> | undefined;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: React.Context<SplitButtonContextProps>;
|
|
7
|
+
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); }
|
|
2
|
-
import React, { useContext,
|
|
2
|
+
import React, { useContext, useRef } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { ThemeContext } from "styled-components";
|
|
5
5
|
import useClickAwayListener from "../../hooks/__internal__/useClickAwayListener";
|
|
@@ -8,12 +8,12 @@ import Button from "../button";
|
|
|
8
8
|
import StyledSplitButton from "./split-button.style";
|
|
9
9
|
import StyledSplitButtonToggle from "./split-button-toggle.style";
|
|
10
10
|
import StyledSplitButtonChildrenContainer from "./split-button-children.style";
|
|
11
|
-
import Events from "../../__internal__/utils/helpers/events";
|
|
12
11
|
import guid from "../../__internal__/utils/helpers/guid";
|
|
13
12
|
import Popover from "../../__internal__/popover";
|
|
14
13
|
import { filterStyledSystemMarginProps, filterOutStyledSystemSpacingProps } from "../../style/utils";
|
|
15
14
|
import { baseTheme } from "../../style/themes";
|
|
16
|
-
import
|
|
15
|
+
import useChildButtons from "../../hooks/__internal__/useChildButtons";
|
|
16
|
+
import SplitButtonContext from "./__internal__/split-button.context";
|
|
17
17
|
const CONTENT_WIDTH_RATIO = 0.75;
|
|
18
18
|
export const SplitButton = _ref => {
|
|
19
19
|
let {
|
|
@@ -33,39 +33,17 @@ export const SplitButton = _ref => {
|
|
|
33
33
|
} = _ref;
|
|
34
34
|
const theme = useContext(ThemeContext) || baseTheme;
|
|
35
35
|
const buttonLabelId = useRef(guid());
|
|
36
|
-
const buttonChildren = useMemo(() => React.Children.toArray(children), [children]);
|
|
37
|
-
const buttonChildrenRefs = useMemo(() => buttonChildren.map(() => /*#__PURE__*/React.createRef()), [buttonChildren]);
|
|
38
|
-
const splitButtonNode = useRef(null);
|
|
39
36
|
const toggleButton = useRef(null);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (splitButtonNode.current) {
|
|
51
|
-
setMinWidth(CONTENT_WIDTH_RATIO * splitButtonNode.current.getBoundingClientRect().width);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function handleToggleButtonKeyDown(ev) {
|
|
55
|
-
if (Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev) || Events.isUpKey(ev)) {
|
|
56
|
-
ev.preventDefault();
|
|
57
|
-
if (!showAdditionalButtons) {
|
|
58
|
-
showButtons();
|
|
59
|
-
}
|
|
60
|
-
setTimeout(() => {
|
|
61
|
-
buttonChildrenRefs[0]?.current?.focus();
|
|
62
|
-
}, 0);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const hideButtonsIfTriggerNotFocused = useCallback(() => {
|
|
66
|
-
if (toggleButton.current === document.activeElement) return;
|
|
67
|
-
setShowAdditionalButtons(false);
|
|
68
|
-
}, []);
|
|
37
|
+
const {
|
|
38
|
+
showAdditionalButtons,
|
|
39
|
+
showButtons,
|
|
40
|
+
hideButtons,
|
|
41
|
+
buttonNode,
|
|
42
|
+
hideButtonsIfTriggerNotFocused,
|
|
43
|
+
handleToggleButtonKeyDown,
|
|
44
|
+
wrapperProps,
|
|
45
|
+
contextValue
|
|
46
|
+
} = useChildButtons(toggleButton, CONTENT_WIDTH_RATIO);
|
|
69
47
|
const mainButtonProps = {
|
|
70
48
|
onMouseEnter: hideButtonsIfTriggerNotFocused,
|
|
71
49
|
onFocus: hideButtonsIfTriggerNotFocused,
|
|
@@ -126,43 +104,24 @@ export const SplitButton = _ref => {
|
|
|
126
104
|
disabled: disabled
|
|
127
105
|
}))];
|
|
128
106
|
}
|
|
129
|
-
function childrenWithProps() {
|
|
130
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
131
|
-
return childArray.filter(Boolean).map((child, index) => {
|
|
132
|
-
const childProps = {
|
|
133
|
-
key: index.toString(),
|
|
134
|
-
role: "menuitem",
|
|
135
|
-
ref: buttonChildrenRefs[index],
|
|
136
|
-
tabIndex: -1,
|
|
137
|
-
onClick: ev => {
|
|
138
|
-
if (child.props.onClick) child.props.onClick(ev);
|
|
139
|
-
hideButtons();
|
|
140
|
-
toggleButton.current?.focus();
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
return /*#__PURE__*/React.cloneElement(child, childProps);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
107
|
function renderAdditionalButtons() {
|
|
147
108
|
if (!showAdditionalButtons) return null;
|
|
148
109
|
return /*#__PURE__*/React.createElement(Popover, {
|
|
149
110
|
placement: "bottom-end",
|
|
150
|
-
reference:
|
|
151
|
-
}, /*#__PURE__*/React.createElement(StyledSplitButtonChildrenContainer, {
|
|
152
|
-
role: "menu",
|
|
111
|
+
reference: buttonNode
|
|
112
|
+
}, /*#__PURE__*/React.createElement(StyledSplitButtonChildrenContainer, _extends({}, wrapperProps, {
|
|
153
113
|
"aria-label": text,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}, childrenWithProps()));
|
|
114
|
+
align: align
|
|
115
|
+
}), /*#__PURE__*/React.createElement(SplitButtonContext.Provider, {
|
|
116
|
+
value: contextValue
|
|
117
|
+
}, children)));
|
|
159
118
|
}
|
|
160
119
|
const handleClick = useClickAwayListener(hideButtons);
|
|
161
120
|
const marginProps = filterStyledSystemMarginProps(rest);
|
|
162
121
|
return /*#__PURE__*/React.createElement(StyledSplitButton, _extends({
|
|
163
122
|
onMouseLeave: hideButtonsIfTriggerNotFocused,
|
|
164
123
|
onClick: handleClick,
|
|
165
|
-
ref:
|
|
124
|
+
ref: buttonNode
|
|
166
125
|
}, componentTags(), marginProps), renderMainButton(), renderAdditionalButtons());
|
|
167
126
|
};
|
|
168
127
|
export default SplitButton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./useChildButtons";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./useChildButtons";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
declare const useChildButtons: (toggleButtonRef: React.RefObject<HTMLButtonElement>, widthRatio?: number) => {
|
|
3
|
+
showAdditionalButtons: boolean;
|
|
4
|
+
showButtons: () => void;
|
|
5
|
+
hideButtons: () => void;
|
|
6
|
+
buttonNode: import("react").RefObject<HTMLDivElement>;
|
|
7
|
+
hideButtonsIfTriggerNotFocused: () => void;
|
|
8
|
+
handleToggleButtonKeyDown: (ev: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
9
|
+
wrapperProps: {
|
|
10
|
+
role: string;
|
|
11
|
+
"data-element": string;
|
|
12
|
+
onKeyDown: (ev: any) => void;
|
|
13
|
+
minWidth: number;
|
|
14
|
+
ref: import("react").RefObject<HTMLDivElement>;
|
|
15
|
+
};
|
|
16
|
+
contextValue: {
|
|
17
|
+
inSplitButton: boolean;
|
|
18
|
+
onChildButtonClick: (childOnClick?: React.MouseEventHandler<HTMLButtonElement>) => (ev: React.MouseEvent<HTMLButtonElement>) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export default useChildButtons;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
+
import Events from "../../../__internal__/utils/helpers/events";
|
|
3
|
+
import useMenuKeyboardNavigation from "../useMenuKeyboardNavigation";
|
|
4
|
+
const useChildButtons = function (toggleButtonRef) {
|
|
5
|
+
let widthRatio = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
6
|
+
const [showAdditionalButtons, setShowAdditionalButtons] = useState(false);
|
|
7
|
+
const [minWidth, setMinWidth] = useState(0);
|
|
8
|
+
const buttonNode = useRef(null);
|
|
9
|
+
const childrenContainer = useRef(null);
|
|
10
|
+
const focusFirstChildButtonOnOpen = useRef(false);
|
|
11
|
+
const hideButtons = useCallback(() => {
|
|
12
|
+
setShowAdditionalButtons(false);
|
|
13
|
+
}, []);
|
|
14
|
+
function showButtons() {
|
|
15
|
+
setShowAdditionalButtons(true);
|
|
16
|
+
|
|
17
|
+
/* istanbul ignore else */
|
|
18
|
+
if (buttonNode.current) {
|
|
19
|
+
setMinWidth(widthRatio * buttonNode.current.getBoundingClientRect().width);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const getButtonChildren = useCallback(() => childrenContainer.current?.querySelectorAll('[data-component="button"]'), []);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const firstChild = getButtonChildren()?.[0];
|
|
25
|
+
if (focusFirstChildButtonOnOpen.current && showAdditionalButtons && firstChild) {
|
|
26
|
+
focusFirstChildButtonOnOpen.current = false;
|
|
27
|
+
firstChild.focus();
|
|
28
|
+
}
|
|
29
|
+
}, [showAdditionalButtons, getButtonChildren]);
|
|
30
|
+
const handleToggleButtonKeyDown = ev => {
|
|
31
|
+
if (Events.isEnterKey(ev) || Events.isSpaceKey(ev) || Events.isDownKey(ev) || Events.isUpKey(ev)) {
|
|
32
|
+
ev.preventDefault();
|
|
33
|
+
if (!showAdditionalButtons) {
|
|
34
|
+
showButtons();
|
|
35
|
+
}
|
|
36
|
+
focusFirstChildButtonOnOpen.current = true;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const handleKeyDown = useMenuKeyboardNavigation(toggleButtonRef, getButtonChildren, hideButtons, showAdditionalButtons);
|
|
40
|
+
const onChildButtonClick = childOnClick => ev => {
|
|
41
|
+
childOnClick?.(ev);
|
|
42
|
+
hideButtons();
|
|
43
|
+
toggleButtonRef.current?.focus();
|
|
44
|
+
};
|
|
45
|
+
const hideButtonsIfTriggerNotFocused = useCallback(() => {
|
|
46
|
+
if (toggleButtonRef.current === document.activeElement) return;
|
|
47
|
+
setShowAdditionalButtons(false);
|
|
48
|
+
}, [toggleButtonRef]);
|
|
49
|
+
const wrapperProps = {
|
|
50
|
+
role: "menu",
|
|
51
|
+
"data-element": "additional-buttons",
|
|
52
|
+
onKeyDown: handleKeyDown,
|
|
53
|
+
minWidth,
|
|
54
|
+
ref: childrenContainer
|
|
55
|
+
};
|
|
56
|
+
const contextValue = {
|
|
57
|
+
inSplitButton: true,
|
|
58
|
+
onChildButtonClick
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
showAdditionalButtons,
|
|
62
|
+
showButtons,
|
|
63
|
+
hideButtons,
|
|
64
|
+
buttonNode,
|
|
65
|
+
hideButtonsIfTriggerNotFocused,
|
|
66
|
+
handleToggleButtonKeyDown,
|
|
67
|
+
wrapperProps,
|
|
68
|
+
contextValue
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export default useChildButtons;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (mainControlRef: React.RefObject<HTMLButtonElement>,
|
|
1
|
+
declare const _default: (mainControlRef: React.RefObject<HTMLButtonElement>, getButtonChildren: () => NodeListOf<HTMLButtonElement>, hide: () => void, isOpen: boolean) => (ev: any) => void;
|
|
2
2
|
export default _default;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { useCallback
|
|
1
|
+
import { useCallback } from "react";
|
|
2
2
|
import Events from "../../../__internal__/utils/helpers/events";
|
|
3
3
|
import { defaultFocusableSelectors } from "../../../__internal__/focus-trap/focus-trap-utils";
|
|
4
4
|
import useModalManager from "../useModalManager";
|
|
5
|
-
export default ((mainControlRef,
|
|
6
|
-
const childrenLength = useMemo(() => childrenRefs.length, [childrenRefs]);
|
|
5
|
+
export default ((mainControlRef, getButtonChildren, hide, isOpen) => {
|
|
7
6
|
const refocusMainControl = useCallback(() => {
|
|
8
7
|
hide();
|
|
9
8
|
mainControlRef.current?.focus();
|
|
@@ -26,8 +25,10 @@ export default ((mainControlRef, childrenRefs, hide, isOpen) => {
|
|
|
26
25
|
if (!(Events.isEnterKey(ev) || Events.isSpaceKey(ev))) {
|
|
27
26
|
ev.preventDefault();
|
|
28
27
|
}
|
|
29
|
-
const
|
|
28
|
+
const buttonChildren = getButtonChildren();
|
|
29
|
+
const childrenLength = buttonChildren?.length;
|
|
30
30
|
let nextIndex = -1;
|
|
31
|
+
const currentIndex = Array.from(buttonChildren).indexOf(document.activeElement);
|
|
31
32
|
const arrowModifierPressed = ev.ctrlKey || ev.metaKey;
|
|
32
33
|
if (Events.isEndKey(ev) || arrowModifierPressed && Events.isDownKey(ev)) {
|
|
33
34
|
nextIndex = childrenLength - 1;
|
|
@@ -54,15 +55,15 @@ export default ((mainControlRef, childrenRefs, hide, isOpen) => {
|
|
|
54
55
|
const elements = Array.from(document.querySelectorAll(defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
|
|
55
56
|
const indexOf = elements.indexOf(mainControlRef.current);
|
|
56
57
|
elements[indexOf + 1]?.focus();
|
|
57
|
-
//
|
|
58
|
+
// timeout enforces that the "hide" method will be run after browser focuses on the next element
|
|
58
59
|
setTimeout(hide, 0);
|
|
59
60
|
} else {
|
|
60
61
|
nextIndex = currentIndex + 1;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
if (nextIndex > -1) {
|
|
64
|
-
|
|
65
|
+
buttonChildren?.[nextIndex]?.focus();
|
|
65
66
|
}
|
|
66
|
-
}, [
|
|
67
|
+
}, [hide, refocusMainControl, mainControlRef, getButtonChildren]);
|
|
67
68
|
return handleKeyDown;
|
|
68
69
|
});
|
|
@@ -13,6 +13,7 @@ var _tags = _interopRequireDefault(require("../../__internal__/utils/helpers/tag
|
|
|
13
13
|
var _tooltipProvider = require("../../__internal__/tooltip-provider");
|
|
14
14
|
var _logger = _interopRequireDefault(require("../../__internal__/utils/logger"));
|
|
15
15
|
var _buttonBar = require("../button-bar/button-bar.component");
|
|
16
|
+
var _splitButton = _interopRequireDefault(require("../split-button/__internal__/split-button.context"));
|
|
16
17
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
18
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
18
19
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; }
|
|
@@ -88,6 +89,7 @@ const Button = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
88
89
|
iconTooltipMessage,
|
|
89
90
|
iconTooltipPosition,
|
|
90
91
|
fullWidth: fullWidthProp = false,
|
|
92
|
+
onClick,
|
|
91
93
|
...rest
|
|
92
94
|
} = _ref2;
|
|
93
95
|
const {
|
|
@@ -113,6 +115,10 @@ const Button = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
113
115
|
_logger.default.deprecate("The `dashed` variant of the `buttonType` prop for `Button` component is deprecated and will soon be removed.");
|
|
114
116
|
}
|
|
115
117
|
const [internalRef, setInternalRef] = (0, _react.useState)();
|
|
118
|
+
const {
|
|
119
|
+
inSplitButton,
|
|
120
|
+
onChildButtonClick
|
|
121
|
+
} = (0, _react.useContext)(_splitButton.default);
|
|
116
122
|
let paddingX;
|
|
117
123
|
const handleLinkKeyDown = event => {
|
|
118
124
|
// If space key click link
|
|
@@ -143,11 +149,12 @@ const Button = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
143
149
|
"aria-label": !isValidChildren && iconType ? ariaLabel || iconType : ariaLabel,
|
|
144
150
|
as: !disabled && href ? "a" : "button",
|
|
145
151
|
onKeyDown: href ? handleLinkKeyDown : undefined,
|
|
152
|
+
onClick: inSplitButton ? onChildButtonClick?.(onClick) : onClick,
|
|
146
153
|
draggable: false,
|
|
147
154
|
buttonType: buttonType,
|
|
148
155
|
disabled: disabled,
|
|
149
156
|
destructive: destructive,
|
|
150
|
-
role: "button",
|
|
157
|
+
role: inSplitButton ? "menu-item" : "button",
|
|
151
158
|
type: href ? undefined : "button",
|
|
152
159
|
iconType: iconType,
|
|
153
160
|
size: size,
|
|
@@ -7,12 +7,12 @@ exports.default = exports.MultiActionButton = void 0;
|
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
9
|
var _useClickAwayListener = _interopRequireDefault(require("../../hooks/__internal__/useClickAwayListener"));
|
|
10
|
+
var _splitButton = _interopRequireDefault(require("../split-button/__internal__/split-button.context"));
|
|
10
11
|
var _multiActionButton = require("./multi-action-button.style");
|
|
11
12
|
var _button = _interopRequireDefault(require("../button"));
|
|
12
|
-
var _events = _interopRequireDefault(require("../../__internal__/utils/helpers/events"));
|
|
13
13
|
var _popover = _interopRequireDefault(require("../../__internal__/popover"));
|
|
14
14
|
var _utils = require("../../style/utils");
|
|
15
|
-
var
|
|
15
|
+
var _useChildButtons = _interopRequireDefault(require("../../hooks/__internal__/useChildButtons"));
|
|
16
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
17
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
18
18
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; }
|
|
@@ -32,57 +32,17 @@ const MultiActionButton = _ref => {
|
|
|
32
32
|
"data-role": dataRole,
|
|
33
33
|
...rest
|
|
34
34
|
} = _ref;
|
|
35
|
-
const ref = (0, _react.useRef)(null);
|
|
36
35
|
const buttonRef = (0, _react.useRef)(null);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/* istanbul ignore else */
|
|
49
|
-
if (ref.current) {
|
|
50
|
-
setMinWidth(ref.current.getBoundingClientRect().width);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const childrenWithProps = () => {
|
|
54
|
-
return buttonChildren.map((child, index) => {
|
|
55
|
-
if (! /*#__PURE__*/_react.default.isValidElement(child)) {
|
|
56
|
-
return child;
|
|
57
|
-
}
|
|
58
|
-
const props = {
|
|
59
|
-
key: index.toString(),
|
|
60
|
-
role: "menuitem",
|
|
61
|
-
ref: buttonChildrenRefs[index],
|
|
62
|
-
tabIndex: -1,
|
|
63
|
-
onClick: ev => {
|
|
64
|
-
if (child.props.onClick) child.props.onClick(ev);
|
|
65
|
-
hideButtons();
|
|
66
|
-
buttonRef.current?.focus();
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
return /*#__PURE__*/_react.default.cloneElement(child, props);
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
|
-
const handleKeyDown = (0, _useMenuKeyboardNavigation.default)(buttonRef, buttonChildrenRefs, hideButtons, showAdditionalButtons);
|
|
73
|
-
const handleMainButtonKeyDown = ev => {
|
|
74
|
-
if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev) || _events.default.isUpKey(ev)) {
|
|
75
|
-
ev.preventDefault();
|
|
76
|
-
if (!showAdditionalButtons) {
|
|
77
|
-
showButtons();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// see if setTimeout could be removed after we update react to v18 thanks to the concurrent mode
|
|
81
|
-
setTimeout(() => {
|
|
82
|
-
buttonChildrenRefs[0]?.current?.focus();
|
|
83
|
-
}, 0);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
36
|
+
const {
|
|
37
|
+
showAdditionalButtons,
|
|
38
|
+
showButtons,
|
|
39
|
+
hideButtons,
|
|
40
|
+
buttonNode,
|
|
41
|
+
hideButtonsIfTriggerNotFocused,
|
|
42
|
+
handleToggleButtonKeyDown,
|
|
43
|
+
wrapperProps,
|
|
44
|
+
contextValue
|
|
45
|
+
} = (0, _useChildButtons.default)(buttonRef);
|
|
86
46
|
const handleInsideClick = (0, _useClickAwayListener.default)(hideButtons);
|
|
87
47
|
const handleClick = ev => {
|
|
88
48
|
showButtons();
|
|
@@ -95,7 +55,7 @@ const MultiActionButton = _ref => {
|
|
|
95
55
|
disabled,
|
|
96
56
|
displayed: showAdditionalButtons,
|
|
97
57
|
onTouchStart: showButtons,
|
|
98
|
-
onKeyDown:
|
|
58
|
+
onKeyDown: handleToggleButtonKeyDown,
|
|
99
59
|
onClick: handleClick,
|
|
100
60
|
buttonType,
|
|
101
61
|
size,
|
|
@@ -107,24 +67,17 @@ const MultiActionButton = _ref => {
|
|
|
107
67
|
};
|
|
108
68
|
const renderAdditionalButtons = () => /*#__PURE__*/_react.default.createElement(_popover.default, {
|
|
109
69
|
placement: "bottom-end",
|
|
110
|
-
reference:
|
|
111
|
-
}, /*#__PURE__*/_react.default.createElement(_multiActionButton.StyledButtonChildrenContainer, {
|
|
112
|
-
role: "menu",
|
|
70
|
+
reference: buttonNode
|
|
71
|
+
}, /*#__PURE__*/_react.default.createElement(_multiActionButton.StyledButtonChildrenContainer, _extends({}, wrapperProps, {
|
|
113
72
|
"aria-label": text,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
onKeyDown: handleKeyDown
|
|
119
|
-
}, childrenWithProps()));
|
|
120
|
-
const hideButtonsIfTriggerNotFocused = (0, _react.useCallback)(() => {
|
|
121
|
-
if (buttonRef.current === document.activeElement) return;
|
|
122
|
-
setShowAdditionalButtons(false);
|
|
123
|
-
}, []);
|
|
73
|
+
align: align
|
|
74
|
+
}), /*#__PURE__*/_react.default.createElement(_splitButton.default.Provider, {
|
|
75
|
+
value: contextValue
|
|
76
|
+
}, children)));
|
|
124
77
|
const marginProps = (0, _utils.filterStyledSystemMarginProps)(rest);
|
|
125
78
|
return /*#__PURE__*/_react.default.createElement(_multiActionButton.StyledMultiActionButton, _extends({
|
|
126
79
|
onMouseLeave: hideButtonsIfTriggerNotFocused,
|
|
127
|
-
ref:
|
|
80
|
+
ref: buttonNode,
|
|
128
81
|
"data-component": "multi-action-button",
|
|
129
82
|
"data-element": dataElement,
|
|
130
83
|
"data-role": dataRole,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface SplitButtonContextProps {
|
|
3
|
+
inSplitButton: boolean;
|
|
4
|
+
onChildButtonClick?: (childOnClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>) => React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> | undefined;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: React.Context<SplitButtonContextProps>;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
var _default = /*#__PURE__*/_react.default.createContext({
|
|
10
|
+
inSplitButton: false
|
|
11
|
+
});
|
|
12
|
+
exports.default = _default;
|
|
@@ -13,12 +13,12 @@ var _button = _interopRequireDefault(require("../button"));
|
|
|
13
13
|
var _splitButton = _interopRequireDefault(require("./split-button.style"));
|
|
14
14
|
var _splitButtonToggle = _interopRequireDefault(require("./split-button-toggle.style"));
|
|
15
15
|
var _splitButtonChildren = _interopRequireDefault(require("./split-button-children.style"));
|
|
16
|
-
var _events = _interopRequireDefault(require("../../__internal__/utils/helpers/events"));
|
|
17
16
|
var _guid = _interopRequireDefault(require("../../__internal__/utils/helpers/guid"));
|
|
18
17
|
var _popover = _interopRequireDefault(require("../../__internal__/popover"));
|
|
19
18
|
var _utils = require("../../style/utils");
|
|
20
19
|
var _themes = require("../../style/themes");
|
|
21
|
-
var
|
|
20
|
+
var _useChildButtons = _interopRequireDefault(require("../../hooks/__internal__/useChildButtons"));
|
|
21
|
+
var _splitButton2 = _interopRequireDefault(require("./__internal__/split-button.context"));
|
|
22
22
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
23
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
24
24
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; }
|
|
@@ -42,39 +42,17 @@ const SplitButton = _ref => {
|
|
|
42
42
|
} = _ref;
|
|
43
43
|
const theme = (0, _react.useContext)(_styledComponents.ThemeContext) || _themes.baseTheme;
|
|
44
44
|
const buttonLabelId = (0, _react.useRef)((0, _guid.default)());
|
|
45
|
-
const buttonChildren = (0, _react.useMemo)(() => _react.default.Children.toArray(children), [children]);
|
|
46
|
-
const buttonChildrenRefs = (0, _react.useMemo)(() => buttonChildren.map(() => /*#__PURE__*/_react.default.createRef()), [buttonChildren]);
|
|
47
|
-
const splitButtonNode = (0, _react.useRef)(null);
|
|
48
45
|
const toggleButton = (0, _react.useRef)(null);
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (splitButtonNode.current) {
|
|
60
|
-
setMinWidth(CONTENT_WIDTH_RATIO * splitButtonNode.current.getBoundingClientRect().width);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function handleToggleButtonKeyDown(ev) {
|
|
64
|
-
if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev) || _events.default.isUpKey(ev)) {
|
|
65
|
-
ev.preventDefault();
|
|
66
|
-
if (!showAdditionalButtons) {
|
|
67
|
-
showButtons();
|
|
68
|
-
}
|
|
69
|
-
setTimeout(() => {
|
|
70
|
-
buttonChildrenRefs[0]?.current?.focus();
|
|
71
|
-
}, 0);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const hideButtonsIfTriggerNotFocused = (0, _react.useCallback)(() => {
|
|
75
|
-
if (toggleButton.current === document.activeElement) return;
|
|
76
|
-
setShowAdditionalButtons(false);
|
|
77
|
-
}, []);
|
|
46
|
+
const {
|
|
47
|
+
showAdditionalButtons,
|
|
48
|
+
showButtons,
|
|
49
|
+
hideButtons,
|
|
50
|
+
buttonNode,
|
|
51
|
+
hideButtonsIfTriggerNotFocused,
|
|
52
|
+
handleToggleButtonKeyDown,
|
|
53
|
+
wrapperProps,
|
|
54
|
+
contextValue
|
|
55
|
+
} = (0, _useChildButtons.default)(toggleButton, CONTENT_WIDTH_RATIO);
|
|
78
56
|
const mainButtonProps = {
|
|
79
57
|
onMouseEnter: hideButtonsIfTriggerNotFocused,
|
|
80
58
|
onFocus: hideButtonsIfTriggerNotFocused,
|
|
@@ -135,43 +113,24 @@ const SplitButton = _ref => {
|
|
|
135
113
|
disabled: disabled
|
|
136
114
|
}))];
|
|
137
115
|
}
|
|
138
|
-
function childrenWithProps() {
|
|
139
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
140
|
-
return childArray.filter(Boolean).map((child, index) => {
|
|
141
|
-
const childProps = {
|
|
142
|
-
key: index.toString(),
|
|
143
|
-
role: "menuitem",
|
|
144
|
-
ref: buttonChildrenRefs[index],
|
|
145
|
-
tabIndex: -1,
|
|
146
|
-
onClick: ev => {
|
|
147
|
-
if (child.props.onClick) child.props.onClick(ev);
|
|
148
|
-
hideButtons();
|
|
149
|
-
toggleButton.current?.focus();
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
return /*#__PURE__*/_react.default.cloneElement(child, childProps);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
116
|
function renderAdditionalButtons() {
|
|
156
117
|
if (!showAdditionalButtons) return null;
|
|
157
118
|
return /*#__PURE__*/_react.default.createElement(_popover.default, {
|
|
158
119
|
placement: "bottom-end",
|
|
159
|
-
reference:
|
|
160
|
-
}, /*#__PURE__*/_react.default.createElement(_splitButtonChildren.default, {
|
|
161
|
-
role: "menu",
|
|
120
|
+
reference: buttonNode
|
|
121
|
+
}, /*#__PURE__*/_react.default.createElement(_splitButtonChildren.default, _extends({}, wrapperProps, {
|
|
162
122
|
"aria-label": text,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}, childrenWithProps()));
|
|
123
|
+
align: align
|
|
124
|
+
}), /*#__PURE__*/_react.default.createElement(_splitButton2.default.Provider, {
|
|
125
|
+
value: contextValue
|
|
126
|
+
}, children)));
|
|
168
127
|
}
|
|
169
128
|
const handleClick = (0, _useClickAwayListener.default)(hideButtons);
|
|
170
129
|
const marginProps = (0, _utils.filterStyledSystemMarginProps)(rest);
|
|
171
130
|
return /*#__PURE__*/_react.default.createElement(_splitButton.default, _extends({
|
|
172
131
|
onMouseLeave: hideButtonsIfTriggerNotFocused,
|
|
173
132
|
onClick: handleClick,
|
|
174
|
-
ref:
|
|
133
|
+
ref: buttonNode
|
|
175
134
|
}, componentTags(), marginProps), renderMainButton(), renderAdditionalButtons());
|
|
176
135
|
};
|
|
177
136
|
exports.SplitButton = SplitButton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./useChildButtons";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "default", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _useChildButtons.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _useChildButtons = _interopRequireDefault(require("./useChildButtons"));
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
declare const useChildButtons: (toggleButtonRef: React.RefObject<HTMLButtonElement>, widthRatio?: number) => {
|
|
3
|
+
showAdditionalButtons: boolean;
|
|
4
|
+
showButtons: () => void;
|
|
5
|
+
hideButtons: () => void;
|
|
6
|
+
buttonNode: import("react").RefObject<HTMLDivElement>;
|
|
7
|
+
hideButtonsIfTriggerNotFocused: () => void;
|
|
8
|
+
handleToggleButtonKeyDown: (ev: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
9
|
+
wrapperProps: {
|
|
10
|
+
role: string;
|
|
11
|
+
"data-element": string;
|
|
12
|
+
onKeyDown: (ev: any) => void;
|
|
13
|
+
minWidth: number;
|
|
14
|
+
ref: import("react").RefObject<HTMLDivElement>;
|
|
15
|
+
};
|
|
16
|
+
contextValue: {
|
|
17
|
+
inSplitButton: boolean;
|
|
18
|
+
onChildButtonClick: (childOnClick?: React.MouseEventHandler<HTMLButtonElement>) => (ev: React.MouseEvent<HTMLButtonElement>) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export default useChildButtons;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _events = _interopRequireDefault(require("../../../__internal__/utils/helpers/events"));
|
|
9
|
+
var _useMenuKeyboardNavigation = _interopRequireDefault(require("../useMenuKeyboardNavigation"));
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
const useChildButtons = function (toggleButtonRef) {
|
|
12
|
+
let widthRatio = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
13
|
+
const [showAdditionalButtons, setShowAdditionalButtons] = (0, _react.useState)(false);
|
|
14
|
+
const [minWidth, setMinWidth] = (0, _react.useState)(0);
|
|
15
|
+
const buttonNode = (0, _react.useRef)(null);
|
|
16
|
+
const childrenContainer = (0, _react.useRef)(null);
|
|
17
|
+
const focusFirstChildButtonOnOpen = (0, _react.useRef)(false);
|
|
18
|
+
const hideButtons = (0, _react.useCallback)(() => {
|
|
19
|
+
setShowAdditionalButtons(false);
|
|
20
|
+
}, []);
|
|
21
|
+
function showButtons() {
|
|
22
|
+
setShowAdditionalButtons(true);
|
|
23
|
+
|
|
24
|
+
/* istanbul ignore else */
|
|
25
|
+
if (buttonNode.current) {
|
|
26
|
+
setMinWidth(widthRatio * buttonNode.current.getBoundingClientRect().width);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const getButtonChildren = (0, _react.useCallback)(() => childrenContainer.current?.querySelectorAll('[data-component="button"]'), []);
|
|
30
|
+
(0, _react.useEffect)(() => {
|
|
31
|
+
const firstChild = getButtonChildren()?.[0];
|
|
32
|
+
if (focusFirstChildButtonOnOpen.current && showAdditionalButtons && firstChild) {
|
|
33
|
+
focusFirstChildButtonOnOpen.current = false;
|
|
34
|
+
firstChild.focus();
|
|
35
|
+
}
|
|
36
|
+
}, [showAdditionalButtons, getButtonChildren]);
|
|
37
|
+
const handleToggleButtonKeyDown = ev => {
|
|
38
|
+
if (_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev) || _events.default.isDownKey(ev) || _events.default.isUpKey(ev)) {
|
|
39
|
+
ev.preventDefault();
|
|
40
|
+
if (!showAdditionalButtons) {
|
|
41
|
+
showButtons();
|
|
42
|
+
}
|
|
43
|
+
focusFirstChildButtonOnOpen.current = true;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const handleKeyDown = (0, _useMenuKeyboardNavigation.default)(toggleButtonRef, getButtonChildren, hideButtons, showAdditionalButtons);
|
|
47
|
+
const onChildButtonClick = childOnClick => ev => {
|
|
48
|
+
childOnClick?.(ev);
|
|
49
|
+
hideButtons();
|
|
50
|
+
toggleButtonRef.current?.focus();
|
|
51
|
+
};
|
|
52
|
+
const hideButtonsIfTriggerNotFocused = (0, _react.useCallback)(() => {
|
|
53
|
+
if (toggleButtonRef.current === document.activeElement) return;
|
|
54
|
+
setShowAdditionalButtons(false);
|
|
55
|
+
}, [toggleButtonRef]);
|
|
56
|
+
const wrapperProps = {
|
|
57
|
+
role: "menu",
|
|
58
|
+
"data-element": "additional-buttons",
|
|
59
|
+
onKeyDown: handleKeyDown,
|
|
60
|
+
minWidth,
|
|
61
|
+
ref: childrenContainer
|
|
62
|
+
};
|
|
63
|
+
const contextValue = {
|
|
64
|
+
inSplitButton: true,
|
|
65
|
+
onChildButtonClick
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
showAdditionalButtons,
|
|
69
|
+
showButtons,
|
|
70
|
+
hideButtons,
|
|
71
|
+
buttonNode,
|
|
72
|
+
hideButtonsIfTriggerNotFocused,
|
|
73
|
+
handleToggleButtonKeyDown,
|
|
74
|
+
wrapperProps,
|
|
75
|
+
contextValue
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
var _default = useChildButtons;
|
|
79
|
+
exports.default = _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (mainControlRef: React.RefObject<HTMLButtonElement>,
|
|
1
|
+
declare const _default: (mainControlRef: React.RefObject<HTMLButtonElement>, getButtonChildren: () => NodeListOf<HTMLButtonElement>, hide: () => void, isOpen: boolean) => (ev: any) => void;
|
|
2
2
|
export default _default;
|
|
@@ -9,8 +9,7 @@ var _events = _interopRequireDefault(require("../../../__internal__/utils/helper
|
|
|
9
9
|
var _focusTrapUtils = require("../../../__internal__/focus-trap/focus-trap-utils");
|
|
10
10
|
var _useModalManager = _interopRequireDefault(require("../useModalManager"));
|
|
11
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
-
var _default = (mainControlRef,
|
|
13
|
-
const childrenLength = (0, _react.useMemo)(() => childrenRefs.length, [childrenRefs]);
|
|
12
|
+
var _default = (mainControlRef, getButtonChildren, hide, isOpen) => {
|
|
14
13
|
const refocusMainControl = (0, _react.useCallback)(() => {
|
|
15
14
|
hide();
|
|
16
15
|
mainControlRef.current?.focus();
|
|
@@ -33,8 +32,10 @@ var _default = (mainControlRef, childrenRefs, hide, isOpen) => {
|
|
|
33
32
|
if (!(_events.default.isEnterKey(ev) || _events.default.isSpaceKey(ev))) {
|
|
34
33
|
ev.preventDefault();
|
|
35
34
|
}
|
|
36
|
-
const
|
|
35
|
+
const buttonChildren = getButtonChildren();
|
|
36
|
+
const childrenLength = buttonChildren?.length;
|
|
37
37
|
let nextIndex = -1;
|
|
38
|
+
const currentIndex = Array.from(buttonChildren).indexOf(document.activeElement);
|
|
38
39
|
const arrowModifierPressed = ev.ctrlKey || ev.metaKey;
|
|
39
40
|
if (_events.default.isEndKey(ev) || arrowModifierPressed && _events.default.isDownKey(ev)) {
|
|
40
41
|
nextIndex = childrenLength - 1;
|
|
@@ -61,16 +62,16 @@ var _default = (mainControlRef, childrenRefs, hide, isOpen) => {
|
|
|
61
62
|
const elements = Array.from(document.querySelectorAll(_focusTrapUtils.defaultFocusableSelectors)).filter(el => Number(el.tabIndex) !== -1);
|
|
62
63
|
const indexOf = elements.indexOf(mainControlRef.current);
|
|
63
64
|
elements[indexOf + 1]?.focus();
|
|
64
|
-
//
|
|
65
|
+
// timeout enforces that the "hide" method will be run after browser focuses on the next element
|
|
65
66
|
setTimeout(hide, 0);
|
|
66
67
|
} else {
|
|
67
68
|
nextIndex = currentIndex + 1;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
if (nextIndex > -1) {
|
|
71
|
-
|
|
72
|
+
buttonChildren?.[nextIndex]?.focus();
|
|
72
73
|
}
|
|
73
|
-
}, [
|
|
74
|
+
}, [hide, refocusMainControl, mainControlRef, getButtonChildren]);
|
|
74
75
|
return handleKeyDown;
|
|
75
76
|
};
|
|
76
77
|
exports.default = _default;
|