Skip to content

Feat/submittable form controls #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ representative at an online or offline event.

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@mimsh.in.
`mostafa.sh.coderino@gmail.com`.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
Expand Down
23 changes: 8 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ git checkout next
git pull upstream next
```

4. Install the dependencies with yarn (npm isn't supported):
4. Install the dependencies with `pnpm` (`npm` and `yarn` aren't supported):

```sh
yarn install
pnpm install
```

5. Create a new topic branch:

```sh
git checkout -b my-topic-branch
git switch -c my-topic-branch
```

6. Make changes, commit and push to your fork:
Expand All @@ -81,7 +81,7 @@ The core team is monitoring for Pull Requests. We will review your Pull Request
Start developing server and watch for code changes:

```sh
yarn dev
pnpm dev
```

The local dev server is a NextJS app.
Expand All @@ -92,27 +92,20 @@ You can import codes and make changes to `/pages/index.tsx` page.
You can build the project, including all type definitions, with:

```sh
yarn build
pnpm build
```

### Testing

To run all the tests, run:

```sh
yarn test
```

To run a specific test, run:

```sh
# ie. yarn test Checkbox.test.tsx
yarn test <filename>
pnpm test
```

### Coding style

Please follow the coding style of the project. StylelessUI uses prettier and eslint, so if possible, enable linting in your editor to get real-time feedback.
Please follow the coding style of the project. StylelessUI uses `prettier` and `eslint`, so if possible, enable linting in your editor to get real-time feedback.

### Git Commit Messages

Expand Down Expand Up @@ -155,4 +148,4 @@ Please follow the coding style of the project. StylelessUI uses prettier and esl

## License

By contributing your code to the styleless-ui/* GitHub repositories, you agree to license your contribution under the MIT license.
By contributing your code to the `styleless-ui/*` GitHub repositories, you agree to license your contribution under the MIT license.
117 changes: 117 additions & 0 deletions lib/CheckGroup/CheckGroup.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import classNames from "classnames";
import type { FormEvent, FormEventHandler } from "react";
import {
act,
itShouldMount,
itSupportsDataSetProps,
itSupportsRef,
Expand Down Expand Up @@ -350,4 +352,119 @@ describe("CheckGroup", () => {
expect(checkbox).toBeDisabled();
});
});

it("should be submitted with the form as part of a name/value pair", () => {
const handleSubmit = jest.fn<void, [FormEvent<HTMLFormElement>]>();

const submitHandler: FormEventHandler<HTMLFormElement> = event => {
event.preventDefault();
handleSubmit(event);
};

const getForm = () => screen.getByTestId<HTMLFormElement>("form");
const getFormData = () => new FormData(getForm());

const { rerender } = render(
<form
data-testid="form"
onSubmit={submitHandler}
>
<CheckGroup
{...mockRequiredProps}
value={[]}
name="n"
>
<Checkbox
label={{ screenReaderLabel: "Checkbox 0" }}
value="v0"
disabled
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 1" }}
value="v1"
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 2" }}
value="v2"
/>
</CheckGroup>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(1);
expect(getFormData().getAll("n")).toEqual([]);

rerender(
<form
data-testid="form"
onSubmit={submitHandler}
>
<CheckGroup
{...mockRequiredProps}
value={["v0", "v1"]}
name="n"
>
<Checkbox
label={{ screenReaderLabel: "Checkbox 0" }}
value="v0"
disabled
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 1" }}
value="v1"
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 2" }}
value="v2"
/>
</CheckGroup>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(2);
expect(getFormData().getAll("n")).toEqual(["v1"]);

rerender(
<form
data-testid="form"
onSubmit={submitHandler}
>
<CheckGroup
{...mockRequiredProps}
disabled
value={["v0", "v1", "v2"]}
name="n"
>
<Checkbox
label={{ screenReaderLabel: "Checkbox 0" }}
value="v0"
disabled
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 1" }}
value="v1"
/>
<Checkbox
label={{ screenReaderLabel: "Checkbox 2" }}
value="v2"
/>
</CheckGroup>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(3);
expect(getFormData().getAll("n")).toEqual([]);
});
});
11 changes: 9 additions & 2 deletions lib/CheckGroup/CheckGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ type OwnProps = {
* @default false
*/
readOnly?: boolean;
/**
* The name of the form control when submitted.
* Submitted with the form as part of a name/value pair.
*/
name?: string;
/**
* The Callback is fired when the state changes.
*/
Expand All @@ -100,6 +105,7 @@ const CheckGroupBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
id: idProp,
disabled,
readOnly,
name,
onValueChange,
orientation = "vertical",
...otherProps
Expand Down Expand Up @@ -154,14 +160,15 @@ const CheckGroupBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
id={id}
ref={ref}
className={className}
data-slot={Slots.Root}
aria-orientation={orientation}
aria-label={labelInfo.srOnlyLabel}
aria-labelledby={labelInfo.labelledBy}
aria-disabled={disabled}
data-slot={Slots.Root}
data-name={name}
>
<CheckGroupContext.Provider
value={{ value, readOnly, disabled, onChange: handleValueChange }}
value={{ value, name, readOnly, disabled, onChange: handleValueChange }}
>
{children}
</CheckGroupContext.Provider>
Expand Down
2 changes: 1 addition & 1 deletion lib/CheckGroup/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { PickAsMandatory } from "../types";
import { type Props } from "./CheckGroup";

type ContextValue = PickAsMandatory<Props, "value"> &
Pick<Props, "readOnly" | "disabled"> & {
Pick<Props, "readOnly" | "disabled" | "name"> & {
onChange: (newCheckedState: boolean, inputValue: string) => void;
};

Expand Down
78 changes: 78 additions & 0 deletions lib/Checkbox/Checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import classNames from "classnames";
import type { FormEvent, FormEventHandler } from "react";
import {
act,
itShouldMount,
itSupportsDataSetProps,
itSupportsFocusEvents,
Expand Down Expand Up @@ -278,4 +280,80 @@ describe("Checkbox", () => {

expect(handleCheckedChange.mock.calls.length).toBe(0);
});

it("should be submitted with the form as part of a name/value pair", () => {
const handleSubmit = jest.fn<void, [FormEvent<HTMLFormElement>]>();

const submitHandler: FormEventHandler<HTMLFormElement> = event => {
event.preventDefault();
handleSubmit(event);
};

const getForm = () => screen.getByTestId<HTMLFormElement>("form");
const getFormData = () => new FormData(getForm());

const { rerender } = render(
<form
data-testid="form"
onSubmit={submitHandler}
>
<Checkbox
{...mockRequiredProps}
checked={false}
name="n"
value="v0"
/>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(1);
expect(getFormData().get("n")).toBe(null);

rerender(
<form
data-testid="form"
onSubmit={submitHandler}
>
<Checkbox
{...mockRequiredProps}
checked={true}
name="n"
value="v0"
/>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(2);
expect(getFormData().get("n")).toBe("v0");

rerender(
<form
data-testid="form"
onSubmit={submitHandler}
>
<Checkbox
{...mockRequiredProps}
disabled
checked={true}
name="n"
value="v0"
/>
</form>,
);

act(() => {
getForm().submit();
});

expect(handleSubmit.mock.calls.length).toBe(3);
expect(getFormData().get("n")).toBe(null);
});
});
Loading