Skip to content

Commit

Permalink
refactor(inputs): change the way props are spread internally
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
Props not declared in propTypes (including className) are no longer
being spread on the root element in following components:
ButtonToggleGroup, Checkbox, Date, Decimal,
GroupedCharacter, Number, RadioButton, Select, MultiSelect,
FilterableSelect, Switch, Textarea, Textbox.

Furthermore in all these components apart from the ButtonToggleGroup
all not declared props will be passed to the underlying HTML input
element
  • Loading branch information
mkrds committed Sep 24, 2021
1 parent 614f6e2 commit 1cc93ec
Show file tree
Hide file tree
Showing 73 changed files with 942 additions and 621 deletions.
2 changes: 1 addition & 1 deletion cypress/locators/switch/locators.js
Original file line number Diff line number Diff line change
@@ -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;
31 changes: 15 additions & 16 deletions src/__internal__/checkable-input/checkable-input.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ import HiddenCheckableInput from "./hidden-checkable-input.component";
import guid from "../../utils/helpers/guid";

const CheckableInput = ({
autoFocus,
checked,
children,
disabled,
error,
fieldHelp,
fieldHelpInline,
info,
inputId,
id: inputId,
inputRef,
inputType,
inputValue,
type,
value,
inputWidth,
label,
labelAlign,
Expand All @@ -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,
Expand All @@ -56,7 +56,6 @@ const CheckableInput = ({
labelAlign,
labelHelp,
labelHelpIcon: "info",
labelId,
labelInline,
labelSpacing,
name: id,
Expand All @@ -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 (
Expand All @@ -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) */
Expand All @@ -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 */
Expand All @@ -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,
Expand Down
34 changes: 14 additions & 20 deletions src/__internal__/checkable-input/checkable-input.d.ts
Original file line number Diff line number Diff line change
@@ -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 */
Expand All @@ -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<HTMLInputElement>) => void;
/** Specify a callback triggered on focus */
onFocus?: (ev: React.FocusEvent<HTMLInputElement>) => void;
/** Specify a callback triggered on change */
onChange?: (ev: React.ChangeEvent<HTMLInputElement>) => 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<HTMLInputElement>
> {}
declare function CheckableInput(props: CheckableInputProps): JSX.Element;

export default CheckableInput;
19 changes: 6 additions & 13 deletions src/__internal__/checkable-input/checkable-input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -23,27 +23,20 @@ function render(props) {
describe("CheckableInput", () => {
function mountInput(props) {
return mount(
<CheckableInput
inputType="text"
inputValue=""
onChange={() => null}
{...props}
/>
<CheckableInput type="text" value="" onChange={() => 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");
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 (
<HiddenCheckableInputStyle
aria-checked={props.checked}
aria-labelledby={labelId}
autoFocus={autoFocus}
aria-checked={checked}
checked={checked}
aria-describedby={helpId}
name={name}
role={inputType}
tabIndex={tabindex}
type={inputType}
value={inputValue}
role={type}
type={type}
value={value}
{...props}
onFocus={handleFocus}
onBlur={handleBlur}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onChange={onChange}
ref={inputRef}
/>
);
};

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,
Expand Down
42 changes: 42 additions & 0 deletions src/__internal__/checkable-input/hidden-checkable-input.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as React from "react";

export interface CommonHiddenCheckableInputProps
extends Omit<
React.InputHTMLAttributes<HTMLInputElement>,
"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<HTMLInputElement>) => void;
/** OnFocus event handler */
onFocus?: (ev: React.FocusEvent<HTMLInputElement>) => void;
/** Blur event handler */
onBlur?: (ev: React.FocusEvent<HTMLInputElement>) => void;
/** OnMouseLeave event handler */
onMouseLeave?: (ev: React.MouseEvent<HTMLInputElement>) => void;
/** OnMouseEnter event handler */
onMouseEnter?: (ev: React.MouseEvent<HTMLInputElement>) => void;
/** Value of the input */
value?: string;
/** A callback to retrieve the input reference */
inputRef: React.Ref<HTMLInputElement>;
}

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;
Loading

0 comments on commit 1cc93ec

Please sign in to comment.