Skip to content
This repository has been archived by the owner on Jan 23, 2025. It is now read-only.

Commit

Permalink
ui-components: Input component accepts all native input props
Browse files Browse the repository at this point in the history
- InputProps are extended with HTMLInputElementAttributes to
allow provide all allowed props down to <input> element
and do not limit usage of component.
- `prefix` prop is renamed to avoid naming conflicts with
native `prefix` prop.
  • Loading branch information
koorosh committed May 29, 2020
1 parent 299f2a3 commit 8face4e
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 11 deletions.
4 changes: 2 additions & 2 deletions packages/storybook-ui-components/stories/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const SearchInput = () => {
onChange={setValue}
invalid={boolean("invalid", false)}
placeholder={text("Placeholder", "Search...")}
prefix={<Search />}
prefixIcon={<Search />}
/>
);
};
Expand All @@ -58,7 +58,7 @@ export const NumberInputWithIcon = () => {
onChange={setValue}
invalid={boolean("invalid", false)}
placeholder={text("Placeholder", "Counter...")}
prefix={<Search />}
prefixIcon={<Search />}
/>
);
};
16 changes: 13 additions & 3 deletions packages/ui-components/src/Input/BaseInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, {
import classNames from "classnames/bind";
import styles from "./styles.module.scss";

export interface InputProps<T = string | number> {
type OwnInputProps<T = string | number> = {
type?: T extends string ? "text" : "number";
initialValue?: T;
value?: T;
Expand All @@ -21,8 +21,16 @@ export interface InputProps<T = string | number> {
name?: string;
disabled?: boolean;
invalid?: boolean;
prefix?: React.ReactNode;
}
prefixIcon?: React.ReactNode;
};

type NativeInputProps<T> = Omit<
React.InputHTMLAttributes<HTMLInputElement>,
keyof OwnInputProps<T>
>;

export type InputProps<T = string | number> = NativeInputProps<T> &
OwnInputProps<T>;

const cx = classNames.bind(styles);

Expand All @@ -38,6 +46,7 @@ export const BaseInput: React.FC<InputProps> = ({
onChange,
disabled = false,
invalid = false,
...props
}) => {
const [value, setValue] = useState<string | number>(
outerValue || initialValue,
Expand Down Expand Up @@ -78,6 +87,7 @@ export const BaseInput: React.FC<InputProps> = ({

return (
<input
{...props}
name={name}
type={type}
value={value}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui-components/src/Input/NumberInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const NumberInput: React.FC<NumberInputProps> = ({
onChange,
value: outerValue,
initialValue,
prefix,
prefixIcon,
invalid,
disabled,
...props
Expand Down Expand Up @@ -49,7 +49,7 @@ export const NumberInput: React.FC<NumberInputProps> = ({

return (
<InputWrapper disabled={disabled} invalid={invalid} className="number-type">
<InputPrefix>{prefix}</InputPrefix>
<InputPrefix>{prefixIcon}</InputPrefix>
<BaseInput
{...props}
disabled={disabled}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui-components/src/Input/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { InputPrefix, InputWrapper } from "./helpers";
export type TextInputProps = Omit<InputProps<string>, "type">;

export const TextInput: React.FC<TextInputProps> = props => {
const { prefix, disabled, invalid } = props;
const { prefixIcon, disabled, invalid } = props;
return (
<InputWrapper disabled={disabled} invalid={invalid}>
<InputPrefix>{prefix}</InputPrefix>
<InputPrefix>{prefixIcon}</InputPrefix>
<BaseInput {...props} type="text" />
</InputWrapper>
);
Expand Down
34 changes: 32 additions & 2 deletions packages/ui-components/src/Input/input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ describe("TextInput", () => {
expect(props.style).toBeUndefined();
});
});

it("applies native <input> props and event handlers", () => {
const onSubmitSpyFn = jasmine.createSpy();
const wrapper = shallow<HTMLDivElement>(
<TextInput onSubmit={onSubmitSpyFn} aria-label="number-input-el" />,
);
const inputElWrapper = wrapper
.find(BaseInput)
.dive()
.find("input")
.at(0);
inputElWrapper.simulate("submit");
expect(onSubmitSpyFn).toHaveBeenCalled();
expect(inputElWrapper.prop("aria-label")).toEqual("number-input-el");
});
});

describe("NumberInput", () => {
Expand All @@ -89,6 +104,21 @@ describe("NumberInput", () => {
inputWrapper.prop("onChange")("abc");
expect(onChangeSpyFn).not.toHaveBeenCalled();
});

it("applies native <input> props and event handlers", () => {
const onSubmitSpyFn = jasmine.createSpy();
const wrapper = shallow<HTMLDivElement>(
<NumberInput onSubmit={onSubmitSpyFn} aria-label="number-input-el" />,
);
const inputElWrapper = wrapper
.find(BaseInput)
.dive()
.find("input")
.at(0);
inputElWrapper.simulate("submit");
expect(onSubmitSpyFn).toHaveBeenCalled();
expect(inputElWrapper.prop("aria-label")).toEqual("number-input-el");
});
});

describe("Spin buttons handlers", () => {
Expand Down Expand Up @@ -126,13 +156,13 @@ describe("NumberInput", () => {

describe("Input with prefixed Icon", () => {
it("renders Icon with TextInput component", () => {
const wrapper = shallow(<TextInput prefix={<Search />} />);
const wrapper = shallow(<TextInput prefixIcon={<Search />} />);
const prefixWrapper = wrapper.find(Search);
expect(prefixWrapper).toBeDefined();
});

it("renders Icon with NumberInput component", () => {
const wrapper = shallow(<NumberInput prefix={<Search />} />);
const wrapper = shallow(<NumberInput prefixIcon={<Search />} />);
const prefixWrapper = wrapper.find(Search);
expect(prefixWrapper).toBeDefined();
});
Expand Down

0 comments on commit 8face4e

Please sign in to comment.