Skip to content

Commit

Permalink
feat: booleanFIeld input hook and demo
Browse files Browse the repository at this point in the history
  • Loading branch information
MiroslavPetrik committed Mar 1, 2023
1 parent 3b0c40e commit d6957ba
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 5 deletions.
52 changes: 49 additions & 3 deletions src/fields/boolean-field/Docs.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Meta, Markdown } from "@storybook/blocks";

import { Meta, Markdown, Stories } from "@storybook/blocks";
import * as BooleanFieldStories from "./booleanField.stories";
import Config from "./config.md?raw";

<Meta title="fields/booleanField" />
<Meta title="fields/booleanField" of={BooleanFieldStories} />

# `booleanField(): ValidatedFieldAtom<boolean | undefined>`

Expand All @@ -23,3 +23,49 @@ const yesNoAnswer = booleanField({
## Initial Config

<Markdown>{Config}</Markdown>

## useBooleanFieldProps()

The `useBooleanFieldProps` will parse the input values as boolean. You can think of it like `valueAsBoolean` which is similar to `valueAsNumber` used in the `useNumberFieldProps`.
Note that the example uses generic `useSelectOptions` hook.

```tsx
const YesNoOptions = <Option,>({
field,
label,
getValue,
getLabel,
options,
}: SelectFieldProps<Option, boolean>) => {
const props = useBooleanFieldProps(field);

const { renderOptions } = useSelectOptions(field, {
getValue,
getLabel,
options,
});

return (
<div style={{ margin: "20px 0" }}>
<FieldLabel field={field} label={label} />
{renderOptions.map(({ id, value, label, isActive }) => (
<div key={id}>
<input
type="radio"
{...props}
id={id}
value={`${value}`}
checked={isActive}
/>
<label htmlFor={id}>{label}</label>
</div>
))}
<div>
<FieldErrors field={field} />
</div>
</div>
);
};
```

<Stories />
99 changes: 99 additions & 0 deletions src/fields/boolean-field/booleanField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { booleanField } from "./booleanField";
import { useBooleanFieldProps } from "./useBooleanFieldProps";
import { FieldLabel } from "../../components";
import { FieldErrors } from "../../components/field-errors";
import { FormStory, fixArgs, meta } from "../../scenarios/StoryForm";
import { SelectFieldProps, useSelectOptions } from "../select-field";

export default {
...meta,
title: "fields/booleanField",
};

const YesNoOptions = <Option,>({
field,
label,
getValue,
getLabel,
options,
}: SelectFieldProps<Option, boolean>) => {
const props = useBooleanFieldProps(field);

const { renderOptions } = useSelectOptions(field, {
getValue,
getLabel,
options,
});

return (
<div style={{ margin: "20px 0" }}>
<FieldLabel field={field} label={label} />
{renderOptions.map(({ id, value, label, isActive }) => (
<div key={id}>
<input
type="radio"
{...props}
id={id}
value={`${value}`}
checked={isActive}
/>
<label htmlFor={id}>{label}</label>
</div>
))}
<div>
<FieldErrors field={field} />
</div>
</div>
);
};

const yesNoOptions = [
{
label: "Yes, I accept the Funeral terms.",
value: true,
},
{
label: "No, I don't accept the Funeral terms.",
value: false,
},
];
export const Required: FormStory = {
args: fixArgs({
fields: {
termsOfService: booleanField(),
},
children: ({ fields }) => (
<YesNoOptions
field={fields.termsOfService}
label="Do you accept the Funeral terms?"
options={yesNoOptions}
getLabel={({ label }) => label}
getValue={({ value }) => value}
/>
),
}),
};

// export const Optional: FormStory = {
// args: fixArgs({
// fields: {
// newsletter: checkboxField({
// optional: true,
// }),
// },
// children: ({ fields }) => (
// <CheckboxInput
// field={fields.newsletter}
// label="Subscribe to newsletter"
// />
// ),
// }),
// parameters: {
// docs: {
// description: {
// story:
// "Optional checkboxField will have true or false value in the submit data.",
// },
// },
// },
// };
10 changes: 8 additions & 2 deletions src/fields/boolean-field/booleanField.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { z } from "zod";

import { ValidatedFieldAtomConfig, validatedFieldAtom } from "..";
import {
ValidatedFieldAtom,
ValidatedFieldAtomConfig,
validatedFieldAtom,
} from "..";
import { ZodParams, defaultParams } from "../zodParams";

export type BooleanFieldValue = boolean | undefined;

export type BooleanFieldAtom = ValidatedFieldAtom<BooleanFieldValue>;

export const booleanField = ({
required_error = defaultParams.required_error,
...config
}: Partial<ValidatedFieldAtomConfig<BooleanFieldValue>> & ZodParams) =>
}: Partial<ValidatedFieldAtomConfig<BooleanFieldValue>> & ZodParams = {}) =>
validatedFieldAtom({
value: undefined,
schema: z.boolean({ required_error }),
Expand Down
15 changes: 15 additions & 0 deletions src/fields/boolean-field/useBooleanFieldProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ChangeEvent } from "react";

import { BooleanFieldAtom } from "./booleanField";
import { FieldProps, useFieldProps } from "../../hooks";

export type NumberFieldProps = FieldProps<BooleanFieldAtom>;

const valueAsBoolean = (event: ChangeEvent<HTMLInputElement>) => {
const value = JSON.parse(event.currentTarget.value);

return typeof value === "boolean" ? value : undefined;
};

export const useBooleanFieldProps = (field: BooleanFieldAtom) =>
useFieldProps(field, valueAsBoolean);

0 comments on commit d6957ba

Please sign in to comment.