import { useState, useMemo } from 'react'
import Content from '../../Content'
import Br from '../../Br'
import Span from '../../typography/Span'
import ObjectInput from '../ObjectInput'
import { useValue, useValue$ } from 'startupjs'
import { Sandbox } from '@startupjs/docs'

# ObjectInput

ObjectInput lets build dynamic forms using its declarative api.

ObjectInput accepts an inputs metadata object with a required `input` key to specify what type of input to display in the `properties` property.

Possible types are: [array](/docs/forms/Array), [сheckbox](/docs/forms/Checkbox), [date](/docs/forms/DateTimePicker), [datetime](/docs/forms/DateTimePicker), [multiselect](/docs/forms/Multiselect), [number](/docs/forms/NumberInput), [object](/docs/forms/ObjectInput), [password](/docs/forms/PasswordInput), [radio](/docs/forms/Radio), [select](/docs/forms/Select), [time](/docs/forms/DateTimePicker), [text](/docs/forms/TextInput).

```jsx
import { ObjectInput } from from '@startupjs/ui'
```

## Simple example

It's important to have `properties` object defined as a constant either outside of your component or cached with `useMemo()`, otherwise component is going to re-render the whole form tree whenever you are editing one of the field.

```jsx example
const $value = useValue$()

return (
  <ObjectInput
    $value={$value}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
  />
)
```

## Row

You can show nested inputs in a row by passing the `row` flag.

```jsx example
const $value = useValue$()

return (
  <ObjectInput
    $value={$value}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
    row
  />
)
```

## Inputs order

ObjectInput accepts an array in the `order` property to specify in what order should the inputs be displayed.

```jsx example
const $value = useValue$()

return (
  <ObjectInput
    $value={$value}
    order={['password', 'email']}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
  />
)
```

## Displaying errors

The `errors` property accepts an object with error texts for inputs, where the key is the input key from the `properties` object and its value is the error text.

```jsx example
const [, $value] = useValue({})

return (
  <ObjectInput
    $value={$value}
    errors={{
      email: 'Email input error',
      password: 'Password input error'
    }}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
  />
)
```

## Disabled

```jsx example
const $value = useValue$()

return (
  <ObjectInput
    $value={$value}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
    disabled
  />
)
```

## Readonly

```jsx example
const $value = useValue$({ email: 'startupjs@gmail.com', password: '123456' })

return (
  <ObjectInput
    $value={$value}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
    readonly
  />
)
```

## Advanced usage

ObjectInput supports `dependsOn` and `dependsValue` properties for each input object in `properties` to dynamically display inputs.

- `dependsOn` is used to specify the object key which the current input depends on
- `dependsValue` is used to specify at what value of the input with key `dependsOn` should the current input be shown

In the example below the dependent `password` input will only be shown if the `email` input is not empty.

**Caution**: When the `dependsOn` field changes and dependent field is no longer visible its previous value is preserved.

```jsx example
const [, $value] = useValue()

return (
  <ObjectInput
    $value={$value}
    properties={{
      email: {
        input: 'text',
        label: 'Email'
      },
      password: {
        input: 'text',
        label: 'Password',
        dependsOn: 'email',
        description: "Make sure it's at least 15 characters OR at least 8 characters including a number and a lowercase letter"
      }
    }}
  />
)
```
