Skip to content

Commit 80c22ba

Browse files
committed
fix(form): fixed floating label behavior for TextArea
Also wrote a sanity check for the `NativeSelect` component Closes #1043
1 parent c737a6d commit 80c22ba

File tree

3 files changed

+107
-3
lines changed

3 files changed

+107
-3
lines changed

packages/form/src/select/__tests__/NativeSelect.tsx

+55-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from "react";
2-
import { render } from "@testing-library/react";
1+
import React, { ReactElement, useState } from "react";
2+
import { fireEvent, render } from "@testing-library/react";
33

44
import { NativeSelect } from "../NativeSelect";
55

@@ -43,4 +43,57 @@ describe("NativeSelect", () => {
4343
rerender(<NativeSelect {...PROPS} multiple />);
4444
expect(getIcon(container)).toBe(null);
4545
});
46+
47+
it("should handle the floating label state correctly for controlled values", () => {
48+
function Test(): ReactElement {
49+
const [value, setValue] = useState("");
50+
51+
return (
52+
<>
53+
<button type="button" onClick={() => setValue(options[2])}>
54+
Set
55+
</button>
56+
<button type="button" onClick={() => setValue("")}>
57+
Reset
58+
</button>
59+
<NativeSelect
60+
id="field-id"
61+
label="Label"
62+
value={value}
63+
onChange={(event) => setValue(event.currentTarget.value)}
64+
>
65+
{options.map((opt) => (
66+
<option key={opt}>{opt}</option>
67+
))}
68+
</NativeSelect>
69+
</>
70+
);
71+
}
72+
73+
const { getByRole, getByText } = render(<Test />);
74+
75+
const setButton = getByRole("button", { name: "Set" });
76+
const resetButton = getByRole("button", { name: "Reset" });
77+
const field = getByRole("combobox") as HTMLSelectElement;
78+
const label = getByText("Label");
79+
expect(label.className).not.toContain("rmd-floating-label--active");
80+
expect(label.className).not.toContain("rmd-floating-label--inactive");
81+
82+
fireEvent.click(setButton);
83+
expect(label.className).toContain("rmd-floating-label--active");
84+
expect(label.className).toContain("rmd-floating-label--inactive");
85+
86+
fireEvent.focus(field);
87+
fireEvent.change(field, { target: { value: options[1] } });
88+
expect(label.className).toContain("rmd-floating-label--active");
89+
expect(label.className).not.toContain("rmd-floating-label--inactive");
90+
91+
fireEvent.blur(field);
92+
expect(label.className).toContain("rmd-floating-label--active");
93+
expect(label.className).toContain("rmd-floating-label--inactive");
94+
95+
fireEvent.click(resetButton);
96+
expect(label.className).not.toContain("rmd-floating-label--active");
97+
expect(label.className).not.toContain("rmd-floating-label--inactive");
98+
});
4699
});

packages/form/src/text-field/TextArea.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
248248
mask.value = event.currentTarget.value;
249249
updateHeight();
250250
},
251+
value,
252+
defaultValue,
251253
});
252254

253255
const [ref, refHandler] = useEnsuredRef(forwardedRef);

packages/form/src/text-field/__tests__/TextArea.tsx

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// TODO: Figure out how to test the resize behavior in jsdom, or just write
22
// tests with cypress
3-
import React from "react";
3+
import React, { ReactElement, useState } from "react";
44
import { act, fireEvent, render } from "@testing-library/react";
55
import { mocked } from "ts-jest/utils";
66
import ResizeObserverPolyfill from "resize-observer-polyfill";
@@ -145,4 +145,53 @@ describe("TextArea", () => {
145145
rerender(<TextArea {...props} resize="horizontal" />);
146146
expect(realContainer).toHaveClass("rmd-text-field-container--inline");
147147
});
148+
149+
it("should handle the floating label state correctly for controlled values", () => {
150+
function Test(): ReactElement {
151+
const [value, setValue] = useState("");
152+
153+
return (
154+
<>
155+
<button type="button" onClick={() => setValue("100")}>
156+
Set
157+
</button>
158+
<button type="button" onClick={() => setValue("")}>
159+
Reset
160+
</button>
161+
<TextArea
162+
id="field-id"
163+
label="Label"
164+
value={value}
165+
onChange={(event) => setValue(event.currentTarget.value)}
166+
/>
167+
</>
168+
);
169+
}
170+
171+
const { getByRole, getByText } = render(<Test />);
172+
173+
const setButton = getByRole("button", { name: "Set" });
174+
const resetButton = getByRole("button", { name: "Reset" });
175+
const field = getByRole("textbox") as HTMLInputElement;
176+
const label = getByText("Label");
177+
expect(label.className).not.toContain("rmd-floating-label--active");
178+
expect(label.className).not.toContain("rmd-floating-label--inactive");
179+
180+
fireEvent.click(setButton);
181+
expect(label.className).toContain("rmd-floating-label--active");
182+
expect(label.className).toContain("rmd-floating-label--inactive");
183+
184+
fireEvent.focus(field);
185+
fireEvent.change(field, { target: { value: "100-" } });
186+
expect(label.className).toContain("rmd-floating-label--active");
187+
expect(label.className).not.toContain("rmd-floating-label--inactive");
188+
189+
fireEvent.blur(field);
190+
expect(label.className).toContain("rmd-floating-label--active");
191+
expect(label.className).toContain("rmd-floating-label--inactive");
192+
193+
fireEvent.click(resetButton);
194+
expect(label.className).not.toContain("rmd-floating-label--active");
195+
expect(label.className).not.toContain("rmd-floating-label--inactive");
196+
});
148197
});

0 commit comments

Comments
 (0)