Skip to content

Commit

Permalink
Added textarea form field
Browse files Browse the repository at this point in the history
  • Loading branch information
Dejiah committed Dec 30, 2023
1 parent 106d6c5 commit b48314a
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 6 deletions.
3 changes: 2 additions & 1 deletion demo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fastui import AnyComponent, FastUI
from fastui import components as c
from fastui.events import GoToEvent, PageEvent
from fastui.forms import FormFile, SelectSearchResponse, fastui_form
from fastui.forms import FormFile, SelectSearchResponse, Textarea, fastui_form
from httpx import AsyncClient
from pydantic import BaseModel, EmailStr, Field, SecretStr, field_validator
from pydantic_core import PydanticCustomError
Expand Down Expand Up @@ -143,6 +143,7 @@ class BigModel(BaseModel):
name: str | None = Field(
None, description='This field is not required, it must start with a capital letter if provided'
)
info: Annotated[str | None, Textarea(rows=5)] = Field(None, description='Optional free text information about you.')
profile_pic: Annotated[UploadFile, FormFile(accept='image/*', max_size=16_000)] = Field(
description='Upload a profile picture, must not be more than 16kb'
)
Expand Down
2 changes: 2 additions & 0 deletions src/npm-fastui-bootstrap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ export const classNameGenerator: ClassNameGenerator = ({
}
}
case 'FormFieldInput':
case 'FormFieldTextarea':
case 'FormFieldBoolean':
case 'FormFieldSelect':
case 'FormFieldSelectSearch':
case 'FormFieldFile':
switch (subElement) {
case 'textarea':
case 'input':
return {
'form-control': type !== 'FormFieldBoolean',
Expand Down
28 changes: 28 additions & 0 deletions src/npm-fastui/src/components/FormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Select, { StylesConfig } from 'react-select'

import type {
FormFieldInput,
FormFieldTextarea,
FormFieldBoolean,
FormFieldFile,
FormFieldSelect,
Expand Down Expand Up @@ -44,6 +45,32 @@ export const FormFieldInputComp: FC<FormFieldInputProps> = (props) => {
)
}

interface FormFieldTextareaProps extends FormFieldTextarea {
onChange?: PrivateOnChange
}

export const FormFieldTextareaComp: FC<FormFieldTextareaProps> = (props) => {
const { name, placeholder, required, locked, rows, cols } = props
return (
<div className={useClassName(props)}>
<Label {...props} />
<textarea
className={useClassName(props, { el: 'textarea' })}
defaultValue={props.initial}
id={inputId(props)}
rows={rows}
cols={cols}
name={name}
required={required}
disabled={locked}
placeholder={placeholder}
aria-describedby={descId(props)}
/>
<ErrorDescription {...props} />
</div>
)
}

interface FormFieldBooleanProps extends FormFieldBoolean {
onChange?: PrivateOnChange
}
Expand Down Expand Up @@ -284,6 +311,7 @@ const Label: FC<FormFieldProps> = (props) => {

export type FormFieldProps =
| FormFieldInputProps
| FormFieldTextareaProps
| FormFieldBooleanProps
| FormFieldFileProps
| FormFieldSelectProps
Expand Down
3 changes: 3 additions & 0 deletions src/npm-fastui/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CodeComp } from './Code'
import { FormComp } from './form'
import {
FormFieldInputComp,
FormFieldTextareaComp,
FormFieldBooleanComp,
FormFieldSelectComp,
FormFieldSelectSearchComp,
Expand Down Expand Up @@ -121,6 +122,8 @@ export const AnyComp: FC<FastProps> = (props) => {
return <FormComp {...props} />
case 'FormFieldInput':
return <FormFieldInputComp {...props} />
case 'FormFieldTextarea':
return <FormFieldTextareaComp {...props} />
case 'FormFieldBoolean':
return <FormFieldBooleanComp {...props} />
case 'FormFieldFile':
Expand Down
34 changes: 32 additions & 2 deletions src/npm-fastui/src/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type FastProps =
| Details
| Form
| FormFieldInput
| FormFieldTextarea
| FormFieldBoolean
| FormFieldFile
| FormFieldSelect
Expand Down Expand Up @@ -297,7 +298,14 @@ export interface Form {
submitTrigger?: PageEvent
footer?: FastProps[]
className?: ClassName
formFields: (FormFieldInput | FormFieldBoolean | FormFieldFile | FormFieldSelect | FormFieldSelectSearch)[]
formFields: (
| FormFieldInput
| FormFieldTextarea
| FormFieldBoolean
| FormFieldFile
| FormFieldSelect
| FormFieldSelectSearch
)[]
type: 'Form'
}
export interface FormFieldInput {
Expand All @@ -314,6 +322,21 @@ export interface FormFieldInput {
placeholder?: string
type: 'FormFieldInput'
}
export interface FormFieldTextarea {
name: string
title: string[] | string
required?: boolean
error?: string
locked?: boolean
description?: string
displayMode?: 'default' | 'inline'
className?: ClassName
rows?: number
cols?: number
initial?: string
placeholder?: string
type: 'FormFieldTextarea'
}
export interface FormFieldBoolean {
name: string
title: string[] | string
Expand Down Expand Up @@ -392,5 +415,12 @@ export interface ModelForm {
footer?: FastProps[]
className?: ClassName
type: 'ModelForm'
formFields: (FormFieldInput | FormFieldBoolean | FormFieldFile | FormFieldSelect | FormFieldSelectSearch)[]
formFields: (
| FormFieldInput
| FormFieldTextarea
| FormFieldBoolean
| FormFieldFile
| FormFieldSelect
| FormFieldSelectSearch
)[]
}
12 changes: 11 additions & 1 deletion src/python-fastui/fastui/components/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ class FormFieldInput(BaseFormField):
type: _t.Literal['FormFieldInput'] = 'FormFieldInput'


class FormFieldTextarea(BaseFormField):
rows: _t.Union[int, None] = None
cols: _t.Union[int, None] = None
initial: _t.Union[str, None] = None
placeholder: _t.Union[str, None] = None
type: _t.Literal['FormFieldTextarea'] = 'FormFieldTextarea'


class FormFieldBoolean(BaseFormField):
initial: _t.Union[bool, None] = None
mode: _t.Literal['checkbox', 'switch'] = 'checkbox'
Expand Down Expand Up @@ -65,7 +73,9 @@ class FormFieldSelectSearch(BaseFormField):
type: _t.Literal['FormFieldSelectSearch'] = 'FormFieldSelectSearch'


FormField = _t.Union[FormFieldInput, FormFieldBoolean, FormFieldFile, FormFieldSelect, FormFieldSelectSearch]
FormField = _t.Union[
FormFieldInput, FormFieldTextarea, FormFieldBoolean, FormFieldFile, FormFieldSelect, FormFieldSelectSearch
]


class BaseForm(pydantic.BaseModel, ABC, defer_build=True, extra='forbid'):
Expand Down
7 changes: 6 additions & 1 deletion src/python-fastui/fastui/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
if _t.TYPE_CHECKING:
from . import json_schema

__all__ = 'FastUIForm', 'fastui_form', 'FormFile', 'SelectSearchResponse', 'SelectOption'
__all__ = 'FastUIForm', 'fastui_form', 'FormFile', 'Textarea', 'SelectSearchResponse', 'SelectOption'

FormModel = _t.TypeVar('FormModel', bound=pydantic.BaseModel)

Expand Down Expand Up @@ -226,3 +226,8 @@ def name_to_loc(name: str) -> 'json_schema.SchemeLocation':
else:
loc.append(part)
return loc


# Use uppercase for consistency with pydantic.Field, which is also a function
def Textarea(rows: _t.Union[int, None] = None, cols: _t.Union[int, None] = None) -> _t.Any: # N802
return pydantic.Field(json_schema_extra={'format': 'textarea', 'rows': rows, 'cols': cols})

Check warning on line 233 in src/python-fastui/fastui/forms.py

View check run for this annotation

Codecov / codecov/patch

src/python-fastui/fastui/forms.py#L233

Added line #L233 was not covered by tests
23 changes: 22 additions & 1 deletion src/python-fastui/fastui/json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
FormFieldInput,
FormFieldSelect,
FormFieldSelectSearch,
FormFieldTextarea,
InputHtmlType,
)

Expand All @@ -30,7 +31,7 @@ def model_json_schema_to_fields(model: _t.Type[BaseModel]) -> _t.List[FormField]


JsonSchemaInput: _ta.TypeAlias = (
'JsonSchemaString | JsonSchemaStringEnum | JsonSchemaFile | JsonSchemaInt | JsonSchemaNumber'
'JsonSchemaString | JsonSchemaStringEnum | JsonSchemaFile | JsonSchemaTextarea | JsonSchemaInt | JsonSchemaNumber'
)
JsonSchemaField: _ta.TypeAlias = 'JsonSchemaInput | JsonSchemaBool'
JsonSchemaConcrete: _ta.TypeAlias = 'JsonSchemaField | JsonSchemaArray | JsonSchemaObject'
Expand Down Expand Up @@ -69,6 +70,15 @@ class JsonSchemaFile(JsonSchemaBase, total=False):
accept: str


class JsonSchemaTextarea(JsonSchemaBase, total=False):
type: _ta.Required[_t.Literal['string']]
format: _ta.Required[_t.Literal['textarea']]
rows: int
cols: int
default: str
placeholder: str


class JsonSchemaBool(JsonSchemaBase, total=False):
type: _ta.Required[_t.Literal['boolean']]
default: bool
Expand Down Expand Up @@ -236,6 +246,17 @@ def special_string_field(
accept=schema.get('accept'),
description=schema.get('description'),
)
elif schema.get('format') == 'textarea':
return FormFieldTextarea(

Check warning on line 250 in src/python-fastui/fastui/json_schema.py

View check run for this annotation

Codecov / codecov/patch

src/python-fastui/fastui/json_schema.py#L250

Added line #L250 was not covered by tests
name=name,
title=title,
required=required,
rows=schema.get('rows'),
cols=schema.get('cols'),
placeholder=schema.get('placeholder'),
initial=schema.get('initial'),
description=schema.get('description'),
)
elif enum := schema.get('enum'):
enum_labels = schema.get('enum_labels', {})
return FormFieldSelect(
Expand Down

0 comments on commit b48314a

Please sign in to comment.