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

Commit

Permalink
AR-2129 Allow all form control children to be removed on subsequent r…
Browse files Browse the repository at this point in the history
…enders (#325)

* Add failing tests for removing FormControl children

* Fix form controls not being removeable
  • Loading branch information
Justin Anastos authored Mar 2, 2021
1 parent 4cc01e7 commit 825c18a
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 30 deletions.
47 changes: 29 additions & 18 deletions src/FormControl/FormControl.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { FormLabel } from "../FormLabel";
import { FormHelperText } from "../FormHelperText";
import { Input } from "../Input";
import { FormErrorMessage } from "../FormErrorMessage";
import { FormEndAdornment } from "../FormEndAdornment";
import { FormStartAdornment } from "../FormStartAdornment";
import { FormDescription } from "../FormDescription";

test("when passed a label, renders it", () => {
render(
Expand Down Expand Up @@ -88,24 +91,6 @@ test("when passed `<FormErrorMessage />`, renders error and svg", () => {
expect(container.querySelector("svg")).toBeInTheDocument();
});

test("when passed `<FormErrorMessage />` that is removed, removes the error message", () => {
const Component: React.FC<{ errorText?: string }> = ({ errorText }) => (
<FormControl id="test">
<Input />
{errorText && <FormErrorMessage>{errorText}</FormErrorMessage>}
</FormControl>
);

const { container, rerender } = render(<Component errorText="error text" />);

expect(screen.getByText("error text")).toBeInTheDocument();
expect(container.querySelector("svg")).toBeInTheDocument();

rerender(<Component />);

expect(screen.queryByText("error text")).not.toBeInTheDocument();
});

test("when passed `<HelperText>` witout `showIcon` prop, renders no svg", () => {
const { container } = render(
<FormControl id="test">
Expand Down Expand Up @@ -143,3 +128,29 @@ test("when not passed `autoFocus` prop, should not have focus after mounting", (

expect(formField).not.toHaveFocus();
});

test.each([
["FormDescription", FormDescription],
["FormEndAdornment", FormEndAdornment],
["FormErrorMessage", FormErrorMessage],
["FormHelperText", FormHelperText],
["FormLabel", FormLabel],
["FormStartAdornment", FormStartAdornment],
])("%s can be removed on subsequent renders", (_, Component) => {
const { rerender } = render(
<FormControl id="test">
<Component>text</Component>
<Input />
</FormControl>,
);

expect(screen.getByText("text")).toBeInTheDocument();

rerender(
<FormControl id="test">
<Input />
</FormControl>,
);

expect(screen.queryByText("text")).not.toBeInTheDocument();
});
2 changes: 2 additions & 0 deletions src/FormDescription/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export const FormDescription: React.FC<Props> = ({

React.useLayoutEffect(() => {
setDescription?.(element);

return () => setDescription?.(null);
}, [element, setDescription]);

return setDescription ? null : element;
Expand Down
11 changes: 5 additions & 6 deletions src/FormEndAdornment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import { useFormControlInternalContext } from "../shared/FormControlContext";
* This is intended to be rendered below `<FormControl>`. If this is rendered on
* it's own; it will render `children` without any modification.
*/
export function FormEndAdornment({
export const FormEndAdornment: React.FC<{ className?: string }> = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}): React.ReactNode {
}) => {
const { setEndAdornment } = useFormControlInternalContext();

const element = React.useMemo(
Expand All @@ -40,7 +37,9 @@ export function FormEndAdornment({

React.useLayoutEffect(() => {
setEndAdornment?.(element);

return () => setEndAdornment?.(null);
}, [element, setEndAdornment]);

return setEndAdornment ? null : element;
}
};
2 changes: 2 additions & 0 deletions src/FormHelperText/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export const FormHelperText: React.FC<Props> = ({
React.useLayoutEffect(() => {
// This will cause a bug if you change the `error` prop
setHelper?.(element);

return () => setHelper?.(null);
}, [element, setHelper]);

// If `setHelper` exists then we're rendering this under the form control
Expand Down
2 changes: 2 additions & 0 deletions src/FormLabel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export const FormLabel: React.FC<Props> = ({

React.useLayoutEffect(() => {
setLabel?.(element);

return () => setLabel?.(null);
}, [element, setLabel]);

return setLabel ? null : element;
Expand Down
11 changes: 5 additions & 6 deletions src/FormStartAdornment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import { useFormControlInternalContext } from "../shared/FormControlContext";
* This is intended to be rendered below `<FormControl>`. If this is rendered on
* it's own; it will render `children` without any modification.
*/
export function FormStartAdornment({
export const FormStartAdornment: React.FC<{ className?: string }> = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}): React.ReactNode {
}) => {
const { setStartAdornment } = useFormControlInternalContext();

const element = React.useMemo(
Expand All @@ -39,7 +36,9 @@ export function FormStartAdornment({

React.useLayoutEffect(() => {
setStartAdornment?.(element);

return () => setStartAdornment?.(null);
}, [element, setStartAdornment]);

return setStartAdornment ? null : element;
}
};

0 comments on commit 825c18a

Please sign in to comment.