-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from linked-planet/feature/form-wrapper
adding initial form-wrapper to ui-kit-ts
- Loading branch information
Showing
17 changed files
with
1,399 additions
and
417 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
/build | ||
|
||
# misc | ||
.idea | ||
.DS_Store | ||
.env.local | ||
.env.development.local | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { | ||
type Path, | ||
useForm, | ||
type Control, | ||
type DefaultValues, | ||
type FieldValues, | ||
type RegisterOptions, | ||
type UseFormRegisterReturn, | ||
type UseFormWatch, | ||
} from "react-hook-form" | ||
import { twMerge } from "tailwind-merge" | ||
import { Button } from "../Button" | ||
|
||
export interface FormProps<T extends FieldValues> { | ||
control: Control<T> | ||
watch: UseFormWatch<T> | ||
register: ( | ||
name: Path<T>, | ||
options?: RegisterOptions<T>, | ||
) => UseFormRegisterReturn | ||
readonly?: boolean | ||
} | ||
|
||
export interface FormField<T extends FieldValues> { | ||
name: Path<T> | ||
title: string | ||
description?: string | ||
required?: boolean | ||
formProps: FormProps<T> | ||
} | ||
|
||
export interface DynamicFormProps<T extends FieldValues> | ||
extends Omit< | ||
React.FormHTMLAttributes<HTMLFormElement>, | ||
"children" | "onSubmit" | ||
> { | ||
obj: DefaultValues<T> | ||
children: ( | ||
formProps: FormProps<T>, | ||
reset: (newDefaultValue?: T) => void, | ||
) => React.JSX.Element | ||
onSubmit: (obj: T) => void | ||
readonly?: boolean | ||
vertical?: boolean | ||
hideReset?: boolean | ||
hideSave?: boolean | ||
} | ||
|
||
export function DynamicForm<T extends FieldValues>({ | ||
obj, | ||
children, | ||
onSubmit, | ||
readonly, | ||
vertical, | ||
className, | ||
hideSave, | ||
hideReset, | ||
...props | ||
}: DynamicFormProps<T>) { | ||
const { | ||
register, | ||
handleSubmit, | ||
formState: { isDirty, isValid }, | ||
control, | ||
reset, | ||
watch, | ||
} = useForm<T>({ | ||
defaultValues: obj, | ||
}) | ||
|
||
const onReset = (e: React.FormEvent) => { | ||
e.preventDefault() | ||
reset() | ||
} | ||
|
||
return ( | ||
<form | ||
{...props} | ||
className={twMerge( | ||
`flex ${vertical ? "flex-row" : "flex-col"} gap-4`, | ||
className, | ||
)} | ||
onSubmit={handleSubmit(onSubmit)} | ||
onReset={onReset} | ||
> | ||
{children( | ||
{ | ||
control: control, | ||
watch: watch, | ||
register: register, | ||
readonly: readonly, | ||
}, | ||
reset, | ||
)} | ||
|
||
<hr className="border border-border" /> | ||
|
||
<div className="flex flex-row items-end w-full justify-end mt-4"> | ||
{!hideReset && ( | ||
<Button | ||
type="reset" | ||
appearance="subtle" | ||
disabled={!isDirty} | ||
> | ||
Reset | ||
</Button> | ||
)} | ||
{!hideSave && ( | ||
<Button | ||
appearance="primary" | ||
type="submit" | ||
disabled={!isValid} | ||
> | ||
Save | ||
</Button> | ||
)} | ||
</div> | ||
</form> | ||
) | ||
} |
50 changes: 50 additions & 0 deletions
50
library/src/components/form/elements/CheckboxFormField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { useEffect, useRef } from "react" | ||
import type { FieldValues } from "react-hook-form" | ||
import type { FormField } from "../DynamicForm" | ||
import { Label } from "../../inputs" | ||
import { Checkbox } from "../../Checkbox" | ||
|
||
export interface CheckboxFormField<T extends FieldValues> extends FormField<T> { | ||
onChange?: (value: string) => void | ||
} | ||
|
||
export function CheckboxFormField<T extends FieldValues>({ | ||
name, | ||
onChange, | ||
formProps, | ||
required, | ||
description, | ||
title, | ||
}: CheckboxFormField<T>) { | ||
const fieldValue = formProps.watch(name) | ||
const onChangeCB = useRef(onChange) | ||
if (onChangeCB.current !== onChange) { | ||
onChangeCB.current = onChange | ||
} | ||
|
||
useEffect(() => { | ||
onChangeCB.current?.(fieldValue) | ||
}, [fieldValue]) | ||
|
||
const inputProps = formProps.register(name) | ||
|
||
return ( | ||
<div className="flex flex-1 flex-col"> | ||
<Label htmlFor={name} required={required}> | ||
{title} | ||
</Label> | ||
{description && ( | ||
<p className="mt-0 pb-2"> | ||
<small>{description}</small> | ||
</p> | ||
)} | ||
<Checkbox | ||
className="mt-2" | ||
label={"Aktivieren"} | ||
disabled={formProps.readonly} | ||
id={inputProps?.name} | ||
{...inputProps} | ||
/> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { useEffect, useRef } from "react" | ||
import type { FieldValues } from "react-hook-form" | ||
import type { FormField } from "../DynamicForm" | ||
import { Input, Label } from "../../inputs" | ||
|
||
export interface InputFormField<T extends FieldValues> extends FormField<T> { | ||
onChange?: (value: string) => void | ||
placeholder?: string | ||
} | ||
|
||
export function InputFormField<T extends FieldValues>({ | ||
onChange, | ||
formProps, | ||
name, | ||
required, | ||
description, | ||
title, | ||
placeholder, | ||
}: InputFormField<T>) { | ||
const fieldValue = formProps.watch(name) | ||
const onChangeCB = useRef(onChange) | ||
if (onChangeCB.current !== onChange) { | ||
onChangeCB.current = onChange | ||
} | ||
|
||
useEffect(() => { | ||
onChangeCB.current?.(fieldValue) | ||
}, [fieldValue]) | ||
|
||
const inputProps = formProps.register(name) | ||
|
||
return ( | ||
<div className="flex flex-1 flex-col min-w-max"> | ||
<Label htmlFor={name} required={required}> | ||
{title} | ||
</Label> | ||
{description && ( | ||
<p className="mt-0 pb-2"> | ||
<small>{description}</small> | ||
</p> | ||
)} | ||
<Input | ||
id={name} | ||
{...inputProps} | ||
disabled={formProps?.readonly} | ||
placeholder={placeholder} | ||
/> | ||
</div> | ||
) | ||
} |
62 changes: 62 additions & 0 deletions
62
library/src/components/form/elements/SelectMultiFormField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { useEffect, useRef } from "react" | ||
import type { FieldValues } from "react-hook-form" | ||
import type { FormField } from "../DynamicForm" | ||
import { Label, Select } from "../../inputs" | ||
|
||
export interface SelectMultiFormField< | ||
T extends FieldValues, | ||
A extends string | number, | ||
> extends FormField<T> { | ||
options: Array<{ label: string; value: A }> | ||
onChange?: (values: Array<string>) => void | ||
placeholder?: string | ||
} | ||
|
||
export function SelectMultiFormField< | ||
T extends FieldValues, | ||
A extends string | number, | ||
>({ | ||
name, | ||
onChange, | ||
formProps, | ||
required, | ||
description, | ||
title, | ||
options, | ||
placeholder, | ||
}: SelectMultiFormField<T, A>) { | ||
const fieldValue = formProps.watch(name) | ||
const onChangeCB = useRef(onChange) | ||
if (onChangeCB.current !== onChange) { | ||
onChangeCB.current = onChange | ||
} | ||
|
||
useEffect(() => { | ||
onChangeCB.current?.(fieldValue) | ||
}, [fieldValue]) | ||
|
||
const inputProps = formProps.register(name) | ||
|
||
return ( | ||
<div className="flex flex-1 flex-col min-w-max"> | ||
<Label htmlFor={inputProps?.name} required={required}> | ||
{title} | ||
</Label> | ||
{description && ( | ||
<p className="mt-0 pb-2"> | ||
<small>{description}</small> | ||
</p> | ||
)} | ||
<Select<T, A, true> | ||
isMulti | ||
id={name} | ||
name={name} | ||
control={formProps.control} | ||
options={options} | ||
required={required} | ||
disabled={formProps.readonly} | ||
placeholder={placeholder} | ||
/> | ||
</div> | ||
) | ||
} |
61 changes: 61 additions & 0 deletions
61
library/src/components/form/elements/SelectSingleFormField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { useEffect, useRef } from "react" | ||
import type { FieldValues, Path } from "react-hook-form" | ||
import type { FormField } from "../DynamicForm" | ||
import { Label, Select } from "../../inputs" | ||
|
||
export interface SelectSingleFormField< | ||
T extends FieldValues, | ||
A extends string | number, | ||
> extends FormField<T> { | ||
options: Array<{ label: string; value: A }> | ||
onChange?: (value: string) => void | ||
placeholder?: string | ||
} | ||
|
||
export function SelectSingleFormField< | ||
T extends FieldValues, | ||
A extends string | number, | ||
>({ | ||
name, | ||
description, | ||
title, | ||
formProps, | ||
onChange, | ||
required, | ||
options, | ||
placeholder, | ||
}: SelectSingleFormField<T, A>) { | ||
const fieldValue = formProps.watch(name) | ||
const onChangeCB = useRef(onChange) | ||
if (onChangeCB.current !== onChange) { | ||
onChangeCB.current = onChange | ||
} | ||
|
||
useEffect(() => { | ||
onChangeCB.current?.(fieldValue) | ||
}, [fieldValue]) | ||
|
||
const inputProps = formProps.register(name) | ||
|
||
return ( | ||
<div className="flex flex-1 flex-col min-w-max"> | ||
<Label htmlFor={inputProps?.name} required={required}> | ||
{title} | ||
</Label> | ||
{description && ( | ||
<p className="mt-0 pb-2"> | ||
<small>{description}</small> | ||
</p> | ||
)} | ||
<Select<T, A, false> | ||
id={inputProps?.name} | ||
name={inputProps?.name as Path<T>} | ||
control={formProps.control} | ||
options={options} | ||
required={required} | ||
disabled={formProps.readonly} | ||
placeholder={placeholder} | ||
/> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.