Skip to content

Commit

Permalink
Merge pull request #182 from melfore/177-remove-state-from-input
Browse files Browse the repository at this point in the history
Remove internal state from InputText
  • Loading branch information
luciob authored Apr 19, 2021
2 parents e6e4068 + abf1aaf commit 756b35e
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 39 deletions.
56 changes: 30 additions & 26 deletions src/components/InputText/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { boolean, object, select, text } from "@storybook/addon-knobs";

import { Icons } from "../../types/Icon";
import { InputSize, InputType, InputVariant } from "../../types/Input";
import FormMock from "../../utils/mocks/FormMock";
import IntlProviderMock, { LocaleMock, MessageMock } from "../../utils/mocks/IntlProviderMock";
import { getDocumentationPage, StoriesWrapper } from "../../utils/stories";

Expand All @@ -26,34 +27,37 @@ export default {
};

export const Canvas = () => (
<InputText
adornment={object("adornment", undefined)}
disabled={boolean("disabled", false)}
initialValue={text("initialValue", "")}
label={text("label", "Label")}
multiline={object("multiline", undefined)}
onChange={action("onChange callback")}
placeholder={text("placeholder", "Placeholder Text")}
required={boolean("required", false)}
shrink={boolean("shrink", false)}
size={select("size", InputSize, InputSize.default)}
type={select("type", InputType, InputType.default)}
variant={select("variant", InputVariant, InputVariant.default)}
/>
// FormMock simulates external form component handling state
// In a real case scenario "onChange" and "value" props must be passed to InputText
<FormMock inputValue={text("value", "Some text")} onInputChange={action("onChange callback")}>
<InputText
adornment={object("adornment", undefined)}
disabled={boolean("disabled", false)}
label={text("label", "Label")}
multiline={object("multiline", undefined)}
onChange={action("onChange callback")}
placeholder={text("placeholder", "Placeholder Text")}
required={boolean("required", false)}
size={select("size", InputSize, InputSize.default)}
type={select("type", InputType, InputType.default)}
value={text("value", "")}
variant={select("variant", InputVariant, InputVariant.default)}
/>
</FormMock>
);

export const CustomStyle = () => (
<InputText
initialValue="Some text"
label="Custom Style"
style={{ color: "red", fontWeight: "bold", fontSize: "large", textAlign: "center" }}
value="Some text"
/>
);

export const Disabled = () => (
<StoriesWrapper>
<InputText disabled label="Label" />
<InputText disabled initialValue="Disabled" label="Label" />
<InputText disabled label="Label" value="Disabled" />
</StoriesWrapper>
);

Expand All @@ -72,53 +76,53 @@ export const Localized = () => (
export const Multiline = () => (
<StoriesWrapper>
<InputText
initialValue="Multiline by one"
label="Label"
multiline={{
rows: 1,
}}
value="Multiline by one"
/>
<InputText
initialValue="Multiline by three"
label="Label"
multiline={{
rows: 3,
}}
value="Multiline by three"
/>
<InputText
initialValue="Multiline max five, broken in MUI"
label="Label"
multiline={{
rows: 3,
rowsMax: 5,
}}
value="Multiline max five, broken in MUI"
/>
</StoriesWrapper>
);

export const Required = () => <InputText initialValue="Required" label="Label" required />;
export const Required = () => <InputText value="Required" label="Label" required />;

export const Size = () => (
<StoriesWrapper>
<InputText initialValue="Default" label="Label" />
<InputText initialValue="Small" label="Label" size={InputSize.small} />
<InputText label="Label" value="Default" />
<InputText label="Label" size={InputSize.small} value="Small" />
</StoriesWrapper>
);

export const Variant = () => (
<StoriesWrapper>
<InputText initialValue="Default" label="Label" />
<InputText initialValue="Filled" label="Label" variant={InputVariant.filled} />
<InputText label="Label" value="Default" />
<InputText label="Label" variant={InputVariant.filled} value="Filled" />
</StoriesWrapper>
);

export const WithAdornment = () => (
<StoriesWrapper>
<InputText adornment={{ icon: Icons.search }} initialValue="Adornment used to render icon" label="Label" />
<InputText adornment={{ icon: Icons.search }} value="Adornment used to render icon" label="Label" />
<InputText
adornment={{ icon: Icons.close, onClick: action("On Clear") }}
initialValue="Adornment is clickable and triggers an action"
label="Label"
value="Adornment is clickable and triggers an action"
/>
</StoriesWrapper>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/InputText/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ describe("InputText test suite:", () => {
});

it("value", () => {
const initialValue = "Initial Text Value";
const { element, wrapper } = getInputTextTestable({ initialValue });
expect(wrapper.prop("value")).toEqual(initialValue);
const value = "Initial Text Value";
const { element, wrapper } = getInputTextTestable({ value });
expect(wrapper.prop("value")).toEqual(value);

const snapshotWrapper = renderer.create(element).toJSON();
expect(snapshotWrapper).toMatchSnapshot();
Expand Down
12 changes: 3 additions & 9 deletions src/components/InputText/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { CSSProperties, FC, useEffect, useState } from "react";
import React, { CSSProperties, FC } from "react";
import { InputAdornment as MUIInputAdornment, TextField as MUITextField } from "@material-ui/core";

import { IconSize } from "../../types/Icon";
Expand Down Expand Up @@ -47,7 +47,6 @@ const InputText: FC<IInputText> = ({
adornment = undefined,
dataCy = DATA_CY_DEFAULT,
disabled = false,
initialValue = "",
label,
multiline = undefined,
onChange = undefined,
Expand All @@ -57,19 +56,14 @@ const InputText: FC<IInputText> = ({
size = InputSize.default,
style,
type = InputType.default,
value = "",
variant = InputVariant.default,
}) => {
const baseStyle: CSSProperties = { width: "100%" };

const [value, setValue] = useState(initialValue);
useEffect(() => setValue(initialValue), [initialValue]);

const onChangeHandler = (event: any) => {
const value = event.target.value;
setValue(value);
if (onChange) {
onChange(value);
}
onChange && onChange(value);
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/types/InputText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface IInputAdornment {

export interface IInputText extends IInput {
adornment?: IInputAdornment;
initialValue?: string;
multiline?: IMultilineInput;
type?: InputType;
value?: string;
}
76 changes: 76 additions & 0 deletions src/utils/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { getAllComposedDataCy, getComposedDataCy, getObjectProperty, slugify, suppressEvent } from "./index";

describe("getAllComposedDataCy", () => {
it("all", () => {
expect(
getAllComposedDataCy({
label: {
label: "Label",
},
value: {
label: "Label",
value: () => "value",
},
})
).toEqual([
{
label: "Label",
suffix: "label",
},
{
label: "Label",
suffix: "value",
},
]);
});
});

describe("getComposedDataCy", () => {
it("valid", () => {
const subpart = { label: "Subpart Label" };
expect(getComposedDataCy("data-cy", subpart)).toEqual("data-cy-subpart-label");
});

it("valid - explicit value", () => {
const subpart = { label: "Subpart Label", value: () => "Subpart Value" };
expect(getComposedDataCy("data-cy", subpart)).toEqual("data-cy-Subpart Value");
});

it("valid - explicit value with args", () => {
const subpart = { label: "Subpart Label", value: (int: number) => `Subpart Value [${int}]` };
expect(getComposedDataCy("data-cy", subpart, 123)).toEqual("data-cy-Subpart Value [123]");
});
});

describe("getObjectProperty", () => {
it("all", () => {
expect(getObjectProperty(undefined, "path")).toEqual(undefined);
expect(getObjectProperty(null, "path")).toEqual(undefined);
expect(getObjectProperty({}, "path")).toEqual(undefined);
expect(getObjectProperty({ path: "value" }, "path.nested")).toEqual(undefined);
expect(getObjectProperty({ path: "value" }, "path")).toEqual("value");
expect(getObjectProperty({ path: { nested: "value" } }, "path.nested")).toEqual("value");
});
});

describe("slugify", () => {
it("all", () => {
expect(slugify("SlugifyPlease")).toEqual("slugifyplease");
expect(slugify("Slugify Please")).toEqual("slugify-please");
});
});

describe("suppressEvent", () => {
it("invalid", () => {
expect(suppressEvent(null));
});

it("valid", () => {
const preventDefault = jest.fn();
const stopPropagation = jest.fn();
const mockedEvent: any = { preventDefault, stopPropagation };
expect(suppressEvent(mockedEvent));
expect(preventDefault).toHaveBeenCalledTimes(1);
expect(preventDefault).toHaveBeenCalledTimes(1);
});
});

0 comments on commit 756b35e

Please sign in to comment.