Skip to content

Commit

Permalink
Merge pull request #108 from mathisobadia/develop
Browse files Browse the repository at this point in the history
Add submitOnEnter prop to TextField.TextArea
  • Loading branch information
fabien-ml committed May 8, 2023
2 parents 0e3f533 + 2d6b03c commit e346b9f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
7 changes: 4 additions & 3 deletions apps/docs/src/routes/docs/core/components/text-field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,10 @@ function HTMLFormExample() {

### TextField.TextArea

| Prop | Description |
| :--------- | :------------------------------------------------------------------------------------ |
| autoResize | `boolean` <br/> Whether the textarea should adjust its height when the value changes. |
| Prop | Description |
| :------------ | :---------------------------------------------------------------------------------------- |
| autoResize | `boolean` <br/> Whether the textarea should adjust its height when the value changes. |
| submitOnEnter | `boolean` <br/> Whether the form should be submitted when the user presses the enter key. |

### TextField.ErrorMessage

Expand Down
18 changes: 16 additions & 2 deletions packages/core/src/text-field/text-field-text-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* https://github.com/adobe/react-spectrum/blob/0af91c08c745f4bb35b6ad4932ca17a0d85dd02c/packages/@react-spectrum/textfield/src/TextArea.tsx
*/

import { mergeDefaultProps, mergeRefs, OverrideComponentProps } from "@kobalte/utils";
import { composeEventHandlers, mergeDefaultProps, mergeRefs, OverrideComponentProps } from "@kobalte/utils";
import { createEffect, on, splitProps } from "solid-js";

import { AsChildProp } from "../polymorphic";
Expand All @@ -17,6 +17,9 @@ import { TextFieldInputBase } from "./text-field-input";
export interface TextFieldTextAreaOptions extends AsChildProp {
/** Whether the textarea should adjust its height when the value changes. */
autoResize?: boolean;

/** Whether the form should be submitted when the user presses the enter key. */
submitOnEnter?: boolean;
}

export interface TextFieldTextAreaProps
Expand All @@ -37,7 +40,7 @@ export function TextFieldTextArea(props: TextFieldTextAreaProps) {
props
);

const [local, others] = splitProps(props, ["ref", "autoResize"]);
const [local, others] = splitProps(props, ["ref", "autoResize", "submitOnEnter", "onKeyPress"]);

createEffect(
on([() => ref, () => local.autoResize, () => context.value()], ([ref, autoResize]) => {
Expand All @@ -49,9 +52,20 @@ export function TextFieldTextArea(props: TextFieldTextAreaProps) {
})
);

const onKeyPress = (event: KeyboardEvent) => {
if (ref && local.submitOnEnter && event.key === "Enter" && !event.shiftKey) {
if (ref.form) {
ref.form.requestSubmit();
event.preventDefault();
}
}
};

return (
<TextFieldInputBase
as="textarea"
aria-multiline={local.submitOnEnter ? "false" : undefined}
onKeyPress={composeEventHandlers([local.onKeyPress, onKeyPress])}
ref={mergeRefs(el => (ref = el), local.ref) as any}
{...(others as any)}
/>
Expand Down
69 changes: 69 additions & 0 deletions packages/core/src/text-field/text-field.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -396,4 +396,73 @@ describe("TextField", () => {
expect(input).toHaveAttribute("readonly");
expect(input).toHaveAttribute("aria-readonly", "true");
});

it("should have 'aria-multiline' set to false on textarea when 'submitOnEnter' is true", () => {
render(() => (
<TextField.Root>
<TextField.TextArea submitOnEnter />
</TextField.Root>
));

const input = screen.getByRole("textbox") as HTMLInputElement;
expect(input).toHaveAttribute("aria-multiline", "false");
});

it("should not have 'aria-multiline' on textarea when 'submitOnEnter' is false", () => {
render(() => (
<TextField.Root>
<TextField.TextArea />
</TextField.Root>
));

const input = screen.getByRole("textbox") as HTMLInputElement;
expect(input).not.toHaveAttribute("aria-multiline");
});

it("form is submitted when 'submitOnEnter' is true and user presses the enter key", async () => {
const onSubmit = jest.fn();
render(() => (
<form onSubmit={onSubmit}>
<TextField.Root>
<TextField.TextArea submitOnEnter />
</TextField.Root>
</form>
));

const input = screen.getByRole("textbox") as HTMLInputElement;
await userEvent.type(input, "abc{enter}");
expect(onSubmit).toHaveBeenCalledTimes(1);
});

it("form is not submitted when 'submitOnEnter' is true and the user presses shift + enter at the same time", async () => {
const onSubmit = jest.fn();

render(() => (
<form onSubmit={onSubmit}>
<TextField.Root>
<TextField.TextArea submitOnEnter />
</TextField.Root>
</form>
));

const input = screen.getByRole("textbox") as HTMLInputElement;
await userEvent.type(input, "{Shift>}enter{/Shift}");
expect(onSubmit).not.toHaveBeenCalled();
});

it("form is not submitted when 'submitOnEnter' is not set and user presses the enter key", async () => {
const onSubmit = jest.fn();

render(() => (
<form onSubmit={onSubmit}>
<TextField.Root>
<TextField.TextArea />
</TextField.Root>
</form>
));

const input = screen.getByRole("textbox") as HTMLInputElement;
await userEvent.type(input, "{enter}");
expect(onSubmit).not.toHaveBeenCalled();
});
});

0 comments on commit e346b9f

Please sign in to comment.