Skip to content
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

feat: handle change method #58

Merged
merged 8 commits into from
Jan 18, 2021
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
6 changes: 2 additions & 4 deletions examples/basic-forms/1-basic-form-naive/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Example: React.FC = () => {
<input
id={name.id}
value={name.value}
onChange={e => name.setValue(e.target.value)}
onChange={name.handleChange}
onBlur={name.handleBlur}
autoComplete="off"
/>
Expand All @@ -45,9 +45,7 @@ const Example: React.FC = () => {
type="number"
id={age.id}
value={age.value}
onChange={e =>
age.setValue(e.target.value === "" ? "" : +e.target.value)
}
onChange={age.handleChange}
onBlur={age.handleBlur}
autoComplete="off"
/>
Expand Down
6 changes: 2 additions & 4 deletions examples/basic-forms/2-basic-form-improved/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const NameField: React.FC = () => {
<input
id={field.id}
value={field.value}
onChange={e => field.setValue(e.target.value)}
onChange={field.handleChange}
onBlur={field.handleBlur}
autoComplete="off"
/>
Expand All @@ -60,9 +60,7 @@ const AgeField: React.FC = () => {
type="number"
id={field.id}
value={field.value}
onChange={e =>
field.setValue(e.target.value === "" ? "" : +e.target.value)
}
onChange={field.handleChange}
onBlur={field.handleBlur}
autoComplete="off"
/>
Expand Down
6 changes: 2 additions & 4 deletions examples/basic-forms/3-basic-form-validation/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const NameField: React.FC = () => {
<input
id={field.id}
value={field.value}
onChange={e => field.setValue(e.target.value)}
onChange={field.handleChange}
onBlur={field.handleBlur}
autoComplete="off"
/>
Expand All @@ -80,9 +80,7 @@ const AgeField: React.FC = () => {
type="number"
id={field.id}
value={field.value}
onChange={e =>
field.setValue(e.target.value === "" ? "" : +e.target.value)
}
onChange={field.handleChange}
onBlur={field.handleBlur}
autoComplete="off"
/>
Expand Down
6 changes: 2 additions & 4 deletions examples/basic-forms/4-basic-form-mui/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const NameField: React.FC = () => {
label="Name:"
id={field.id}
value={field.value}
onChange={e => field.setValue(e.target.value)}
onChange={field.handleChange}
onBlur={field.handleBlur}
error={field.error != null}
helperText={field.error}
Expand All @@ -83,9 +83,7 @@ const AgeField: React.FC = () => {
label="Age:"
id={field.id}
value={field.value}
onChange={e =>
field.setValue(e.target.value === "" ? "" : +e.target.value)
}
onChange={field.handleChange}
onBlur={field.handleBlur}
error={field.error != null}
helperText={field.error}
Expand Down
2 changes: 1 addition & 1 deletion examples/inputs/checkbox-group-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const ColorsCheckboxGroup: React.FC = () => {
name={colors.id}
checked={field.value}
onBlur={field.handleBlur}
onChange={e => field.setValue(e.target.checked)}
onChange={field.handleChange}
/>
<label htmlFor={field.id}>{labels[key]}</label>
</div>
Expand Down
2 changes: 1 addition & 1 deletion examples/inputs/field-array-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const PromoCodesArrayInput: React.FC = () => {
<input
key={field.id}
value={field.value}
onChange={e => field.setValue(e.target.value)}
onChange={field.handleChange}
onBlur={field.handleBlur}
autoComplete="off"
/>
Expand Down
5 changes: 3 additions & 2 deletions examples/inputs/mui-date-picker-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import ReactDOM from "react-dom";
import "../index.css";

const Schema = createFormSchema(fields => ({
date: fields.instanceOf(Date),
date: fields.date(),
}));

const Example: React.FC = () => {
Expand All @@ -44,7 +44,8 @@ const DatePickerInput: React.FC = () => {
variant="inline"
label="Choose your favourite date"
value={dateField.value}
onChange={date => dateField.setValue(date as Date)}
onChange={dateField.setValue}
onBlur={dateField.handleBlur}
fullWidth
autoOk
/>
Expand Down
5 changes: 1 addition & 4 deletions examples/inputs/mui-multi-select-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ const ColorsMultiSelectInput: React.FC = () => {
<Select
labelId={colors.id}
value={colors.value}
onChange={e => {
// TODO: simplify when field.handleChange is implemented
colors.setValue(e.target.value as Array<"red" | "green" | "blue">);
}}
onChange={colors.handleChange}
input={<Input />}
renderValue={selected => (selected as string[]).join(", ")}
multiple
Expand Down
5 changes: 3 additions & 2 deletions examples/inputs/radio-group-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ const ColorsRadioGroup: React.FC = () => {
<legend>Choose your favourite color:</legend>

{Object.values(colors.options).map(option => (
<div key={colors.id}>
<div key={option}>
<input
id={option}
type="radio"
name={colors.id}
value={option}
checked={colors.value === option}
onBlur={colors.handleBlur}
onChange={e => e.target.checked && colors.setValue(option)}
onChange={colors.handleChange}
/>
<label htmlFor={option}>{labels[option]}</label>
</div>
Expand Down
6 changes: 1 addition & 5 deletions examples/inputs/select-input/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,9 @@ const ColorSelectInput: React.FC = () => {
<select
id={field.id}
value={field.value}
onChange={e => field.setValue(e.target.value as Color)}
onChange={field.handleChange}
onBlur={field.handleBlur}
>
{/*
we need custom-typed Object.keys in order for type of `option`
to be inferred properly to "red" | "green" | "blue" in this example
*/}
{Object.values(field.options).map(option => (
<option key={option} value={option}>
{labels[option]}
Expand Down
40 changes: 18 additions & 22 deletions src/core/builders/create-form-schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe("createFormSchema", () => {
choice: fields.choice("A", "B", "C"),
num: fields.number(),
bool: fields.bool(),
instance: fields.instanceOf(Date),
date: fields.date(),
arrayString: fields.array(fields.string()),
arrayChoice: fields.array(fields.choice("a", "b", "c")),
arrayArrayString: fields.array(fields.array(fields.string())),
Expand All @@ -35,7 +35,7 @@ describe("createFormSchema", () => {
choice: "A" | "B" | "C";
num: number | "";
bool: boolean;
instance: Date | null;
date: Date | null;
arrayString: string[];
arrayChoice: Array<"a" | "b" | "c">;
arrayArrayString: string[][];
Expand All @@ -59,7 +59,7 @@ describe("createFormSchema", () => {
choice: fields.choice("A", "B", "C"),
num: fields.number(),
bool: fields.bool(),
instance: fields.instanceOf(Date),
date: fields.date(),
arrayString: fields.array(fields.string()),
arrayChoice: fields.array(fields.choice("a", "b", "c")),
arrayArrayString: fields.array(fields.array(fields.string())),
Expand All @@ -86,7 +86,7 @@ describe("createFormSchema", () => {
choice: "A" | "B" | "C";
num: number | "";
bool: boolean;
instance: Date | null;
date: Date | null;
arrayString: string[];
arrayChoice: Array<"a" | "b" | "c">;
arrayArrayString: string[][];
Expand Down Expand Up @@ -115,7 +115,7 @@ describe("createFormSchema", () => {
choice: fields.choice("A", "B", "C"),
num: fields.number(),
bool: fields.bool(),
instance: fields.instanceOf(Date),
date: fields.date(),
arrayString: fields.array(fields.string()),
arrayChoice: fields.array(fields.choice("a", "b", "c")),
arrayArrayString: fields.array(fields.array(fields.string())),
Expand All @@ -136,7 +136,7 @@ describe("createFormSchema", () => {
"choice",
"num",
"bool",
"instance",
"date",
"arrayString",
"arrayChoice",
"arrayArrayString",
Expand All @@ -153,7 +153,7 @@ describe("createFormSchema", () => {
choice: fields.choice("A", "B", "C"),
num: fields.number(),
bool: fields.bool(),
instance: fields.instanceOf(Date),
date: fields.date(),
arrayString: fields.array(fields.string()),
arrayChoice: fields.array(fields.choice("a", "b", "c")),
arrayArrayString: fields.array(fields.array(fields.string())),
Expand All @@ -174,7 +174,7 @@ describe("createFormSchema", () => {
choice: expect.objectContaining({ __path: "choice" }),
num: expect.objectContaining({ __path: "num" }),
bool: expect.objectContaining({ __path: "bool" }),
instance: expect.objectContaining({ __path: "instance" }),
date: expect.objectContaining({ __path: "date" }),
arrayString: expect.objectContaining({
__path: "arrayString",
nth: expect.any(Function),
Expand Down Expand Up @@ -227,7 +227,7 @@ describe("createFormSchema", () => {
expect(descriptor.__decoder.fieldType).toBe("string");
expect(descriptor.__decoder.init()).toBe("");
expect(descriptor.__decoder.decode("foo").ok).toBe(true);
expect(descriptor.__decoder.decode(42).ok).toBe(false);
expect(descriptor.__decoder.decode({}).ok).toBe(false);
});

it("creates field descriptor for choice field", () => {
Expand Down Expand Up @@ -263,7 +263,7 @@ describe("createFormSchema", () => {
expect(descriptor.__decoder.fieldType).toBe("number");
expect(descriptor.__decoder.init()).toBe("");
expect(descriptor.__decoder.decode(666).ok).toBe(true);
expect(descriptor.__decoder.decode("42").ok).toBe(false);
expect(descriptor.__decoder.decode("foo").ok).toBe(false);
});

it("creates field descriptor for bool field", () => {
Expand All @@ -277,25 +277,21 @@ describe("createFormSchema", () => {
expect(descriptor.__decoder.fieldType).toBe("bool");
expect(descriptor.__decoder.init()).toBe(false);
expect(descriptor.__decoder.decode(true).ok).toBe(true);
expect(descriptor.__decoder.decode("true").ok).toBe(false);
expect(descriptor.__decoder.decode("foo").ok).toBe(false);
});

it("creates field descriptor for instanceOf field", () => {
class MyClass {
constructor(public foo: string) {}
}

it("creates field descriptor for date field", () => {
const Schema = createFormSchema(fields => ({
theClass: fields.instanceOf(MyClass),
theDate: fields.date(),
}));

const descriptor = impl(Schema.theClass);
const descriptor = impl(Schema.theDate);

expect(descriptor.__path).toBe("theClass");
expect(descriptor.__decoder.fieldType).toBe("class");
expect(descriptor.__path).toBe("theDate");
expect(descriptor.__decoder.fieldType).toBe("date");
expect(descriptor.__decoder.init()).toBe(null);
expect(descriptor.__decoder.decode(new MyClass("42")).ok).toBe(true);
expect(descriptor.__decoder.decode({ foo: "42" }).ok).toBe(false);
expect(descriptor.__decoder.decode(new Date()).ok).toBe(true);
expect(descriptor.__decoder.decode(new Date("foo")).ok).toBe(false);
});

it("creates field descriptor for array field", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/builders/create-form-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const createFieldDescriptor = (
case "bool":
case "number":
case "string":
case "class":
case "date":
case "choice":
return rootDescriptor;

Expand Down
10 changes: 5 additions & 5 deletions src/core/builders/create-form-validator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe("createFormValidator", () => {
string: fields.string(),
number: fields.number(),
choice: fields.choice("A", "B", "C"),
instance: fields.instanceOf(Date),
date: fields.date(),
arrayString: fields.array(fields.string()),
arrayChoice: fields.array(fields.choice("a", "b", "c")),
arrayArrayString: fields.array(fields.array(fields.string())),
Expand Down Expand Up @@ -178,18 +178,18 @@ describe("createFormValidator", () => {
expect(validation).toEqual([{ field: Schema.choice, error: null }]);
});

it("should return ERR for failing single-rule on instance field ", async () => {
it("should return ERR for failing single-rule on date field ", async () => {
const { validate } = createFormValidator(Schema, validate => [
validate({
field: Schema.instance,
field: Schema.date,
rules: () => [x => (x === null ? "REQUIRED" : null)],
}),
]);
const getValue = () => null as any;

const validation = await validate({ fields: [Schema.instance], getValue });
const validation = await validate({ fields: [Schema.date], getValue });

expect(validation).toEqual([{ field: Schema.instance, error: "REQUIRED" }]);
expect(validation).toEqual([{ field: Schema.date, error: "REQUIRED" }]);
});

it("should return ERR for failing multiple-rule on string array field ", async () => {
Expand Down
6 changes: 3 additions & 3 deletions src/core/decoders/array.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe("array decoder", () => {
const decoder = impl(array(string()));
const value = [null, "foo", 42, "", []];

expect(decoder.decode(value)).toEqual({ ok: false, value });
expect(decoder.decode(value)).toEqual({ ok: false });
});
});

Expand All @@ -64,7 +64,7 @@ describe("array decoder", () => {
const decoder = impl(array(string()));
const value = [null, "foo", 42, "", []];

expect(decoder.decode(value)).toEqual({ ok: false, value });
expect(decoder.decode(value)).toEqual({ ok: false });
});
});

Expand All @@ -87,7 +87,7 @@ describe("array decoder", () => {
const decoder = impl(array(string()));
const value = [null, "foo", 42, "", []];

expect(decoder.decode(value)).toEqual({ ok: false, value });
expect(decoder.decode(value)).toEqual({ ok: false });
});
});
});
6 changes: 3 additions & 3 deletions src/core/decoders/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { impl, opaque } from "../types/type-mapper-util";

/**
* Define array field with elements of type defined by provided `innerDecoder`.
* Will check if value is array and if each element matches expected type at runtime.
* Default initial value will be `[]`
* Accepts empty arrays and arrays containing elements which are valid in respect to rules imposed by `innerDecoder`.
*
* @example
* ```
Expand All @@ -23,7 +23,7 @@ export const array = <E>(
init: () => [],

decode: value => {
if (Array.isArray(value)) {
if (value && Array.isArray(value)) {
const decodeResults = value.map(impl(innerDecoder).decode);
if (decodeResults.every(result => result.ok)) {
return {
Expand All @@ -32,7 +32,7 @@ export const array = <E>(
};
}
}
return { ok: false, value };
return { ok: false };
},
};

Expand Down
Loading