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.
Files changed (48) hide show
  1. package/esm/__internal__/form-field/form-field.component.d.ts +3 -1
  2. package/esm/__internal__/form-field/form-field.component.js +3 -1
  3. package/esm/__internal__/label/label.component.d.ts +3 -2
  4. package/esm/__internal__/label/label.component.js +10 -5
  5. package/esm/components/button-toggle/button-toggle-group/button-toggle-group.component.d.ts +64 -0
  6. package/esm/components/button-toggle/button-toggle-group/button-toggle-group.component.js +157 -0
  7. package/esm/components/button-toggle/button-toggle-group/button-toggle-group.style.d.ts +6 -0
  8. package/esm/components/button-toggle/button-toggle-group/button-toggle-group.style.js +64 -0
  9. package/esm/components/button-toggle/button-toggle.component.d.ts +21 -8
  10. package/esm/components/button-toggle/button-toggle.component.js +94 -27
  11. package/esm/components/button-toggle/button-toggle.style.d.ts +7 -6
  12. package/esm/components/button-toggle/button-toggle.style.js +46 -37
  13. package/esm/components/button-toggle/index.d.ts +3 -1
  14. package/esm/components/button-toggle/index.js +2 -1
  15. package/esm/components/popover-container/popover-container.component.js +1 -1
  16. package/lib/__internal__/form-field/form-field.component.d.ts +3 -1
  17. package/lib/__internal__/form-field/form-field.component.js +3 -1
  18. package/lib/__internal__/label/label.component.d.ts +3 -2
  19. package/lib/__internal__/label/label.component.js +10 -5
  20. package/lib/components/button-toggle/button-toggle-group/button-toggle-group.component.d.ts +64 -0
  21. package/lib/components/button-toggle/button-toggle-group/button-toggle-group.component.js +168 -0
  22. package/lib/components/button-toggle/button-toggle-group/button-toggle-group.style.d.ts +6 -0
  23. package/lib/components/{button-toggle-group → button-toggle/button-toggle-group}/button-toggle-group.style.js +29 -46
  24. package/lib/components/button-toggle/button-toggle-group/package.json +6 -0
  25. package/lib/components/button-toggle/button-toggle.component.d.ts +21 -8
  26. package/lib/components/button-toggle/button-toggle.component.js +93 -26
  27. package/lib/components/button-toggle/button-toggle.style.d.ts +7 -6
  28. package/lib/components/button-toggle/button-toggle.style.js +48 -40
  29. package/lib/components/button-toggle/index.d.ts +3 -1
  30. package/lib/components/button-toggle/index.js +8 -1
  31. package/lib/components/popover-container/popover-container.component.js +1 -1
  32. package/package.json +1 -1
  33. package/esm/components/button-toggle/button-toggle-input.component.d.ts +0 -25
  34. package/esm/components/button-toggle/button-toggle-input.component.js +0 -44
  35. package/esm/components/button-toggle-group/button-toggle-group.component.d.ts +0 -47
  36. package/esm/components/button-toggle-group/button-toggle-group.component.js +0 -84
  37. package/esm/components/button-toggle-group/button-toggle-group.style.d.ts +0 -4
  38. package/esm/components/button-toggle-group/button-toggle-group.style.js +0 -81
  39. package/lib/components/button-toggle/button-toggle-input.component.d.ts +0 -25
  40. package/lib/components/button-toggle/button-toggle-input.component.js +0 -54
  41. package/lib/components/button-toggle-group/button-toggle-group.component.d.ts +0 -47
  42. package/lib/components/button-toggle-group/button-toggle-group.component.js +0 -94
  43. package/lib/components/button-toggle-group/button-toggle-group.style.d.ts +0 -4
  44. package/lib/components/button-toggle-group/package.json +0 -6
  45. /package/esm/components/{button-toggle-group → button-toggle/button-toggle-group}/index.d.ts +0 -0
  46. /package/esm/components/{button-toggle-group → button-toggle/button-toggle-group}/index.js +0 -0
  47. /package/lib/components/{button-toggle-group → button-toggle/button-toggle-group}/index.d.ts +0 -0
  48. /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
- htmlFor: htmlFor,
110
+ id: labelId
111
+ }, as === "label" ? {
112
+ htmlFor
113
+ } : {}, {
110
114
  onMouseEnter: handleMouseEnter,
111
115
  onMouseLeave: handleMouseLeave,
112
- isRequired: isRequired
113
- }, children), icon());
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 { StyledButtonToggleLabelProps } from "./button-toggle.style";
3
- import { ButtonToggleInputProps } from "./button-toggle-input.component";
4
- export interface ButtonToggleProps extends ButtonToggleInputProps, Partial<StyledButtonToggleLabelProps> {
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
- /** Callback triggered by click event on the input. */
18
- onClick?: (ev: React.MouseEvent<HTMLInputElement>) => void;
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, onChange, onFocus, size, value, }: ButtonToggleProps): React.JSX.Element;
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, StyledButtonToggleLabel, StyledButtonToggleContentWrapper } from "./button-toggle.style";
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 inputGuid = guid();
37
- const inputRef = useRef(null);
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
- inputRef.current?.focus();
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
- return /*#__PURE__*/React.createElement(StyledButtonToggle, {
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
- onClick: handleClick
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
- "data-element": "button-toggle-input",
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
- htmlFor: inputGuid,
134
+ id: inputGuid.current,
78
135
  onMouseEnter: onMouseEnter,
79
136
  onMouseLeave: onMouseLeave,
80
137
  size: size,
81
- grouped: grouped
82
- }, /*#__PURE__*/React.createElement(StyledButtonToggleContentWrapper, null, icon, children)));
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 StyledButtonToggleLabelProps {
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 StyledButtonToggleLabel: import("styled-components").StyledComponent<"label", any, StyledButtonToggleLabelProps, never>;
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 StyledButtonToggleProps {
24
+ export interface StyledButtonToggleWrapperProps {
23
25
  grouped?: boolean;
24
26
  }
25
- declare const StyledButtonToggle: import("styled-components").StyledComponent<"div", any, StyledButtonToggleProps, never>;
26
- declare const StyledButtonToggleInput: import("styled-components").StyledComponent<"input", any, {}, never>;
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, };