Skip to content

Commit

Permalink
Improve change event handling and add filter prop
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Nov 27, 2024
1 parent 0e0a725 commit bb2330c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-scissors-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"signal-form": patch
---

Improve change event handling and add filter property
14 changes: 9 additions & 5 deletions lib/controls/check-box-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export type CheckBoxInputProps = Omit<
"type"
> & {
name: string;
onAfterChange?: ChangeEventHandler<HTMLInputElement>;
};

export const CheckBoxInput = forwardRef<HTMLInputElement, CheckBoxInputProps>(
({ name, onChange, ...props }, forwardedRef) => {
({ name, onChange, onAfterChange, ...props }, forwardedRef) => {
let field = useField(name);
let value = useFieldData<boolean>(name, false);
let ref = useForwardedRef(forwardedRef);
Expand All @@ -26,10 +27,13 @@ export const CheckBoxInput = forwardRef<HTMLInputElement, CheckBoxInputProps>(
let onChangeHandler: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(e.target.checked);
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(e.target.checked);
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand Down
18 changes: 13 additions & 5 deletions lib/controls/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ export type InputProps = Omit<
> & {
name: string;
value?: string | ReadonlySignal<string>;
onAfterChange?: ChangeEventHandler<HTMLInputElement>;
filter?: (value: string) => string;
};

export const Input = forwardRef<HTMLInputElement, InputProps>(
({ name, value, onChange, ...props }, forwardedRef) => {
(
{ name, value, onChange, onAfterChange, filter, ...props },
forwardedRef
) => {
let field = useField<string>(name);
let ref = useForwardedRef(forwardedRef);

Expand All @@ -37,10 +42,13 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
let onChangeHandler: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(e.target.value);
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(filter ? filter(e.target.value) : e.target.value);
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand Down
14 changes: 9 additions & 5 deletions lib/controls/radio-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ export type RadioInputProps = Omit<
> & {
name: string;
value: string;
onAfterChange?: ChangeEventHandler<HTMLInputElement>;
};

export const RadioInput = forwardRef<HTMLInputElement, RadioInputProps>(
({ name, value, onChange, ...props }, forwardedRef) => {
({ name, value, onChange, onAfterChange, ...props }, forwardedRef) => {
let field = useField<string>(name);
let isChecked = useComputedValue(() => {
return field.data.value?.toString() === value.toString();
Expand All @@ -30,10 +31,13 @@ export const RadioInput = forwardRef<HTMLInputElement, RadioInputProps>(
let onChangeHandler: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(value);
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(value);
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand Down
27 changes: 17 additions & 10 deletions lib/controls/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useForwardedRef } from "~/utils/use-forwarded-ref";

export type SelectProps = SelectHTMLAttributes<HTMLSelectElement> & {
name: string;
onAfterChange?: ChangeEventHandler<HTMLSelectElement>;
};

export const Select = forwardRef<HTMLSelectElement, SelectProps>(
Expand All @@ -19,7 +20,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
);

export const SingleSelect = forwardRef<HTMLSelectElement, SelectProps>(
({ name, multiple, onChange, ...props }, forwardedRef) => {
({ name, multiple, onChange, onAfterChange, ...props }, forwardedRef) => {
let field = useField(name);
let value = useFieldData<string>(name, "");
let ref = useForwardedRef(forwardedRef);
Expand All @@ -33,10 +34,13 @@ export const SingleSelect = forwardRef<HTMLSelectElement, SelectProps>(
let onChangeHandler: ChangeEventHandler<HTMLSelectElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(e.target.value);
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(e.target.value);
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand All @@ -55,7 +59,7 @@ export const SingleSelect = forwardRef<HTMLSelectElement, SelectProps>(
);

export const MultipleSelect = forwardRef<HTMLSelectElement, SelectProps>(
({ name, multiple, onChange, ...props }, forwardedRef) => {
({ name, multiple, onChange, onAfterChange, ...props }, forwardedRef) => {
let field = useField(name);
let value = useFieldData<string[]>(name, []);
let ref = useForwardedRef<HTMLSelectElement>(forwardedRef);
Expand All @@ -69,10 +73,13 @@ export const MultipleSelect = forwardRef<HTMLSelectElement, SelectProps>(
let onChangeHandler: ChangeEventHandler<HTMLSelectElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(Array.from(e.target.selectedOptions, (o) => o.value));
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(Array.from(e.target.selectedOptions, (o) => o.value));
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand Down
14 changes: 9 additions & 5 deletions lib/controls/text-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export type TextAreaProps = Omit<
> & {
name: string;
value?: string | ReadonlySignal<string>;
onAfterChange?: ChangeEventHandler<HTMLTextAreaElement>;
};

export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
({ name, value, onChange, ...props }, forwardedRef) => {
({ name, value, onChange, onAfterChange, ...props }, forwardedRef) => {
let field = useField<string>(name);
let ref = useForwardedRef(forwardedRef);

Expand All @@ -37,10 +38,13 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
let onChangeHandler: ChangeEventHandler<HTMLTextAreaElement> = useCallback(
(e) => {
onChange?.(e);
batch(() => {
field.setData(e.target.value);
field.setTouched();
});
if (!e.isDefaultPrevented()) {
batch(() => {
field.setData(e.target.value);
field.setTouched();
});
}
onAfterChange?.(e);
},
[]
);
Expand Down
15 changes: 15 additions & 0 deletions stories/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,18 @@ export const Reactive: Story = {
);
},
};

export const Filtered: Story = {
render() {
return (
<Form>
<p>
<label>
Code:{" "}
<Input name="name" filter={(v) => v.toUpperCase().slice(0, 6)} />
</label>
</p>
</Form>
);
},
};

0 comments on commit bb2330c

Please sign in to comment.