diff --git a/cypress/locators/switch/locators.js b/cypress/locators/switch/locators.js index 423fdf2182..69296fddde 100644 --- a/cypress/locators/switch/locators.js +++ b/cypress/locators/switch/locators.js @@ -1,4 +1,4 @@ // component preview locators -const SWITCH_DATA_COMPONENT = '[data-component="Switch"]'; +const SWITCH_DATA_COMPONENT = '[data-component="switch"]'; export default SWITCH_DATA_COMPONENT; diff --git a/src/__internal__/checkable-input/checkable-input.component.js b/src/__internal__/checkable-input/checkable-input.component.js index acf8929493..9f34293866 100644 --- a/src/__internal__/checkable-input/checkable-input.component.js +++ b/src/__internal__/checkable-input/checkable-input.component.js @@ -11,6 +11,7 @@ import HiddenCheckableInput from "./hidden-checkable-input.component"; import guid from "../../utils/helpers/guid"; const CheckableInput = ({ + autoFocus, checked, children, disabled, @@ -18,10 +19,10 @@ const CheckableInput = ({ fieldHelp, fieldHelpInline, info, - inputId, + id: inputId, inputRef, - inputType, - inputValue, + type, + value, inputWidth, label, labelAlign, @@ -35,14 +36,13 @@ const CheckableInput = ({ onFocus, required, reverse, - tabindex, validationOnLabel, warning, + ...props }) => { const { current: id } = useRef(inputId || guid()); - const labelId = `${id} label`; const helpId = `${id} help`; - const isRadio = inputType === "radio"; + const isRadio = type === "radio"; const formFieldProps = { disabled, @@ -56,7 +56,6 @@ const CheckableInput = ({ labelAlign, labelHelp, labelHelpIcon: "info", - labelId, labelInline, labelSpacing, name: id, @@ -69,20 +68,20 @@ const CheckableInput = ({ }; const inputProps = { + autoFocus, checked, disabled, helpId, id, inputRef, - inputType, - inputValue, - labelId, + type, + value, name, onBlur, onChange, onFocus, required, - tabindex, + ...props, }; return ( @@ -107,6 +106,8 @@ const CheckableInput = ({ }; CheckableInput.propTypes = { + /** If true the Component will be focused when page load */ + autoFocus: PropTypes.bool, /** Set the value of the CheckableInput */ checked: PropTypes.bool, /** Used to set the visible aspect of the input (i.e. the checkbox sprite, input slider etc) */ @@ -130,11 +131,11 @@ CheckableInput.propTypes = { /** Displays fieldHelp inline with the CheckableInput */ fieldHelpInline: PropTypes.bool, /** Unique Identifier for the input. Will use a randomly generated GUID if none is provided */ - inputId: PropTypes.string, + id: PropTypes.string, /** Specifies input type, 'checkbox' or 'radio' */ - inputType: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, /** Value passed to the input */ - inputValue: PropTypes.string, + value: PropTypes.string, /** Sets percentage-based input width */ inputWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /** The content for the Label to apply to the input */ @@ -161,8 +162,6 @@ CheckableInput.propTypes = { reverse: PropTypes.bool, /** Flag to configure component as mandatory */ required: PropTypes.bool, - /** Input tabindex */ - tabindex: PropTypes.string, /** A callback to retrieve the input reference */ inputRef: PropTypes.oneOfType([ PropTypes.func, diff --git a/src/__internal__/checkable-input/checkable-input.d.ts b/src/__internal__/checkable-input/checkable-input.d.ts index e4a02b1142..12b290e2a7 100644 --- a/src/__internal__/checkable-input/checkable-input.d.ts +++ b/src/__internal__/checkable-input/checkable-input.d.ts @@ -1,9 +1,11 @@ import * as React from "react"; + import { ValidationPropTypes } from "../validations"; +import { CommonHiddenCheckableInputProps } from "./hidden-checkable-input"; -export interface CommonCheckableInputProps extends ValidationPropTypes { - /** Set the value of the CheckableInput */ - checked?: boolean; +export interface CommonCheckableInputProps + extends ValidationPropTypes, + CommonHiddenCheckableInputProps { /** If true, the component will be disabled */ disabled?: boolean; /** Help content to be displayed under an input */ @@ -13,47 +15,39 @@ export interface CommonCheckableInputProps extends ValidationPropTypes { * To be used with labelInline prop set to true */ fieldHelpInline?: boolean; + /** Unique Identifier for the input. Will use a randomly generated GUID if none is provided */ + id?: string; /** Sets percentage-based input width */ inputWidth?: number | string; /** Label content */ label?: React.ReactNode; + /** The content for the help tooltip, to appear next to the Label */ + labelHelp?: string | React.ReactNode; /** Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) */ labelSpacing?: 1 | 2; /** Label width */ labelWidth?: number; - /** The name of the the input */ - name?: string; - /** Specify a callback triggered on blur */ - onBlur?: (ev: React.FocusEvent) => void; - /** Specify a callback triggered on focus */ - onFocus?: (ev: React.FocusEvent) => void; - /** Specify a callback triggered on change */ - onChange?: (ev: React.ChangeEvent) => void; /** Flag to configure component as mandatory */ required?: boolean; /** If true the label switches position with the input */ reverse?: boolean; + /** Size of the component */ + size?: "small" | "large"; } export interface CheckableInputProps extends CommonCheckableInputProps { /** Used to set the visible aspect of the input (i.e. the checkbox sprite, input slider etc) */ children?: React.ReactNode; - /** Unique Identifier for the input. Will use a randomly generated GUID if none is provided */ - inputId?: string; /** HTML type attribute of the input */ - inputType?: string; + type: string; /** Value passed to the input */ - inputValue?: string; + value?: string; /** Text alignment of the label */ labelAlign?: "left" | "right"; - /** A message that the Help component will display */ - labelHelp?: React.ReactNode; /** When true label is inline */ labelInline?: boolean; } -declare class CheckableInput extends React.Component< - CheckableInputProps & React.HTMLProps -> {} +declare function CheckableInput(props: CheckableInputProps): JSX.Element; export default CheckableInput; diff --git a/src/__internal__/checkable-input/checkable-input.spec.js b/src/__internal__/checkable-input/checkable-input.spec.js index c8eb742725..fd7947ef63 100644 --- a/src/__internal__/checkable-input/checkable-input.spec.js +++ b/src/__internal__/checkable-input/checkable-input.spec.js @@ -2,11 +2,11 @@ import React from "react"; import TestRenderer from "react-test-renderer"; import { mount } from "enzyme"; import { css } from "styled-components"; + import { assertStyleMatch } from "../../__spec_helper__/test-utils"; import CheckableInput from "."; import FieldHelpStyle from "../field-help/field-help.style"; import { FieldLineStyle } from "../form-field/form-field.style"; -import Label from "../label"; import HiddenCheckableInputStyle from "./hidden-checkable-input.style"; import LabelStyle, { StyledLabelContainer } from "../label/label.style"; import { @@ -23,27 +23,20 @@ function render(props) { describe("CheckableInput", () => { function mountInput(props) { return mount( - null} - {...props} - /> + null} {...props} /> ); } describe("helpId", () => { describe("when label and labelHelp props are present", () => { - it("returns an appropriate helpId property", () => { + it("passes an appropriate helpId property to Help component", () => { const labelWrapper = mountInput({ - inputId: "foo", + id: "foo", label: "bar", labelHelp: "baz", - }) - .find(Label) - .find("label"); + }).find(StyledHelp); - expect(labelWrapper.prop("id")).toBe("foo label"); + expect(labelWrapper.prop("id")).toBe("foo help"); }); }); }); diff --git a/src/__internal__/checkable-input/hidden-checkable-input.component.js b/src/__internal__/checkable-input/hidden-checkable-input.component.js index f01160ae89..67cc99da98 100644 --- a/src/__internal__/checkable-input/hidden-checkable-input.component.js +++ b/src/__internal__/checkable-input/hidden-checkable-input.component.js @@ -5,12 +5,13 @@ import { InputContext, InputGroupContext } from "../input-behaviour"; const HiddenCheckableInput = ({ helpId, - labelId, name, - inputType, - inputValue, - tabindex, + checked, + type, + value, inputRef, + onChange, + autoFocus, ...props }) => { const { onBlur, onFocus, onMouseEnter, onMouseLeave } = useContext( @@ -36,45 +37,61 @@ const HiddenCheckableInput = ({ }; const handleMouseEnter = (ev) => { + if (props.onMouseEnter) props.onMouseEnter(ev); if (onMouseEnter) onMouseEnter(ev); if (onMouseEnterGroup) onMouseEnterGroup(ev); }; const handleMouseLeave = (ev) => { + if (props.onMouseLeave) props.onMouseLeave(ev); if (onMouseLeave) onMouseLeave(ev); if (onMouseLeaveGroup) onMouseLeaveGroup(ev); }; return ( ); }; HiddenCheckableInput.propTypes = { + /** Allows component to be focused on page load */ + autoFocus: PropTypes.bool, + /** Checked state of the input */ checked: PropTypes.bool, - labelId: PropTypes.string, + /** Element id for aria-describedby */ helpId: PropTypes.string, + /** Input name */ name: PropTypes.string, - onBlur: PropTypes.func, + /** OnChange event handler */ + onChange: PropTypes.func, + /** OnFocus event handler */ onFocus: PropTypes.func, - inputType: PropTypes.string.isRequired, - inputValue: PropTypes.string, - tabindex: PropTypes.number, + /** Blur event handler */ + onBlur: PropTypes.func, + /** OnMouseLeave event handler */ + onMouseLeave: PropTypes.func, + /** OnMouseEnter event handler */ + onMouseEnter: PropTypes.func, + /** HTML type attribute of the input */ + type: PropTypes.string.isRequired, + /** Value of the input */ + value: PropTypes.string, /** A callback to retrieve the input reference */ inputRef: PropTypes.oneOfType([ PropTypes.func, diff --git a/src/__internal__/checkable-input/hidden-checkable-input.d.ts b/src/__internal__/checkable-input/hidden-checkable-input.d.ts new file mode 100644 index 0000000000..24abc93863 --- /dev/null +++ b/src/__internal__/checkable-input/hidden-checkable-input.d.ts @@ -0,0 +1,42 @@ +import * as React from "react"; + +export interface CommonHiddenCheckableInputProps + extends Omit< + React.InputHTMLAttributes, + "value" | "size" | "type" + > { + /** If true the Component will be focused when page load */ + autoFocus?: boolean; + /** Checked state of the input */ + checked?: boolean; + /** Input name */ + name?: string; + /** OnChange event handler */ + onChange?: (ev: React.ChangeEvent) => void; + /** OnFocus event handler */ + onFocus?: (ev: React.FocusEvent) => void; + /** Blur event handler */ + onBlur?: (ev: React.FocusEvent) => void; + /** OnMouseLeave event handler */ + onMouseLeave?: (ev: React.MouseEvent) => void; + /** OnMouseEnter event handler */ + onMouseEnter?: (ev: React.MouseEvent) => void; + /** Value of the input */ + value?: string; + /** A callback to retrieve the input reference */ + inputRef: React.Ref; +} + +export interface HiddenCheckableInputProps + extends CommonHiddenCheckableInputProps { + /** HTML type attribute of the input */ + type: string; + /** Element id for aria-describedby */ + helpId?: string; +} + +declare function HiddenCheckableInput( + props: HiddenCheckableInputProps +): JSX.Element; + +export default HiddenCheckableInput; diff --git a/src/__internal__/checkable-input/hidden-checkable-input.spec.js b/src/__internal__/checkable-input/hidden-checkable-input.spec.js index 5eafd453b9..1d3375ddc5 100644 --- a/src/__internal__/checkable-input/hidden-checkable-input.spec.js +++ b/src/__internal__/checkable-input/hidden-checkable-input.spec.js @@ -13,7 +13,7 @@ const render = ( return mount( - + ); @@ -28,9 +28,11 @@ describe("HiddenCheckableInput", () => { let contextOnFocus; let groupContextOnFocus; + let propOnMouseEnter; let contextOnMouseEnter; let groupContextOnMouseEnter; + let propOnMouseLeave; let contextOnMouseLeave; let groupContextOnMouseLeave; @@ -45,9 +47,11 @@ describe("HiddenCheckableInput", () => { contextOnFocus = jest.fn(); groupContextOnFocus = jest.fn(); + propOnMouseEnter = jest.fn(); contextOnMouseEnter = jest.fn(); groupContextOnMouseEnter = jest.fn(); + propOnMouseLeave = jest.fn(); contextOnMouseLeave = jest.fn(); groupContextOnMouseLeave = jest.fn(); @@ -55,6 +59,8 @@ describe("HiddenCheckableInput", () => { { onBlur: propOnBlur, onFocus: propOnFocus, + onMouseEnter: propOnMouseEnter, + onMouseLeave: propOnMouseLeave, }, { onBlur: groupContextOnBlur, @@ -76,9 +82,9 @@ describe("HiddenCheckableInput", () => { checked: true, helpId: "test-help", name: "test-name", - inputType: "test-type", - inputValue: "test-value", - tabindex: 0, + type: "test-type", + value: "test-value", + tabIndex: 0, }; const shallowWrapper = shallow(); @@ -101,12 +107,14 @@ describe("HiddenCheckableInput", () => { it("triggers onMouseEnter callbacks passed from context", () => { wrapper.find(HiddenCheckableInputStyle).props().onMouseEnter(); + expect(propOnMouseEnter).toHaveBeenCalled(); expect(contextOnMouseEnter).toHaveBeenCalled(); expect(groupContextOnMouseEnter).toHaveBeenCalled(); }); it("triggers onMouseLeave callbacks passed from context", () => { wrapper.find(HiddenCheckableInputStyle).props().onMouseLeave(); + expect(propOnMouseLeave).toHaveBeenCalled(); expect(contextOnMouseLeave).toHaveBeenCalled(); expect(groupContextOnMouseLeave).toHaveBeenCalled(); }); diff --git a/src/__internal__/form-field/form-field.component.js b/src/__internal__/form-field/form-field.component.js index 39766d4146..d35bd843e5 100644 --- a/src/__internal__/form-field/form-field.component.js +++ b/src/__internal__/form-field/form-field.component.js @@ -1,6 +1,8 @@ import React, { useContext, useEffect } from "react"; import PropTypes from "prop-types"; -import propTypes from "@styled-system/prop-types"; +import styledSystemPropTypes from "@styled-system/prop-types"; + +import { filterStyledSystemMarginProps } from "../../style/utils"; import FormFieldStyle, { FieldLineStyle } from "./form-field.style"; import Label from "../label"; import FieldHelp from "../field-help"; @@ -8,6 +10,10 @@ import tagComponent from "../../utils/helpers/tags"; import { TabContext } from "../../components/tabs/tab"; import useIsAboveBreakpoint from "../../hooks/__internal__/useIsAboveBreakpoint"; +const marginPropTypes = filterStyledSystemMarginProps( + styledSystemPropTypes.space +); + const FormField = ({ children, disabled, @@ -17,7 +23,6 @@ const FormField = ({ warning, info, helpId, - helpTag, helpTabIndex, label, labelId, @@ -27,12 +32,9 @@ const FormField = ({ labelInline, labelSpacing = 2, labelWidth, - name, id, reverse, - childOfForm, isOptional, - readOnly, useValidationIcon, adaptiveLabelBreakpoint, isRequired, @@ -53,61 +55,12 @@ const FormField = ({ } }, [id, context, error, warning, info]); - // Conditionally add the spacing props, we can't spread ...rest because some of the parent components - // incorrectly pass props that are consumed in other components. - // - // The styled-system/space props need to be conditional, a undefined value is still considered a value and affects the - // the behaviour - // - // FIXME FE-3370 - const spacingProps = [ - "m", - "margin", - "ml", - "marginLeft", - "mr", - "marginRight", - "mt", - "marginTop", - "mb", - "marginBottom", - "mx", - "marginLeft", - "mx", - "marginRight", - "my", - "marginTop", - "my", - "marginBottom", - "p", - "padding", - "pl", - "paddingLeft", - "pr", - "paddingRight", - "pt", - "paddingTop", - "pb", - "paddingBottom", - "px", - "paddingLeft", - "px", - "paddingRight", - "py", - "paddingTop", - "py", - "paddingBottom", - ].reduce((prev, curr) => { - if (Object.prototype.hasOwnProperty.call(rest, curr)) { - prev[curr] = rest[curr]; - } - return prev; - }, {}); + const marginProps = filterStyledSystemMarginProps(rest); return ( {reverse && children} @@ -117,19 +70,16 @@ const FormField = ({ labelId={labelId} align={labelAlign} disabled={disabled} - readOnly={readOnly} error={error} warning={warning} info={info} help={labelHelp} helpId={helpId} - helpTag={helpTag} helpTabIndex={helpTabIndex} htmlFor={id} helpIcon={labelHelpIcon} inline={inlineLabel} width={labelWidth} - childOfForm={childOfForm} optional={isOptional} useValidationIcon={useValidationIcon} pr={!reverse ? labelSpacing : undefined} @@ -175,22 +125,21 @@ const errorPropType = (props, propName, componentName, ...rest) => { }; FormField.propTypes = { - /** Styled system spacing props */ - ...propTypes.space, + /** Styled system margin props */ + ...marginPropTypes, children: PropTypes.node, - childOfForm: PropTypes.bool, disabled: PropTypes.bool, "data-component": PropTypes.string, + "data-role": PropTypes.string, + "data-element": PropTypes.string, fieldHelp: PropTypes.node, fieldHelpInline: PropTypes.bool, error: errorPropType, warning: errorPropType, info: errorPropType, helpId: PropTypes.string, - helpTag: PropTypes.string, helpTabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), id: PropTypes.string.isRequired, - name: PropTypes.string, isOptional: PropTypes.bool, label: PropTypes.node, labelId: PropTypes.string, @@ -201,7 +150,6 @@ FormField.propTypes = { /** Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) */ labelSpacing: PropTypes.oneOf([1, 2]), labelWidth: PropTypes.number, - readOnly: PropTypes.bool, reverse: PropTypes.bool, useValidationIcon: PropTypes.bool, /** Breakpoint for adaptive label (inline labels change to top aligned). Enables the adaptive behaviour when set */ diff --git a/src/__internal__/form-field/form-field.d.ts b/src/__internal__/form-field/form-field.d.ts index e2585f3a9d..e71ef50796 100644 --- a/src/__internal__/form-field/form-field.d.ts +++ b/src/__internal__/form-field/form-field.d.ts @@ -1,20 +1,16 @@ import * as React from "react"; -import { SpaceProps } from "styled-system"; +import { MarginProps } from "styled-system"; import { ValidationPropTypes } from "../validations"; export interface CommonFormFieldPropTypes - extends SpaceProps, + extends MarginProps, ValidationPropTypes { - /** Flag to indicate that component is used in a Form */ - childOfForm?: boolean; /** If true, the component will be disabled */ disabled?: boolean; /** Help content to be displayed under an input */ fieldHelp?: React.ReactNode; /** The unique id of the Help component */ helpId?: string; - /** Overrides the default 'as' attribute of the Help component */ - helpTag?: string; /** Overrides the default tabindex of the Help component */ helpTabIndex?: number | string; /** Label content */ @@ -53,11 +49,14 @@ export interface FormFieldPropTypes extends CommonFormFieldPropTypes { isOptional?: boolean; /** Flag to configure component as mandatory */ isRequired?: boolean; - /** If true, the component will be read-only */ - readOnly?: boolean; /** Whether to show the validation icon */ useValidationIcon?: boolean; + /** Identifier used for testing purposes, applied to the root element of the component. */ "data-component"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-element"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-role"?: string; } declare function FormField(props: FormFieldPropTypes): JSX.Element; diff --git a/src/__internal__/input/input-presentation.component.js b/src/__internal__/input/input-presentation.component.js index 58dfca7e86..1e87f87310 100644 --- a/src/__internal__/input/input-presentation.component.js +++ b/src/__internal__/input/input-presentation.component.js @@ -4,14 +4,19 @@ import PropTypes from "prop-types"; import InputPresentationStyle, { StyledInputPresentationContainer, } from "./input-presentation.style"; -import extractProps from "../../utils/helpers/extract-props"; import { InputContext, InputGroupContext } from "../input-behaviour"; const InputPresentation = ({ children, positionedChildren, inputWidth, - ...rest + align, + disabled, + readOnly, + size, + error, + warning, + info, }) => { const { hasFocus, onMouseDown, onMouseEnter, onMouseLeave } = useContext( InputContext @@ -22,8 +27,6 @@ const InputPresentation = ({ onMouseLeave: onGroupMouseLeave, } = useContext(InputGroupContext); - const styleProps = extractProps(rest, InputPresentationStyle); - const handleMouseEnter = (e) => { if (onMouseEnter) onMouseEnter(e); if (onGroupMouseEnter) onGroupMouseEnter(e); @@ -43,7 +46,13 @@ const InputPresentation = ({ onMouseDown={onMouseDown} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} - {...styleProps} + align={align} + disabled={disabled} + readOnly={readOnly} + size={size} + warning={warning} + error={error} + info={info} > {children} @@ -55,7 +64,6 @@ InputPresentation.propTypes = { children: PropTypes.node, align: PropTypes.string, disabled: PropTypes.bool, - hasFocus: PropTypes.bool, inputWidth: PropTypes.number, readOnly: PropTypes.bool, positionedChildren: PropTypes.node, diff --git a/src/__internal__/input/input-presentation.d.ts b/src/__internal__/input/input-presentation.d.ts index fed1fc6750..4f93772364 100644 --- a/src/__internal__/input/input-presentation.d.ts +++ b/src/__internal__/input/input-presentation.d.ts @@ -15,8 +15,6 @@ export interface CommonInputPresentationProps extends ValidationPropTypes { } export interface InputPresentationProps extends CommonInputPresentationProps { - /** If true the outline is rendered around the input */ - hasFocus?: boolean; /** Content to be rendered before the input */ positionedChildren?: React.ReactNode; } diff --git a/src/__internal__/input/input-presentation.style.js b/src/__internal__/input/input-presentation.style.js index 6ef3ff423c..70f54cf355 100644 --- a/src/__internal__/input/input-presentation.style.js +++ b/src/__internal__/input/input-presentation.style.js @@ -84,20 +84,7 @@ function stylingForValidations({ theme, error, warning, info, disabled }) { `; } -InputPresentationStyle.safeProps = [ - "align", - "disabled", - "hasFocus", - "inputWidth", - "readOnly", - "size", - "error", - "warning", - "info", -]; - InputPresentationStyle.defaultProps = { - inputWidth: 100, size: "medium", theme: baseTheme, }; @@ -106,7 +93,6 @@ InputPresentationStyle.propTypes = { align: PropTypes.string, disabled: PropTypes.bool, hasFocus: PropTypes.bool, - inputWidth: PropTypes.number, readOnly: PropTypes.bool, size: PropTypes.oneOf(["small", "medium", "large"]), error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), diff --git a/src/__internal__/input/input.component.js b/src/__internal__/input/input.component.js index a4875eab66..63a4fd7dfc 100644 --- a/src/__internal__/input/input.component.js +++ b/src/__internal__/input/input.component.js @@ -6,6 +6,10 @@ import { InputContext, InputGroupContext } from "../input-behaviour"; const Input = React.forwardRef( ( { + align, + placeholder, + disabled, + readOnly, autoFocus, inputRef, onClick, @@ -74,6 +78,10 @@ const Input = React.forwardRef( return ( , "value" | "type"> { + /* The default value alignment on the input */ + align?: "right" | "left"; /** If true the Component will be focused when rendered */ autoFocus?: boolean; /** If true, the component will be disabled */ @@ -8,7 +11,7 @@ export interface CommonInputProps { /** HTML id attribute of the input */ id?: string; /** A callback to retrieve the input reference */ - inputRef?: () => void; + inputRef?: (input: React.RefObject) => void; /** Name of the input */ name?: string; /** Specify a callback triggered on blur */ @@ -19,7 +22,7 @@ export interface CommonInputProps { onClick?: (ev: React.MouseEvent) => void; /** Specify a callback triggered on focus */ onFocus?: (ev: React.FocusEvent) => void; - /** pecify a callback triggered on keuyDown */ + /** Specify a callback triggered on keyDown */ onKeyDown?: (ev: React.KeyboardEvent) => void; /** Placeholder string to be displayed in input */ placeholder?: string; @@ -41,9 +44,7 @@ export interface InputProps extends CommonInputProps { } declare function Input( - props: InputProps & - React.RefAttributes & - React.HTMLProps + props: InputProps & React.RefAttributes ): JSX.Element; export default Input; diff --git a/src/__internal__/label/label.component.js b/src/__internal__/label/label.component.js index 08acbac90d..cf2ceb30ef 100644 --- a/src/__internal__/label/label.component.js +++ b/src/__internal__/label/label.component.js @@ -20,7 +20,6 @@ const Label = ({ inline, align = "right", width, - childOfForm, optional, labelId, helpId, @@ -30,7 +29,6 @@ const Label = ({ info, help, helpIcon, - helpTag, helpTabIndex, useValidationIcon = true, htmlFor, @@ -95,7 +93,6 @@ const Label = ({ @@ -138,8 +134,6 @@ Label.propTypes = { width: PropTypes.number, /** Label alignment */ align: PropTypes.oneOf(["left", "right"]), - /** Flag to indicate that component is used in a Form */ - childOfForm: PropTypes.bool, /** When true, label is placed in line an input */ inline: PropTypes.bool, /** If true, the component will be disabled */ @@ -162,8 +156,6 @@ Label.propTypes = { help: PropTypes.node, /** Icon type */ helpIcon: PropTypes.string, - /** Overrides the default 'as' attribute of the Help component */ - helpTag: PropTypes.string, /** Overrides the default tabindex of the Help component */ helpTabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /** Whether to show the validation icon */ diff --git a/src/__internal__/label/label.d.ts b/src/__internal__/label/label.d.ts index f8a9952a4b..29fd4c0880 100644 --- a/src/__internal__/label/label.d.ts +++ b/src/__internal__/label/label.d.ts @@ -1,14 +1,11 @@ import * as React from "react"; +import { ValidationPropTypes } from "../validations"; -export interface LabelPropTypes { +export interface LabelPropTypes extends ValidationPropTypes { /** Label width */ width?: number; /** Label alignment */ align?: "left" | "right"; - /** Size of an input Label is used in */ - inputSize: "small" | "medium" | "large"; - /** Flag to indicate that component is used in a Form */ - childOfForm: boolean; /** When true, label is placed in line an input */ inline?: boolean; /** Flag to configure component as mandatory */ @@ -23,18 +20,10 @@ export interface LabelPropTypes { helpId?: string; /** Children elements */ children?: React.ReactNode; - /** Status of error validations */ - error?: string | boolean; - /** Status of warnings */ - warning?: string | boolean; - /** Status of info */ - info?: string | boolean; /** A message that the Help component will display */ help?: React.ReactNode; /** Icon type */ helpIcon?: string; - /** Overrides the default 'as' attribute of the Help component */ - helpTag?: string; /** Overrides the default tabindex of the Help component */ helpTabIndex?: string; /** Whether to show the validation icon */ @@ -45,10 +34,8 @@ export interface LabelPropTypes { pr?: 1 | 2; /** Padding left, integer multiplied by base spacing constant (8) */ pl?: 1 | 2; - /** Allows to override existing component styles */ - styleOverride?: () => object | object; } -declare const Label: React.FunctionComponent; +declare function Label(props: LabelPropTypes): JSX.Element; export default Label; diff --git a/src/__internal__/label/label.spec.js b/src/__internal__/label/label.spec.js index f230525354..c6fba071c1 100644 --- a/src/__internal__/label/label.spec.js +++ b/src/__internal__/label/label.spec.js @@ -106,7 +106,6 @@ describe("Label", () => { it('applies styling for an inline "optional" label', () => { const wrapper = render({ inline: true, - childOfForm: true, optional: true, theme: mintTheme, }); @@ -134,7 +133,6 @@ describe("Label", () => { it('applies styling for an inline "isRequired" label', () => { const wrapper = render({ inline: true, - childOfForm: false, isRequired: true, theme: mintTheme, }); diff --git a/src/__internal__/label/label.style.js b/src/__internal__/label/label.style.js index 1a301d516e..ba82786c51 100644 --- a/src/__internal__/label/label.style.js +++ b/src/__internal__/label/label.style.js @@ -55,17 +55,14 @@ export const StyledLabelContainer = styled.div` width: ${width === 0 ? StyledLabelContainer.defaultProps.width : width}%; `} - ${({ childOfForm, optional }) => - childOfForm && + ${({ optional }) => + optional && css` - ${optional && - css` - ::after { - content: "(optional)"; - font-weight: 350; - margin-left: 4px; - } - `} + ::after { + content: "(optional)"; + font-weight: 350; + margin-left: 4px; + } `} `; diff --git a/src/components/button-toggle-group/__snapshots__/button-toggle-group.spec.js.snap b/src/components/button-toggle-group/__snapshots__/button-toggle-group.spec.js.snap index 2c49ab657d..48ccd4b25c 100644 --- a/src/components/button-toggle-group/__snapshots__/button-toggle-group.spec.js.snap +++ b/src/components/button-toggle-group/__snapshots__/button-toggle-group.spec.js.snap @@ -93,13 +93,13 @@ input:not(:checked):not(:disabled) ~ .c6:hover .c8 {
{ - const { - name, - inputWidth, - error, - warning, - info, - label, - onChange, - onBlur, - children, - value, - validationOnLabel, - } = props; - +const ButtonToggleGroup = ({ + children, + name, + error, + warning, + info, + validationOnLabel, + label, + labelHelp, + labelSpacing, + inputWidth, + fieldHelp, + fieldHelpInline, + labelInline, + labelWidth, + labelAlign, + onChange, + onBlur, + value, + "data-component": dataComponent, + "data-element": dataElement, + "data-role": dataRole, + ...props +}) => { const validationProps = { error, warning, info, }; + return ( - + { ButtonToggleGroup.propTypes = { ...marginPropTypes, + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-component": PropTypes.string, + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-element": PropTypes.string, + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-role": PropTypes.string, /** Specifies the name prop to be applied to each button in the group */ name: PropTypes.string.isRequired, /** Children to be rendered (ButtonToggle). */ @@ -129,6 +159,7 @@ ButtonToggleGroup.propTypes = { ButtonToggleGroup.defaultProps = { validationOnLabel: false, + "data-component": "button-toggle-group", }; ButtonToggleGroup.displayName = "ButtonToggleGroup"; diff --git a/src/components/button-toggle-group/button-toggle-group.d.ts b/src/components/button-toggle-group/button-toggle-group.d.ts index 4b8bc1578e..180111d7d6 100644 --- a/src/components/button-toggle-group/button-toggle-group.d.ts +++ b/src/components/button-toggle-group/button-toggle-group.d.ts @@ -1,4 +1,5 @@ import * as React from "react"; +import { MarginProps } from "styled-system"; import { ButtonToggleProps } from "../button-toggle"; import { ValidationPropTypes } from "../../__internal__/validations"; @@ -9,7 +10,15 @@ type ButtonToggle = | null | undefined; -export interface ButtonToggleGroupProps extends ValidationPropTypes { +export interface ButtonToggleGroupProps + extends ValidationPropTypes, + MarginProps { + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-component"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-element"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-role"?: string; /** Specifies the name prop to be applied to each button in the group */ name: string; /** Children to be rendered (ButtonToggle). */ @@ -40,8 +49,6 @@ export interface ButtonToggleGroupProps extends ValidationPropTypes { onChange?: (ev: React.ChangeEvent) => void; /** The value of the Button Toggle Group */ value?: string; - /** Margin bottom, given number will be multiplied by base spacing unit (8) */ - mb?: 0 | 1 | 2 | 3 | 4 | 5 | 7; } declare function ButtonToggleGroup(props: ButtonToggleGroupProps): JSX.Element; diff --git a/src/components/checkbox/checkbox-group.d.ts b/src/components/checkbox/checkbox-group.d.ts index b5fbd18c42..18e42bf128 100644 --- a/src/components/checkbox/checkbox-group.d.ts +++ b/src/components/checkbox/checkbox-group.d.ts @@ -17,8 +17,6 @@ interface CheckboxGroupProps extends ValidationPropTypes, MarginProps { children: React.ReactNode; /** Specifies the name prop to be applied to each button in the group */ groupName: string; - /** Margin bottom, given number will be multiplied by base spacing unit (8) */ - mb?: 0 | 1 | 2 | 3 | 4 | 5 | 7; /** Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) */ labelSpacing?: 1 | 2; /** Flag to configure component as mandatory */ diff --git a/src/components/checkbox/checkbox.component.js b/src/components/checkbox/checkbox.component.js index c8dab93046..92996171a5 100644 --- a/src/components/checkbox/checkbox.component.js +++ b/src/components/checkbox/checkbox.component.js @@ -1,7 +1,7 @@ import React from "react"; import PropTypes from "prop-types"; import styledSystemPropTypes from "@styled-system/prop-types"; -import tagComponent from "../../utils/helpers/tags"; + import CheckboxStyle from "./checkbox.style"; import CheckableInput from "../../__internal__/checkable-input/checkable-input.component"; import CheckboxSvg from "./checkbox-svg.component"; @@ -21,6 +21,7 @@ const Checkbox = ({ /* FIXME: FE-4102 */ onClick, onBlur, + onFocus, value, fieldHelp, autoFocus, @@ -39,6 +40,9 @@ const Checkbox = ({ inputWidth, size, tooltipPosition, + "data-component": dataComponent, + "data-element": dataElement, + "data-role": dataRole, ...props }) => { const largeScreen = useIsAboveBreakpoint(adaptiveSpacingBreakpoint); @@ -50,11 +54,12 @@ const Checkbox = ({ onClick, onChange, onBlur, + onFocus, labelInline: true, - inputId: id, + id, label, - inputValue: value, - inputType: "checkbox", + value, + type: "checkbox", name, reverse: !reverse, fieldHelp, @@ -71,16 +76,18 @@ const Checkbox = ({ inputWidth, labelWidth, tooltipPosition, + ...props, }; return ( @@ -101,7 +108,13 @@ const Checkbox = ({ Checkbox.propTypes = { /** Filtered styled system margin props */ ...marginPropTypes, - /** Set the value of the checkbox */ + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-component": PropTypes.string, + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-element": PropTypes.string, + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-role": PropTypes.string, + /** Checked state of the input */ checked: PropTypes.bool, /** Toggles disabling of input */ disabled: PropTypes.bool, @@ -125,6 +138,8 @@ Checkbox.propTypes = { onChange: PropTypes.func, /** Accepts a callback function which is triggered on blur event */ onBlur: PropTypes.func, + /** Accepts a callback function which is triggered on focus event */ + onFocus: PropTypes.func, /** Accepts a callback function which is triggered on click event */ onClick: PropTypes.func, /** Reverses label and checkbox display */ @@ -148,7 +163,7 @@ Checkbox.propTypes = { Pass string to display icon, tooltip and blue border Pass true boolean to only display blue border */ info: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), - /** Allows component to be focused on page load */ + /** If true the Component will be focused when page load */ autoFocus: PropTypes.bool, /** The content for the help tooltip, to appear next to the Label */ labelHelp: PropTypes.node, @@ -162,6 +177,7 @@ Checkbox.propTypes = { Checkbox.defaultProps = { reverse: false, + "data-component": "checkbox", }; export default Checkbox; diff --git a/src/components/checkbox/checkbox.d.ts b/src/components/checkbox/checkbox.d.ts index afeb03a5e5..183ddcf3a4 100644 --- a/src/components/checkbox/checkbox.d.ts +++ b/src/components/checkbox/checkbox.d.ts @@ -2,21 +2,15 @@ import * as React from "react"; import { MarginProps } from "styled-system"; import { CommonCheckableInputProps } from "../../__internal__/checkable-input"; -export type CheckboxSize = "small" | "large"; - export interface CheckboxProps extends CommonCheckableInputProps, MarginProps { - /** Breakpoint for adaptive label (inline labels change to top aligned). Enables the adaptive behaviour when set */ - adaptiveLabelBreakpoint?: number; - /** If true the Component will be focused when rendered */ - autoFocus?: boolean; - /** Unique Identifier for the input. Will use a randomly generated GUID if none is provided */ - id?: string; - /** A message that the Help component will display */ - labelHelp?: string | React.ReactNode; - /** Size of the checkbox */ - size?: CheckboxSize; - /** Name of the input */ - name?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-component"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-element"?: string; + /** Identifier used for testing purposes, applied to the root element of the component. */ + "data-role"?: string; + /** Breakpoint for adaptive spacing (left margin changes to 0). Enables the adaptive behaviour when set */ + adaptiveSpacingBreakpoint?: number; /** The value of the checkbox, passed on form submit */ value?: string; /** Overrides the default tooltip position */ diff --git a/src/components/checkbox/checkbox.stories.mdx b/src/components/checkbox/checkbox.stories.mdx index d4a4474d42..83f8213bcc 100644 --- a/src/components/checkbox/checkbox.stories.mdx +++ b/src/components/checkbox/checkbox.stories.mdx @@ -190,6 +190,8 @@ The spacing between the legend and the checkboxes can be changed with the `legen +**Any other supplied props will be provided to the underlying HTML input element** + ### CheckboxGroup diff --git a/src/components/checkbox/checkbox.style.js b/src/components/checkbox/checkbox.style.js index 058628c5b2..cca613cf52 100644 --- a/src/components/checkbox/checkbox.style.js +++ b/src/components/checkbox/checkbox.style.js @@ -201,7 +201,6 @@ CheckboxStyle.propTypes = { info: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), fieldHelpInline: PropTypes.bool, inputWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - labelWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), size: PropTypes.string, }; diff --git a/src/components/date/date.component.js b/src/components/date/date.component.js index 4bbdc5d06d..d4f9c16ca0 100644 --- a/src/components/date/date.component.js +++ b/src/components/date/date.component.js @@ -3,10 +3,12 @@ import PropTypes from "prop-types"; import invariant from "invariant"; import styledSystemPropTypes from "@styled-system/prop-types"; -import { filterStyledSystemMarginProps } from "../../style/utils"; +import { + filterStyledSystemMarginProps, + filterOutStyledSystemSpacingProps, +} from "../../style/utils"; import Events from "../../utils/helpers/events/events"; import DateHelper from "../../utils/helpers/date/date"; -import tagComponent from "../../utils/helpers/tags/tags"; import DatePicker from "./date-picker.component"; import StyledDateInput from "./date.style"; import Textbox from "../textbox"; @@ -21,13 +23,6 @@ const marginPropTypes = filterStyledSystemMarginProps( styledSystemPropTypes.space ); -// Spacing props filtering is a temporary solution until FormField and all related components are refactored -// FIXME FE-3370 -const filterOutSpacingProps = (obj) => - Object.fromEntries( - Object.entries(obj).filter(([key]) => !styledSystemPropTypes.space[key]) - ); - class BaseDateInput extends React.Component { localeData = { locale: this.context.locale(), @@ -485,6 +480,9 @@ class BaseDateInput extends React.Component { adaptiveLabelBreakpoint, disablePortal, tooltipPosition, + "data-component": dataComponent, + "data-element": dataElement, + "data-role": dataRole, ...inputProps } = this.props; @@ -505,11 +503,13 @@ class BaseDateInput extends React.Component { role="presentation" size={inputProps.size} labelInline={labelInline} - {...tagComponent("date", this.props)} + data-component={dataComponent} + data-element={dataElement} + data-role={dataRole} {...filterStyledSystemMarginProps(this.props)} > -### Textbox - -Due to the `Textbox` component being used internally by the `Date` component most of the `Textbox` props are appliable to `Date` +Due to the `Textbox` component being used internally by the `Date` component most of the `Textbox` props are applicable to `Date` +**Any other supplied props will be provided to the underlying HTML input element** + ## Translation keys The following keys are available to override the translations for this component by passing in a custom locale object to the diff --git a/src/components/decimal/decimal.component.js b/src/components/decimal/decimal.component.js index b1cb3ff7dd..19762e7679 100644 --- a/src/components/decimal/decimal.component.js +++ b/src/components/decimal/decimal.component.js @@ -241,7 +241,6 @@ class Decimal extends React.Component { onChange={this.onChange} onBlur={this.onBlur} value={this.state.visibleValue} - data-component="decimal" /> ) => void; /** Handler for key press event */ - onKeyPress?: (ev: React.ChangeEvent) => void; + onKeyPress?: (ev: React.KeyboardEvent) => void; /** The input name */ name?: string; /** The decimal precision of the value in the input */ diff --git a/src/components/decimal/decimal.stories.mdx b/src/components/decimal/decimal.stories.mdx index 7c38595eea..4f044ca416 100644 --- a/src/components/decimal/decimal.stories.mdx +++ b/src/components/decimal/decimal.stories.mdx @@ -466,12 +466,12 @@ It is possible to use the `tooltipPosition` to override the default placement of -### Textbox - -Due to the `Textbox` component being used internally by the `Decimal` component, most of the `Textbox` props are appliable to `Decimal` +Due to the `Textbox` component being used internally by the `Decimal` component, most of the `Textbox` props are applicable to `Decimal` +**Any other supplied props will be provided to the underlying HTML input element** + ## Translation keys The following keys are available to override the translations for this component by passing in a custom locale object to the diff --git a/src/components/form/form.stories.mdx b/src/components/form/form.stories.mdx index f9e0596c42..d599d68cb6 100644 --- a/src/components/form/form.stories.mdx +++ b/src/components/form/form.stories.mdx @@ -486,7 +486,6 @@ Please click on "Show code" below to see how to set these components up for alig fieldSpacing={4} >