Skip to content

Commit

Permalink
feat: object schema types (#205)
Browse files Browse the repository at this point in the history
* fix: object schema types

* fix: schema definition

* chore: update docs

* chore: update stories

* chore: fix ci test script

* chore: add changeset
  • Loading branch information
Pagebakers authored Feb 21, 2024
1 parent 1314961 commit efca417
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 217 deletions.
6 changes: 6 additions & 0 deletions .changeset/spotty-cooks-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@saas-ui/forms': minor
'@saas-ui/react': minor
---

Improved ObjectSchema type definitions to be more strict and inherit correct field type props
39 changes: 8 additions & 31 deletions apps/website/src/pages/docs/components/forms/auto-form/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,8 @@ The default Form component supports the following schema format.
The object schema is an object with field props. Array and object fields can have nested fields.
```ts
type FieldTypes =
| 'array'
| 'object'
| 'text'
| 'textarea'
| 'select'
| 'number'
| 'checkbox'
| 'radio'
| 'pin'
| 'phone'
| 'url'
| 'email'
| 'password'
| 'switch'
| 'native-select'

type ObjectSchema = {
[key: FieldTypes]: FieldProps
}
```
```jsx
import { Form } from '@saas-ui/react'
import { Form, ObjectSchema } from '@saas-ui/react'

const schema = {
title: {
Expand All @@ -71,7 +48,7 @@ const schema = {
label: 'Body',
type: 'textarea',
},
}
} as const satisfies ObjectSchema

export default function Task() {
return (
Expand All @@ -90,7 +67,7 @@ export default function Task() {
### Customize submit button

```jsx
import { Form } from '@saas-ui/react'
import { Form, ObjectSchema } from '@saas-ui/react'

const schema = {
title: {
Expand All @@ -103,7 +80,7 @@ const schema = {
label: 'Body',
type: 'textarea',
},
}
} as const satisfies ObjectSchema

export default function Post() {
return (
Expand All @@ -129,7 +106,7 @@ export default function Post() {
### Object field

```jsx
import { Form } from '@saas-ui/react'
import { Form, ObjectSchema } from '@saas-ui/react'

const schema = {
title: {
Expand All @@ -154,7 +131,7 @@ const schema = {
},
},
},
}
} as const satisfies ObjectSchema

export default function Post() {
return (
Expand Down Expand Up @@ -184,7 +161,7 @@ export default function Post() {
### Array field

```jsx
import { Form } from '@saas-ui/react'
import { Form, ObjectSchema } from '@saas-ui/react'

const schema = {
title: {
Expand All @@ -209,7 +186,7 @@ const schema = {
},
},
},
}
} as const satisfies ObjectSchema

export default function Post() {
return (
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"clean": "turbo run clean",
"test": "vitest",
"test:watch": "vitest --watch --onlyChanged",
"test:ci": "vitest --color --runInBand --ci",
"test:ci": "vitest --color --run",
"lint": "turbo run lint",
"lint:staged": "lint-staged --allow-empty --config lint-staged.config.js",
"create:pkg": "hygen package chakra-component",
Expand Down
9 changes: 6 additions & 3 deletions packages/saas-ui-forms/src/auto-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ interface AutoFormOptions {

export interface AutoFormProps<
TFieldValues extends FieldValues,
TContext extends object = object
> extends Omit<FormProps<TFieldValues, TContext>, 'schema' | 'children'>,
TContext extends object = object,
> extends Omit<
FormProps<TFieldValues, TContext>,
'schema' | 'children' | 'fieldResolver'
>,
AutoFormOptions {
children?: React.ReactNode
}
Expand All @@ -40,7 +43,7 @@ export interface AutoFormProps<
export const AutoForm = forwardRef(
<
TFieldValues extends FieldValues = FieldValues,
TContext extends object = object
TContext extends object = object,
>(
props: AutoFormProps<TFieldValues, TContext>,
ref: React.ForwardedRef<HTMLFormElement>
Expand Down
3 changes: 3 additions & 0 deletions packages/saas-ui-forms/src/default-fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ import {
NativeSelectProps,
SelectButtonProps,
SelectListProps,
SelectOption,
} from './select'

import { createField } from './create-field'
import { FieldOption, FieldOptions } from './types'

export interface InputFieldProps extends InputProps {
type?: string
Expand Down Expand Up @@ -95,6 +97,7 @@ export interface SelectFieldProps extends SelectProps {
export const SelectField = createField<SelectFieldProps>(
forwardRef((props, ref) => {
const { buttonProps, listProps, ...rest } = props

return (
<Select ref={ref} {...rest}>
<SelectButton {...buttonProps} />
Expand Down
33 changes: 26 additions & 7 deletions packages/saas-ui-forms/src/field-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { BaseFieldProps } from './types'
import { BaseFieldProps, ValueOf } from './types'

import { get } from '@chakra-ui/utils'
import { ArrayFieldProps } from './array-field'
import { ObjectFieldProps } from './object-field'
import { DefaultFields } from './default-fields'

export type FieldResolver = {
getFields(): BaseFieldProps[]
Expand All @@ -9,16 +12,32 @@ export type FieldResolver = {

export type GetFieldResolver<TSchema = any> = (schema: TSchema) => FieldResolver

interface SchemaField extends BaseFieldProps {
items?: SchemaField[]
properties?: Record<string, SchemaField>
}
type FieldTypes<FieldDefs = DefaultFields> = ValueOf<{
[K in keyof FieldDefs]: FieldDefs[K] extends React.FC<infer Props>
? { type?: K } & Omit<Props, 'name'>
: never
}>

type SchemaField<FieldDefs = DefaultFields> =
| FieldTypes<FieldDefs>
| (Omit<ObjectFieldProps, 'name' | 'children'> & {
type: 'object'
properties?: Record<string, SchemaField<FieldDefs>>
})
| (Omit<ArrayFieldProps, 'name' | 'children'> & {
type: 'array'
items?: SchemaField<FieldDefs>
})

export type ObjectSchema = Record<string, SchemaField>
export type ObjectSchema<FieldDefs = DefaultFields> = Record<
string,
SchemaField<FieldDefs>
>

const mapFields = (schema: ObjectSchema): BaseFieldProps[] =>
schema &&
Object.entries(schema).map(([name, { items, label, title, ...field }]) => {
Object.entries(schema).map(([name, props]) => {
const { items, label, title, ...field } = props as any
return {
...field,
name,
Expand Down
Loading

0 comments on commit efca417

Please sign in to comment.