carbon-react 118.6.0 → 119.0.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.
- package/esm/__internal__/form-field/form-field.component.d.ts +3 -1
- package/esm/__internal__/form-field/form-field.component.js +3 -1
- package/esm/__internal__/label/label.component.d.ts +3 -2
- package/esm/__internal__/label/label.component.js +10 -5
- package/esm/components/button-toggle/button-toggle-group/button-toggle-group.component.d.ts +64 -0
- package/esm/components/button-toggle/button-toggle-group/button-toggle-group.component.js +157 -0
- package/esm/components/button-toggle/button-toggle-group/button-toggle-group.style.d.ts +6 -0
- package/esm/components/button-toggle/button-toggle-group/button-toggle-group.style.js +64 -0
- package/esm/components/button-toggle/button-toggle.component.d.ts +21 -8
- package/esm/components/button-toggle/button-toggle.component.js +94 -27
- package/esm/components/button-toggle/button-toggle.style.d.ts +7 -6
- package/esm/components/button-toggle/button-toggle.style.js +46 -37
- package/esm/components/button-toggle/index.d.ts +3 -1
- package/esm/components/button-toggle/index.js +2 -1
- package/esm/components/popover-container/popover-container.component.js +1 -1
- package/lib/__internal__/form-field/form-field.component.d.ts +3 -1
- package/lib/__internal__/form-field/form-field.component.js +3 -1
- package/lib/__internal__/label/label.component.d.ts +3 -2
- package/lib/__internal__/label/label.component.js +10 -5
- package/lib/components/button-toggle/button-toggle-group/button-toggle-group.component.d.ts +64 -0
- package/lib/components/button-toggle/button-toggle-group/button-toggle-group.component.js +168 -0
- package/lib/components/button-toggle/button-toggle-group/button-toggle-group.style.d.ts +6 -0
- package/lib/components/{button-toggle-group → button-toggle/button-toggle-group}/button-toggle-group.style.js +29 -46
- package/lib/components/button-toggle/button-toggle-group/package.json +6 -0
- package/lib/components/button-toggle/button-toggle.component.d.ts +21 -8
- package/lib/components/button-toggle/button-toggle.component.js +93 -26
- package/lib/components/button-toggle/button-toggle.style.d.ts +7 -6
- package/lib/components/button-toggle/button-toggle.style.js +48 -40
- package/lib/components/button-toggle/index.d.ts +3 -1
- package/lib/components/button-toggle/index.js +8 -1
- package/lib/components/popover-container/popover-container.component.js +1 -1
- package/package.json +1 -1
- package/esm/components/button-toggle/button-toggle-input.component.d.ts +0 -25
- package/esm/components/button-toggle/button-toggle-input.component.js +0 -44
- package/esm/components/button-toggle-group/button-toggle-group.component.d.ts +0 -47
- package/esm/components/button-toggle-group/button-toggle-group.component.js +0 -84
- package/esm/components/button-toggle-group/button-toggle-group.style.d.ts +0 -4
- package/esm/components/button-toggle-group/button-toggle-group.style.js +0 -81
- package/lib/components/button-toggle/button-toggle-input.component.d.ts +0 -25
- package/lib/components/button-toggle/button-toggle-input.component.js +0 -54
- package/lib/components/button-toggle-group/button-toggle-group.component.d.ts +0 -47
- package/lib/components/button-toggle-group/button-toggle-group.component.js +0 -94
- package/lib/components/button-toggle-group/button-toggle-group.style.d.ts +0 -4
- package/lib/components/button-toggle-group/package.json +0 -6
- /package/esm/components/{button-toggle-group → button-toggle/button-toggle-group}/index.d.ts +0 -0
- /package/esm/components/{button-toggle-group → button-toggle/button-toggle-group}/index.js +0 -0
- /package/lib/components/{button-toggle-group → button-toggle/button-toggle-group}/index.d.ts +0 -0
- /package/lib/components/{button-toggle-group → button-toggle/button-toggle-group}/index.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { MarginProps } from "styled-system";
|
|
3
3
|
import { ValidationProps } from "../validations";
|
|
4
|
+
import { LabelProps } from "../label";
|
|
4
5
|
import { TagProps } from "../utils/helpers/tags/tags";
|
|
5
6
|
import { IconType } from "../../components/icon";
|
|
6
7
|
interface CommonFormFieldProps extends MarginProps, ValidationProps {
|
|
@@ -28,6 +29,7 @@ interface CommonFormFieldProps extends MarginProps, ValidationProps {
|
|
|
28
29
|
labelSpacing?: 1 | 2;
|
|
29
30
|
/** Label width */
|
|
30
31
|
labelWidth?: number;
|
|
32
|
+
labelAs?: LabelProps["as"];
|
|
31
33
|
/** If true the label switches position with the input */
|
|
32
34
|
reverse?: boolean;
|
|
33
35
|
/** Id of the validation icon */
|
|
@@ -57,7 +59,7 @@ export interface FormFieldProps extends CommonFormFieldProps, TagProps {
|
|
|
57
59
|
useValidationIcon?: boolean;
|
|
58
60
|
}
|
|
59
61
|
declare const FormField: {
|
|
60
|
-
({ children, "data-component": dataComponent, disabled, fieldHelp: fieldHelpContent, fieldHelpInline, error, warning, info, tooltipId, fieldHelpId, label, labelId, labelAlign, labelHelp, labelHelpIcon, labelInline, labelSpacing, labelWidth, id, reverse, isOptional, useValidationIcon, adaptiveLabelBreakpoint, isRequired, validationIconId, validationRedesignOptIn, ...rest }: FormFieldProps): React.JSX.Element;
|
|
62
|
+
({ children, "data-component": dataComponent, disabled, fieldHelp: fieldHelpContent, fieldHelpInline, error, warning, info, tooltipId, fieldHelpId, label, labelId, labelAlign, labelHelp, labelHelpIcon, labelInline, labelSpacing, labelWidth, labelAs, id, reverse, isOptional, useValidationIcon, adaptiveLabelBreakpoint, isRequired, validationIconId, validationRedesignOptIn, ...rest }: FormFieldProps): React.JSX.Element;
|
|
61
63
|
displayName: string;
|
|
62
64
|
};
|
|
63
65
|
export default FormField;
|
|
@@ -29,6 +29,7 @@ const FormField = _ref => {
|
|
|
29
29
|
labelInline,
|
|
30
30
|
labelSpacing = 2,
|
|
31
31
|
labelWidth,
|
|
32
|
+
labelAs,
|
|
32
33
|
id,
|
|
33
34
|
reverse,
|
|
34
35
|
isOptional,
|
|
@@ -104,7 +105,8 @@ const FormField = _ref => {
|
|
|
104
105
|
pr: !reverse ? labelSpacing : undefined,
|
|
105
106
|
pl: reverse ? labelSpacing : undefined,
|
|
106
107
|
isRequired: isRequired,
|
|
107
|
-
validationIconId: validationIconId
|
|
108
|
+
validationIconId: validationIconId,
|
|
109
|
+
as: labelAs
|
|
108
110
|
}, label), fieldHelpInline && fieldHelp, !reverse && children), !fieldHelpInline && fieldHelp);
|
|
109
111
|
};
|
|
110
112
|
FormField.displayName = "FormField";
|
|
@@ -3,6 +3,7 @@ import { StyledLabelProps, StyledLabelContainerProps } from "./label.style";
|
|
|
3
3
|
import { ValidationProps } from "../validations";
|
|
4
4
|
import { IconType } from "../../components/icon";
|
|
5
5
|
export interface LabelProps extends ValidationProps, StyledLabelProps, StyledLabelContainerProps {
|
|
6
|
+
as?: "span" | "label";
|
|
6
7
|
/** Children elements */
|
|
7
8
|
children?: React.ReactNode;
|
|
8
9
|
/** A message that the Help component will display */
|
|
@@ -20,6 +21,6 @@ export interface LabelProps extends ValidationProps, StyledLabelProps, StyledLab
|
|
|
20
21
|
/** Id of the validation icon */
|
|
21
22
|
validationIconId?: string;
|
|
22
23
|
}
|
|
23
|
-
export declare const Label: ({ align, children, disabled, error, help, helpIcon, htmlFor, info, inline, isRequired, labelId, optional, pr, pl, tooltipId, useValidationIcon, validationIconId, warning, width, }: LabelProps) => React.JSX.Element;
|
|
24
|
-
declare const _default: React.MemoExoticComponent<({ align, children, disabled, error, help, helpIcon, htmlFor, info, inline, isRequired, labelId, optional, pr, pl, tooltipId, useValidationIcon, validationIconId, warning, width, }: LabelProps) => React.JSX.Element>;
|
|
24
|
+
export declare const Label: ({ align, as, children, disabled, error, help, helpIcon, htmlFor, info, inline, isRequired, labelId, optional, pr, pl, tooltipId, useValidationIcon, validationIconId, warning, width, }: LabelProps) => React.JSX.Element;
|
|
25
|
+
declare const _default: React.MemoExoticComponent<({ align, as, children, disabled, error, help, helpIcon, htmlFor, info, inline, isRequired, labelId, optional, pr, pl, tooltipId, useValidationIcon, validationIconId, warning, width, }: LabelProps) => React.JSX.Element>;
|
|
25
26
|
export default _default;
|
|
@@ -1,3 +1,4 @@
|
|
|
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); }
|
|
1
2
|
import React, { useState, useContext } from "react";
|
|
2
3
|
import PropTypes from "prop-types";
|
|
3
4
|
import Help from "../../components/help";
|
|
@@ -27,6 +28,7 @@ const tooltipPosition = _ref2 => {
|
|
|
27
28
|
export const Label = _ref3 => {
|
|
28
29
|
let {
|
|
29
30
|
align = "right",
|
|
31
|
+
as = "label",
|
|
30
32
|
children,
|
|
31
33
|
disabled,
|
|
32
34
|
error,
|
|
@@ -102,14 +104,17 @@ export const Label = _ref3 => {
|
|
|
102
104
|
optional: optional,
|
|
103
105
|
pr: pr,
|
|
104
106
|
pl: pl
|
|
105
|
-
}, /*#__PURE__*/React.createElement(StyledLabel, {
|
|
107
|
+
}, /*#__PURE__*/React.createElement(StyledLabel, _extends({
|
|
106
108
|
"data-element": "label",
|
|
107
109
|
disabled: disabled,
|
|
108
|
-
id: labelId
|
|
109
|
-
|
|
110
|
+
id: labelId
|
|
111
|
+
}, as === "label" ? {
|
|
112
|
+
htmlFor
|
|
113
|
+
} : {}, {
|
|
110
114
|
onMouseEnter: handleMouseEnter,
|
|
111
115
|
onMouseLeave: handleMouseLeave,
|
|
112
|
-
isRequired: isRequired
|
|
113
|
-
|
|
116
|
+
isRequired: isRequired,
|
|
117
|
+
as: as
|
|
118
|
+
}), children), icon());
|
|
114
119
|
};
|
|
115
120
|
export default /*#__PURE__*/React.memo(Label);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { MarginProps } from "styled-system";
|
|
3
|
+
import { TagProps } from "../../../__internal__/utils/helpers/tags";
|
|
4
|
+
export interface CustomEvent {
|
|
5
|
+
target: {
|
|
6
|
+
name?: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface ButtonToggleGroupProps extends MarginProps, TagProps {
|
|
11
|
+
/** Unique id for the root element of the component */
|
|
12
|
+
id: string;
|
|
13
|
+
/** Specifies the name prop to be applied to each button in the group */
|
|
14
|
+
name?: string;
|
|
15
|
+
/** Togglable buttons to be rendered. Only accepts children of type ButtonToggle */
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
/** aria-label for the group wrapper. Required for accessibility when no text label is provided */
|
|
18
|
+
"aria-label"?: string;
|
|
19
|
+
/** Text for the visible label of the button group. */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Text for the label's help tooltip. */
|
|
22
|
+
labelHelp?: React.ReactNode;
|
|
23
|
+
/** Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) */
|
|
24
|
+
labelSpacing?: 1 | 2;
|
|
25
|
+
/** The percentage width of the ButtonToggleGroup. */
|
|
26
|
+
inputWidth?: number | string;
|
|
27
|
+
/** The text for the field help. */
|
|
28
|
+
fieldHelp?: string;
|
|
29
|
+
/** Sets the field help to inline. */
|
|
30
|
+
fieldHelpInline?: boolean;
|
|
31
|
+
/** Sets the label to be inline. */
|
|
32
|
+
labelInline?: boolean;
|
|
33
|
+
/** The percentage width of the label. */
|
|
34
|
+
labelWidth?: number;
|
|
35
|
+
/** If true all ButtonToggle children will flex to the full width of the ButtonToggleGroup parent */
|
|
36
|
+
fullWidth?: boolean;
|
|
37
|
+
/** The alignment for the text in the label. */
|
|
38
|
+
labelAlign?: "left" | "right";
|
|
39
|
+
/** Callback triggered by pressing one of the child buttons. Use with controlled components to set the value prop to the value argument */
|
|
40
|
+
onChange?: (ev: React.MouseEvent<HTMLButtonElement>, value?: string, name?: string) => void;
|
|
41
|
+
/** Determines which child button is selected when the component is used as a controlled component */
|
|
42
|
+
value?: string;
|
|
43
|
+
/** Aria label for rendered help component */
|
|
44
|
+
helpAriaLabel?: string;
|
|
45
|
+
/** set this to true to allow the buttons within the group to be deselected when already selected, leaving no selected button */
|
|
46
|
+
allowDeselect?: boolean;
|
|
47
|
+
}
|
|
48
|
+
declare type ButtonToggleGroupContextType = {
|
|
49
|
+
onButtonClick: (value: string) => void;
|
|
50
|
+
handleKeyDown: (ev: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
51
|
+
pressedButtonValue?: string;
|
|
52
|
+
onChange?: (ev: React.MouseEvent<HTMLButtonElement>, value?: string, name?: string) => void;
|
|
53
|
+
name?: string;
|
|
54
|
+
allowDeselect?: boolean;
|
|
55
|
+
isInGroup: boolean;
|
|
56
|
+
firstButton?: HTMLButtonElement;
|
|
57
|
+
childButtonCallbackRef?: (button: HTMLButtonElement | null) => void;
|
|
58
|
+
};
|
|
59
|
+
export declare const ButtonToggleGroupContext: React.Context<ButtonToggleGroupContextType>;
|
|
60
|
+
declare const ButtonToggleGroup: {
|
|
61
|
+
({ children, fieldHelp, fieldHelpInline, "aria-label": ariaLabel, label, labelHelp, labelSpacing, inputWidth, fullWidth, labelInline, labelWidth, labelAlign, name, onChange, value, "data-component": dataComponent, "data-element": dataElement, "data-role": dataRole, helpAriaLabel, id, allowDeselect, ...props }: ButtonToggleGroupProps): React.JSX.Element;
|
|
62
|
+
displayName: string;
|
|
63
|
+
};
|
|
64
|
+
export default ButtonToggleGroup;
|
|
@@ -0,0 +1,157 @@
|
|
|
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, { createContext, useMemo, useState, useRef } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import invariant from "invariant";
|
|
5
|
+
import FormField from "../../../__internal__/form-field";
|
|
6
|
+
import guid from "../../../__internal__/utils/helpers/guid";
|
|
7
|
+
import StyledButtonToggleGroup, { StyledButtonToggleGroupWrapper } from "./button-toggle-group.style";
|
|
8
|
+
import { ButtonToggle } from "..";
|
|
9
|
+
import { filterStyledSystemMarginProps } from "../../../style/utils";
|
|
10
|
+
import { TooltipProvider } from "../../../__internal__/tooltip-provider";
|
|
11
|
+
import { InputGroupBehaviour } from "../../../__internal__/input-behaviour";
|
|
12
|
+
import Logger from "../../../__internal__/utils/logger";
|
|
13
|
+
import Events from "../../../__internal__/utils/helpers/events";
|
|
14
|
+
let deprecateNameWarnTriggered = false;
|
|
15
|
+
const BUTTON_TOGGLE_SELECTOR = '[data-element="button-toggle-button"]';
|
|
16
|
+
export const ButtonToggleGroupContext = /*#__PURE__*/createContext({
|
|
17
|
+
onButtonClick: /* istanbul ignore next */() => {},
|
|
18
|
+
handleKeyDown: /* istanbul ignore next */() => {},
|
|
19
|
+
pressedButtonValue: undefined,
|
|
20
|
+
allowDeselect: false,
|
|
21
|
+
isInGroup: false
|
|
22
|
+
});
|
|
23
|
+
const ButtonToggleGroup = _ref => {
|
|
24
|
+
let {
|
|
25
|
+
children,
|
|
26
|
+
fieldHelp,
|
|
27
|
+
fieldHelpInline,
|
|
28
|
+
"aria-label": ariaLabel,
|
|
29
|
+
label,
|
|
30
|
+
labelHelp,
|
|
31
|
+
labelSpacing,
|
|
32
|
+
inputWidth,
|
|
33
|
+
fullWidth,
|
|
34
|
+
labelInline,
|
|
35
|
+
labelWidth,
|
|
36
|
+
labelAlign,
|
|
37
|
+
name,
|
|
38
|
+
onChange,
|
|
39
|
+
value,
|
|
40
|
+
"data-component": dataComponent = "button-toggle-group",
|
|
41
|
+
"data-element": dataElement,
|
|
42
|
+
"data-role": dataRole,
|
|
43
|
+
helpAriaLabel,
|
|
44
|
+
id,
|
|
45
|
+
allowDeselect,
|
|
46
|
+
...props
|
|
47
|
+
} = _ref;
|
|
48
|
+
const hasCorrectItemStructure = useMemo(() => {
|
|
49
|
+
const incorrectChild = React.Children.toArray(children).find(child => {
|
|
50
|
+
return ! /*#__PURE__*/React.isValidElement(child) || child.type.displayName !== ButtonToggle.displayName;
|
|
51
|
+
});
|
|
52
|
+
return !incorrectChild;
|
|
53
|
+
}, [children]);
|
|
54
|
+
!hasCorrectItemStructure ? process.env.NODE_ENV !== "production" ? invariant(false, `\`ButtonToggleGroup\` only accepts children of type \`${ButtonToggle.displayName}\``) : invariant(false) : void 0;
|
|
55
|
+
const labelId = useRef(guid());
|
|
56
|
+
const wrapperRef = useRef(null);
|
|
57
|
+
const [pressedButtonValue, setPressedButtonValue] = useState();
|
|
58
|
+
if (name && !deprecateNameWarnTriggered) {
|
|
59
|
+
deprecateNameWarnTriggered = true;
|
|
60
|
+
Logger.deprecate(`The \`name\` prop in \`ButtonToggleGroup\` component is deprecated and will soon be removed. It does not provide any functionality
|
|
61
|
+
since the component can no longer be used in an uncontrolled fashion.`);
|
|
62
|
+
}
|
|
63
|
+
const onButtonClick = buttonValue => {
|
|
64
|
+
let newValue = buttonValue;
|
|
65
|
+
const currentValue = value || pressedButtonValue;
|
|
66
|
+
if (allowDeselect && currentValue === buttonValue) {
|
|
67
|
+
newValue = undefined;
|
|
68
|
+
}
|
|
69
|
+
setPressedButtonValue(newValue);
|
|
70
|
+
};
|
|
71
|
+
const getInnerButtons = () => wrapperRef.current?.querySelectorAll(BUTTON_TOGGLE_SELECTOR);
|
|
72
|
+
// needs to be state not ref, so that a rerender is triggered
|
|
73
|
+
const [firstButton, setFirstButton] = useState();
|
|
74
|
+
const handleKeyDown = ev => {
|
|
75
|
+
const innerButtons = getInnerButtons();
|
|
76
|
+
// istanbul ignore if
|
|
77
|
+
if (!innerButtons || !document.activeElement) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const focusedIndex = Array.from(innerButtons).indexOf(document.activeElement);
|
|
81
|
+
let nextElement;
|
|
82
|
+
if (Events.isLeftKey(ev)) {
|
|
83
|
+
const nextIndex = focusedIndex === 0 ? innerButtons.length - 1 : focusedIndex - 1;
|
|
84
|
+
nextElement = innerButtons[nextIndex];
|
|
85
|
+
} else if (Events.isRightKey(ev)) {
|
|
86
|
+
const nextIndex = (focusedIndex + 1) % innerButtons.length;
|
|
87
|
+
nextElement = innerButtons[nextIndex];
|
|
88
|
+
}
|
|
89
|
+
// istanbul ignore else
|
|
90
|
+
if (nextElement instanceof HTMLButtonElement) {
|
|
91
|
+
nextElement.focus();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const childButtonCallbackRef = button => {
|
|
95
|
+
// setTimeout needed as otherwise innerButtons aren't picked up by the query even though the ref is attached
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
// guard needed to avoid warnings about setting state on an unmounted component - the callback ref will
|
|
98
|
+
// get called with null when the component is about to be unmounted, and it has been unmounted by the time
|
|
99
|
+
// the setTimeout completes
|
|
100
|
+
if (button) {
|
|
101
|
+
const innerButtons = getInnerButtons();
|
|
102
|
+
if (!innerButtons) {
|
|
103
|
+
setFirstButton(undefined);
|
|
104
|
+
} else if (button === innerButtons[0]) {
|
|
105
|
+
setFirstButton(button);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, 0);
|
|
109
|
+
};
|
|
110
|
+
return /*#__PURE__*/React.createElement(TooltipProvider, {
|
|
111
|
+
helpAriaLabel: helpAriaLabel
|
|
112
|
+
}, /*#__PURE__*/React.createElement(InputGroupBehaviour, null, /*#__PURE__*/React.createElement(FormField, _extends({
|
|
113
|
+
label: label,
|
|
114
|
+
labelHelp: labelHelp,
|
|
115
|
+
labelSpacing: labelSpacing,
|
|
116
|
+
fieldHelp: fieldHelp,
|
|
117
|
+
fieldHelpInline: fieldHelpInline,
|
|
118
|
+
labelInline: labelInline,
|
|
119
|
+
labelWidth: labelWidth,
|
|
120
|
+
labelAlign: labelAlign,
|
|
121
|
+
labelId: labelId.current,
|
|
122
|
+
"data-component": dataComponent,
|
|
123
|
+
"data-role": dataRole,
|
|
124
|
+
"data-element": dataElement,
|
|
125
|
+
id: id,
|
|
126
|
+
labelAs: "span"
|
|
127
|
+
}, filterStyledSystemMarginProps(props)), /*#__PURE__*/React.createElement(ButtonToggleGroupContext.Provider, {
|
|
128
|
+
value: {
|
|
129
|
+
onButtonClick,
|
|
130
|
+
handleKeyDown,
|
|
131
|
+
pressedButtonValue: value || pressedButtonValue,
|
|
132
|
+
onChange,
|
|
133
|
+
name,
|
|
134
|
+
allowDeselect,
|
|
135
|
+
isInGroup: true,
|
|
136
|
+
firstButton,
|
|
137
|
+
childButtonCallbackRef
|
|
138
|
+
}
|
|
139
|
+
}, /*#__PURE__*/React.createElement(StyledButtonToggleGroupWrapper, {
|
|
140
|
+
labelInline: labelInline,
|
|
141
|
+
ref: wrapperRef
|
|
142
|
+
}, /*#__PURE__*/React.createElement(StyledButtonToggleGroup, _extends({}, label ? {
|
|
143
|
+
"aria-labelledby": labelId.current
|
|
144
|
+
} : {
|
|
145
|
+
"aria-label": ariaLabel
|
|
146
|
+
}, {
|
|
147
|
+
inputWidth: inputWidth,
|
|
148
|
+
fullWidth: fullWidth,
|
|
149
|
+
role: "group",
|
|
150
|
+
"data-component": dataComponent,
|
|
151
|
+
"data-role": dataRole,
|
|
152
|
+
"data-element": dataElement,
|
|
153
|
+
id: id
|
|
154
|
+
}, filterStyledSystemMarginProps(props)), children))))));
|
|
155
|
+
};
|
|
156
|
+
ButtonToggleGroup.displayName = "ButtonToggleGroup";
|
|
157
|
+
export default ButtonToggleGroup;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ButtonToggleGroupProps } from ".";
|
|
2
|
+
declare type StyledButtonToggleGroupProps = Pick<ButtonToggleGroupProps, "inputWidth" | "fullWidth">;
|
|
3
|
+
declare type StyledButtonToggleGroupWrapperProps = Pick<ButtonToggleGroupProps, "labelInline">;
|
|
4
|
+
export declare const StyledButtonToggleGroupWrapper: import("styled-components").StyledComponent<"div", any, StyledButtonToggleGroupWrapperProps, never>;
|
|
5
|
+
declare const StyledButtonToggleGroup: import("styled-components").StyledComponent<"div", any, StyledButtonToggleGroupProps, never>;
|
|
6
|
+
export default StyledButtonToggleGroup;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import styled, { css } from "styled-components";
|
|
2
|
+
import { margin } from "styled-system";
|
|
3
|
+
import { baseTheme } from "../../../style/themes";
|
|
4
|
+
import { StyledButtonToggle, StyledButtonToggleWrapper } from "../button-toggle.style";
|
|
5
|
+
export const StyledButtonToggleGroupWrapper = styled.div`
|
|
6
|
+
${_ref => {
|
|
7
|
+
let {
|
|
8
|
+
labelInline
|
|
9
|
+
} = _ref;
|
|
10
|
+
return labelInline && css`
|
|
11
|
+
display: flex;
|
|
12
|
+
`;
|
|
13
|
+
}}
|
|
14
|
+
`;
|
|
15
|
+
const StyledButtonToggleGroup = styled.div`
|
|
16
|
+
${margin}
|
|
17
|
+
|
|
18
|
+
display: flex;
|
|
19
|
+
|
|
20
|
+
${StyledButtonToggle}:not(:first-of-type):not(:last-of-type) {
|
|
21
|
+
border-radius: var(--borderRadius000);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
${StyledButtonToggle}:first-of-type ${StyledButtonToggle} {
|
|
25
|
+
border-top-left-radius: var(--borderRadius400);
|
|
26
|
+
border-bottom-left-radius: var(--borderRadius400);
|
|
27
|
+
border-top-right-radius: var(--borderRadius000);
|
|
28
|
+
border-bottom-right-radius: var(--borderRadius000);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
${StyledButtonToggle}:last-of-type ${StyledButtonToggle} {
|
|
32
|
+
border-top-left-radius: var(--borderRadius000);
|
|
33
|
+
border-bottom-left-radius: var(--borderRadius000);
|
|
34
|
+
border-top-right-radius: var(--borderRadius400);
|
|
35
|
+
border-bottom-right-radius: var(--borderRadius400);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
${_ref2 => {
|
|
39
|
+
let {
|
|
40
|
+
fullWidth
|
|
41
|
+
} = _ref2;
|
|
42
|
+
return fullWidth && css`
|
|
43
|
+
${StyledButtonToggle} {
|
|
44
|
+
width: 100%;
|
|
45
|
+
}
|
|
46
|
+
${StyledButtonToggleWrapper} {
|
|
47
|
+
flex: auto;
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
}}
|
|
51
|
+
|
|
52
|
+
${_ref3 => {
|
|
53
|
+
let {
|
|
54
|
+
inputWidth
|
|
55
|
+
} = _ref3;
|
|
56
|
+
return inputWidth && css`
|
|
57
|
+
width: ${`${inputWidth}%`};
|
|
58
|
+
`;
|
|
59
|
+
}}
|
|
60
|
+
`;
|
|
61
|
+
StyledButtonToggleGroup.defaultProps = {
|
|
62
|
+
theme: baseTheme
|
|
63
|
+
};
|
|
64
|
+
export default StyledButtonToggleGroup;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { StyledButtonToggleProps } from "./button-toggle.style";
|
|
3
|
+
export interface ButtonToggleProps extends Partial<StyledButtonToggleProps> {
|
|
4
|
+
/** Prop to specify the aria-label of the component */
|
|
5
|
+
"aria-label"?: string;
|
|
6
|
+
/** Prop to specify the aria-labelledby property of the component */
|
|
7
|
+
"aria-labelledby"?: string;
|
|
8
|
+
/** DEPRECATED: A synonym for pressed, to keep backwards compatibility. */
|
|
9
|
+
checked?: boolean;
|
|
5
10
|
/** Text to display for the button. */
|
|
6
11
|
children?: React.ReactNode;
|
|
7
12
|
/** Identifier used for testing purposes, applied to the root element of the component. */
|
|
@@ -10,15 +15,23 @@ export interface ButtonToggleProps extends ButtonToggleInputProps, Partial<Style
|
|
|
10
15
|
"data-element"?: string;
|
|
11
16
|
/** Identifier used for testing purposes, applied to the root element of the component. */
|
|
12
17
|
"data-role"?: string;
|
|
13
|
-
/** Set the default value of the Group if component is meant to be used as uncontrolled. */
|
|
14
|
-
defaultChecked?: boolean;
|
|
15
18
|
/** Remove spacing from between buttons. */
|
|
16
19
|
grouped?: boolean;
|
|
17
|
-
/**
|
|
18
|
-
|
|
20
|
+
/** An optional string by which to identify the button in an onChange handler on the parent ButtonToggleGroup. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Callback triggered by blur event on the button. */
|
|
23
|
+
onBlur?: (ev: React.FocusEvent<HTMLButtonElement>) => void;
|
|
24
|
+
/** Callback triggered by focus event on the button. */
|
|
25
|
+
onFocus?: (ev: React.FocusEvent<HTMLButtonElement>) => void;
|
|
26
|
+
/** Callback triggered by click event on the button. */
|
|
27
|
+
onClick?: (ev: React.MouseEvent<HTMLButtonElement>) => void;
|
|
28
|
+
/** Set the pressed state of the toggle button */
|
|
29
|
+
pressed?: boolean;
|
|
30
|
+
/** An optional string by which to identify the button in either an onClick handler, or an onChange handler on the parent ButtonToggleGroup. */
|
|
31
|
+
value?: string;
|
|
19
32
|
}
|
|
20
33
|
export declare const ButtonToggle: {
|
|
21
|
-
({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, buttonIcon, buttonIconSize, checked, children, "data-component": dataComponent, "data-element": dataElement, "data-role": dataRole, disabled, grouped, name, onBlur,
|
|
34
|
+
({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, buttonIcon, buttonIconSize, checked, children, "data-component": dataComponent, "data-element": dataElement, "data-role": dataRole, disabled, grouped, name, onBlur, onFocus, onClick, pressed, size, value, }: ButtonToggleProps): React.JSX.Element;
|
|
22
35
|
displayName: string;
|
|
23
36
|
};
|
|
24
37
|
export default ButtonToggle;
|
|
@@ -1,12 +1,15 @@
|
|
|
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); }
|
|
1
2
|
import React, { useContext, useRef } from "react";
|
|
2
3
|
import PropTypes from "prop-types";
|
|
3
4
|
import invariant from "invariant";
|
|
4
|
-
import { StyledButtonToggle,
|
|
5
|
+
import { StyledButtonToggle, StyledButtonToggleWrapper } from "./button-toggle.style";
|
|
5
6
|
import guid from "../../__internal__/utils/helpers/guid";
|
|
7
|
+
import { ButtonToggleGroupContext } from "./button-toggle-group/button-toggle-group.component";
|
|
6
8
|
import ButtonToggleIcon from "./button-toggle-icon.component";
|
|
7
|
-
import ButtonToggleInput from "./button-toggle-input.component";
|
|
8
|
-
import { InputGroupContext } from "../../__internal__/input-behaviour";
|
|
9
9
|
import Logger from "../../__internal__/utils/logger";
|
|
10
|
+
import { InputGroupContext } from "../../__internal__/input-behaviour";
|
|
11
|
+
let deprecateCheckedWarnTriggered = false;
|
|
12
|
+
let deprecateNameWarnTriggered = false;
|
|
10
13
|
let deprecateUncontrolledWarnTriggered = false;
|
|
11
14
|
export const ButtonToggle = _ref => {
|
|
12
15
|
let {
|
|
@@ -23,18 +26,48 @@ export const ButtonToggle = _ref => {
|
|
|
23
26
|
grouped,
|
|
24
27
|
name,
|
|
25
28
|
onBlur,
|
|
26
|
-
onChange,
|
|
27
29
|
onFocus,
|
|
30
|
+
onClick,
|
|
31
|
+
pressed,
|
|
28
32
|
size = "medium",
|
|
29
33
|
value
|
|
30
34
|
} = _ref;
|
|
31
35
|
!!!(children || buttonIcon) ? process.env.NODE_ENV !== "production" ? invariant(false, "Either prop `buttonIcon` must be defined, or this node must have children") : invariant(false) : void 0;
|
|
36
|
+
if (checked !== undefined && !deprecateCheckedWarnTriggered) {
|
|
37
|
+
deprecateCheckedWarnTriggered = true;
|
|
38
|
+
Logger.deprecate("The `checked` prop in `ButtonToggle` component is deprecated and will soon be removed. Please use `pressed` instead.");
|
|
39
|
+
}
|
|
40
|
+
if (name && !deprecateNameWarnTriggered) {
|
|
41
|
+
deprecateNameWarnTriggered = true;
|
|
42
|
+
Logger.deprecate(`The \`name\` prop in \`ButtonToggle\` component is deprecated and will soon be removed. It does not provide any functionality
|
|
43
|
+
since the component can no longer be used in an uncontrolled fashion.`);
|
|
44
|
+
}
|
|
45
|
+
const pressedPropValue = pressed === undefined ? checked : pressed;
|
|
46
|
+
const buttonRef = useRef(null);
|
|
32
47
|
const {
|
|
33
48
|
onMouseEnter,
|
|
34
|
-
onMouseLeave
|
|
49
|
+
onMouseLeave,
|
|
50
|
+
onBlur: inputGroupOnBlur,
|
|
51
|
+
onFocus: inputGroupOnFocus
|
|
35
52
|
} = useContext(InputGroupContext);
|
|
36
|
-
const
|
|
37
|
-
|
|
53
|
+
const {
|
|
54
|
+
onButtonClick,
|
|
55
|
+
handleKeyDown,
|
|
56
|
+
pressedButtonValue,
|
|
57
|
+
onChange,
|
|
58
|
+
name: groupName,
|
|
59
|
+
allowDeselect,
|
|
60
|
+
isInGroup,
|
|
61
|
+
firstButton,
|
|
62
|
+
childButtonCallbackRef
|
|
63
|
+
} = useContext(ButtonToggleGroupContext);
|
|
64
|
+
const callbackRef = element => {
|
|
65
|
+
buttonRef.current = element;
|
|
66
|
+
if (childButtonCallbackRef) {
|
|
67
|
+
childButtonCallbackRef(element);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const inputGuid = useRef(guid());
|
|
38
71
|
let icon;
|
|
39
72
|
if (buttonIcon) {
|
|
40
73
|
icon = /*#__PURE__*/React.createElement(ButtonToggleIcon, {
|
|
@@ -44,42 +77,76 @@ export const ButtonToggle = _ref => {
|
|
|
44
77
|
hasContent: !!children
|
|
45
78
|
});
|
|
46
79
|
}
|
|
47
|
-
function handleClick() {
|
|
48
|
-
|
|
80
|
+
function handleClick(ev) {
|
|
81
|
+
if (onClick) {
|
|
82
|
+
onClick(ev);
|
|
83
|
+
}
|
|
84
|
+
if (onChange) {
|
|
85
|
+
let newValue = value;
|
|
86
|
+
if (allowDeselect && pressedButtonValue === value) {
|
|
87
|
+
newValue = undefined;
|
|
88
|
+
}
|
|
89
|
+
onChange(ev, newValue, groupName || name);
|
|
90
|
+
}
|
|
91
|
+
if (value) {
|
|
92
|
+
onButtonClick(value);
|
|
93
|
+
}
|
|
49
94
|
}
|
|
50
95
|
if (!deprecateUncontrolledWarnTriggered && !onChange) {
|
|
51
96
|
deprecateUncontrolledWarnTriggered = true;
|
|
52
97
|
Logger.deprecate("Uncontrolled behaviour in `Button Toggle` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
|
|
53
98
|
}
|
|
54
|
-
|
|
99
|
+
function handleFocus(ev) {
|
|
100
|
+
if (onFocus) {
|
|
101
|
+
onFocus(ev);
|
|
102
|
+
}
|
|
103
|
+
if (inputGroupOnFocus) {
|
|
104
|
+
inputGroupOnFocus();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function handleBlur(ev) {
|
|
108
|
+
if (onBlur) {
|
|
109
|
+
onBlur(ev);
|
|
110
|
+
}
|
|
111
|
+
if (inputGroupOnBlur) {
|
|
112
|
+
inputGroupOnBlur();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const isPressed = isInGroup ? pressedButtonValue === value : pressedPropValue;
|
|
116
|
+
const isFirstButton = buttonRef.current === firstButton;
|
|
117
|
+
|
|
118
|
+
// if we're in a ButtonToggleGroup, only one button should be tabbable - the pressed button if there is one, or
|
|
119
|
+
// the first one if not
|
|
120
|
+
const tabbable = !isInGroup || isPressed || !pressedButtonValue && isFirstButton;
|
|
121
|
+
return /*#__PURE__*/React.createElement(StyledButtonToggleWrapper, {
|
|
55
122
|
"data-component": dataComponent || "button-toggle",
|
|
56
123
|
"data-element": dataElement,
|
|
57
124
|
"data-role": dataRole,
|
|
58
|
-
grouped: grouped
|
|
59
|
-
|
|
60
|
-
}, /*#__PURE__*/React.createElement(ButtonToggleInput, {
|
|
125
|
+
grouped: grouped
|
|
126
|
+
}, /*#__PURE__*/React.createElement(StyledButtonToggle, _extends({
|
|
61
127
|
"aria-label": ariaLabel,
|
|
62
128
|
"aria-labelledby": ariaLabelledBy,
|
|
63
|
-
"
|
|
64
|
-
name: name,
|
|
65
|
-
checked: checked,
|
|
66
|
-
disabled: disabled,
|
|
67
|
-
guid: inputGuid,
|
|
68
|
-
value: value,
|
|
69
|
-
onChange: onChange,
|
|
70
|
-
onFocus: onFocus,
|
|
71
|
-
onBlur: onBlur,
|
|
72
|
-
ref: inputRef
|
|
73
|
-
}), /*#__PURE__*/React.createElement(StyledButtonToggleLabel, {
|
|
129
|
+
"aria-pressed": !!isPressed,
|
|
74
130
|
buttonIcon: buttonIcon,
|
|
75
131
|
buttonIconSize: buttonIconSize,
|
|
132
|
+
"data-element": "button-toggle-button",
|
|
76
133
|
disabled: disabled,
|
|
77
|
-
|
|
134
|
+
id: inputGuid.current,
|
|
78
135
|
onMouseEnter: onMouseEnter,
|
|
79
136
|
onMouseLeave: onMouseLeave,
|
|
80
137
|
size: size,
|
|
81
|
-
grouped: grouped
|
|
82
|
-
|
|
138
|
+
grouped: grouped,
|
|
139
|
+
value: value,
|
|
140
|
+
onFocus: handleFocus,
|
|
141
|
+
onBlur: handleBlur,
|
|
142
|
+
onClick: handleClick,
|
|
143
|
+
onKeyDown: handleKeyDown
|
|
144
|
+
}, tabbable ? {} : {
|
|
145
|
+
tabIndex: -1
|
|
146
|
+
}, {
|
|
147
|
+
allowDeselect: allowDeselect,
|
|
148
|
+
ref: callbackRef
|
|
149
|
+
}), icon, children));
|
|
83
150
|
};
|
|
84
151
|
ButtonToggle.displayName = "ButtonToggle";
|
|
85
152
|
export default ButtonToggle;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IconType } from "../icon";
|
|
2
2
|
export declare type ButtonToggleIconSizes = "small" | "large";
|
|
3
3
|
declare const StyledButtonToggleContentWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
4
|
-
export interface
|
|
4
|
+
export interface StyledButtonToggleProps {
|
|
5
5
|
/** The icon to be rendered inside of the button */
|
|
6
6
|
buttonIcon?: IconType;
|
|
7
7
|
/** Sets the size of the buttonIcon (eg. large) */
|
|
@@ -11,17 +11,18 @@ export interface StyledButtonToggleLabelProps {
|
|
|
11
11
|
/** ButtonToggle size */
|
|
12
12
|
size: "small" | "medium" | "large";
|
|
13
13
|
grouped?: boolean;
|
|
14
|
+
/** set this to true to allow the button to be deselected when already selected */
|
|
15
|
+
allowDeselect?: boolean;
|
|
14
16
|
}
|
|
15
|
-
declare const
|
|
17
|
+
declare const StyledButtonToggle: import("styled-components").StyledComponent<"button", any, StyledButtonToggleProps, never>;
|
|
16
18
|
export interface StyledButtonToggleIconProps {
|
|
17
19
|
/** Sets the size of the buttonIcon (eg. large) */
|
|
18
20
|
buttonIconSize?: ButtonToggleIconSizes;
|
|
19
21
|
hasContent?: boolean;
|
|
20
22
|
}
|
|
21
23
|
declare const StyledButtonToggleIcon: import("styled-components").StyledComponent<"div", any, StyledButtonToggleIconProps, never>;
|
|
22
|
-
export interface
|
|
24
|
+
export interface StyledButtonToggleWrapperProps {
|
|
23
25
|
grouped?: boolean;
|
|
24
26
|
}
|
|
25
|
-
declare const
|
|
26
|
-
|
|
27
|
-
export { StyledButtonToggle, StyledButtonToggleLabel, StyledButtonToggleIcon, StyledButtonToggleInput, StyledButtonToggleContentWrapper, };
|
|
27
|
+
declare const StyledButtonToggleWrapper: import("styled-components").StyledComponent<"div", any, StyledButtonToggleWrapperProps, never>;
|
|
28
|
+
export { StyledButtonToggle, StyledButtonToggleWrapper, StyledButtonToggleIcon, StyledButtonToggleContentWrapper, };
|