-
-
Notifications
You must be signed in to change notification settings - Fork 357
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
[WIP] Shared Component Library Docs #825
base: main
Are you sure you want to change the base?
Conversation
☁️ Nx Cloud ReportWe didn't find any information for the current pull request with the commit 2adadbf. Check the Nx Cloud Source Control Integration documentation for more information. Alternatively, you can contact us at [email protected]. Sent with 💌 from NxCloud. |
One thing I am running into with this branch, |
How are you defining your component? function TextInputField<
TFormData extends unknown,
TName extends DeepKeyValueName<TFormData, string>,
> Here you can change string to your data type |
Ended up doing this, which is stupid, but works. type ExpirationSelectFieldProps<
Key extends string,
TFormData extends { [K in Key]: ExpirationItem | null },
TName extends DeepKeyValueName<TFormData, ExpirationItem>,
> = Omit<FieldOptions<TFormData, TName>, 'name'> & {
name: Key
form: ReactFormApi<TFormData, any> & {
state: FormState<TFormData>
}
selectProps?: Omit<ComponentProps<typeof Select>, 'onChange' | 'value'> & {
label?: string
placeholder?: string
inputWrapperClassName?: string
}
symbol: string
}
export function ExpirationSelectField<
Key extends string,
TFormData extends { [K in Key]: ExpirationItem | null },
TName extends DeepKeyValueName<TFormData, ExpirationItem>,
>(props: ExpirationSelectFieldProps<Key, TFormData, TName>) { ... } |
I was also working on integrating it more smoothly, i.e. abstracting the boiler plate and allowing to make custom components of it. This is my first POC, works for my side project now. Any feedback / suggestions / improvements are always welcome. Usage: // app/SomeForm.tsx
import { FieldInput, Form } from "../lib/form/Form"
export const SomeForm = () => {
const form = useForm({
defaultValues: {
name: '',
id: '',
}
})
return (
<Form onSubmit={form.handleSubmit}>
<div className="flex flex-col space-y-2">
<FieldInput formT={form} name="name" placeholder="Name" />
<FieldInput formT={form} name="id" placeholder="ID" />
<button type="submit">Add</button>
</div>
</Form>
)
} Abstract form components created to reduce boiler plate and allow for custom custom form components with @tanstack/form: // lib/form/Form.tsx
import { DeepKeys, FieldApi, useForm } from '@tanstack/react-form'
export const Form: React.FC<React.FormHTMLAttributes<HTMLFormElement>> = ({
children,
...props
}) => {
return (
<form
{...props}
onSubmit={(e) => {
e.preventDefault()
e.stopPropagation()
if (props.onSubmit) {
props.onSubmit(e)
}
}}
>
{children}
</form>
)
}
export const FieldInfo = ({ field }: { field: FieldApi<any, any, any, any> }) => {
return (
<>
{field.state.meta.isTouched && field.state.meta.errors.length ? (
<em className=" text-red-500 text-xs">{field.state.meta.errors.join(',')}</em>
) : null}
{field.state.meta.isValidating ? 'Validating...' : null}
</>
)
}
export const FieldInput = <TFormData, TNames extends DeepKeys<TFormData>>({
formT,
name,
...props
}: {
formT: ReturnType<typeof useForm<TFormData, any>>
name: TNames
} & React.InputHTMLAttributes<HTMLInputElement>) => (
<formT.Field<TNames, any, any> name={name}>
{(field) => (
<>
<input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
className="w-full rounded-md border border-gray-300 px-4 py-2 transition duration-200 ease-in-out focus:border-transparent focus:outline-none focus:ring-2 focus:ring-blue-500"
{...props}
/>
<FieldInfo field={field} />
</>
)}
</formT.Field>
) This works so far, but I might want to look into your solution @crutchcorn, with DeepKeyValueName, what's still going wrong (as it seems it's not merged)? |
} | ||
|
||
function TextInputField< | ||
TFormData extends unknown, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anyone know why extends unknown
constrains field.name
to string
instead of string | number
?
@typescript-eslint/no-unnecessary-type-constraint
and other sources I've found claim that an unconstrained generic type parameter already defaults to unknown
, but this must not be true. Maybe some TS wizard will say "oh that's the extends unknown trick it fixes ..." 😅
Before I found this issue I had some of the implementation done myself but couldn't work out why DeepKeys
doesn't exclude number
, among other TS issues.
It's also a shame that form.Field<TName, any, string>
doesn't work, because the types of field.state.value
and field.handleChange
are exactly where it would be useful to have TypeScript help.
There's an issue with interface Fields {
nested: {
name: string
labels: string[]
} | null
}
const form = useForm<Fields>({
defaultValues: {
nested: { name: '', labels: [] },
},
})
return <TextInputField form={form} name="nested.name" />
|
@RazerM can you open a different GH issue for the failing type error you're running into there? |
@crutchcorn it's unique to |
This PR: