Skip to content

Commit

Permalink
Add toast component (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaoyingz authored Apr 19, 2024
1 parent d0779c7 commit 5469907
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 0 deletions.
14 changes: 14 additions & 0 deletions demo/components_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,20 @@ class Delivery(BaseModel):
],
class_name='border-top mt-3 pt-1',
),
c.Div(
components=[
c.Heading(text='Button and Toast', level=2),
c.Paragraph(text='The button below will open a toast.'),
c.Button(text='Show Toast', on_click=PageEvent(name='show-toast')),
c.Toast(
title='Toast',
body=[c.Paragraph(text='This is a toast.')],
open_trigger=PageEvent(name='show-toast'),
position='bottom-end',
),
],
class_name='border-top mt-3 pt-1',
),
title='Components',
)

Expand Down
1 change: 1 addition & 0 deletions demo/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def api_index() -> list[AnyComponent]:
* `Image` - example [here](/components#image)
* `Iframe` - example [here](/components#iframe)
* `Video` - example [here](/components#video)
* `Toast` - example [here](/components#toast)
* `Table` — See [cities table](/table/cities) and [users table](/table/users)
* `Pagination` — See the bottom of the [cities table](/table/cities)
* `ModelForm` — See [forms](/forms/login)
Expand Down
3 changes: 3 additions & 0 deletions src/npm-fastui-bootstrap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Modal } from './modal'
import { Navbar } from './navbar'
import { Pagination } from './pagination'
import { Footer } from './footer'
import { Toast } from './toast'

export const customRender: CustomRender = (props) => {
const { type } = props
Expand All @@ -18,6 +19,8 @@ export const customRender: CustomRender = (props) => {
return () => <Modal {...props} />
case 'Pagination':
return () => <Pagination {...props} />
case 'Toast':
return () => <Toast {...props} />
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/npm-fastui-bootstrap/src/toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FC } from 'react'
import { components, events, renderClassName, EventContextProvider, models } from 'fastui'
import BootstrapToast from 'react-bootstrap/Toast'
import BootstrapToastContainer from 'react-bootstrap/ToastContainer'

export const Toast: FC<models.Toast> = (props) => {
const { className, title, body, position, openTrigger, openContext } = props

const { eventContext, fireId, clear } = events.usePageEventListen(openTrigger, openContext)

return (
<EventContextProvider context={eventContext}>
<BootstrapToastContainer position={position} className="position-fixed bottom-0 end-0 p-3">
<BootstrapToast className={renderClassName(className)} show={!!fireId} onClose={clear}>
<BootstrapToast.Header>
<strong className="me-auto">{title}</strong>
</BootstrapToast.Header>
<BootstrapToast.Body>
<components.AnyCompList propsList={body} />
</BootstrapToast.Body>
</BootstrapToast>
</BootstrapToastContainer>
</EventContextProvider>
)
}
4 changes: 4 additions & 0 deletions src/npm-fastui/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { FireEventComp } from './FireEvent'
import { ErrorComp } from './error'
import { SpinnerComp } from './spinner'
import { CustomComp } from './Custom'
import { ToastComp } from './toast'

// TODO some better way to export components
export {
Expand Down Expand Up @@ -77,6 +78,7 @@ export {
SpinnerComp,
CustomComp,
LinkRender,
ToastComp,
}

export type FastClassNameProps = Exclude<FastProps, Text | Display | ServerLoad | PageTitle | FireEvent>
Expand Down Expand Up @@ -166,6 +168,8 @@ export const AnyComp: FC<FastProps> = (props) => {
return <SpinnerComp {...props} />
case 'Custom':
return <CustomComp {...props} />
case 'Toast':
return <ToastComp {...props} />
default:
unreachable('Unexpected component type', type, props)
return <DisplayError title="Invalid Server Response" description={`Unknown component type: "${type}"`} />
Expand Down
22 changes: 22 additions & 0 deletions src/npm-fastui/src/components/toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC, useEffect } from 'react'

import type { Toast } from '../models'

import { usePageEventListen } from '../events'

export const ToastComp: FC<Toast> = (props) => {
const { title, openTrigger, openContext } = props

const { fireId, clear } = usePageEventListen(openTrigger, openContext)

useEffect(() => {
if (fireId) {
setTimeout(() => {
alert(`${title}\n\nNote: modals are not implemented by pure FastUI, implement a component for 'ToastProps'.`)
clear()
})
}
}, [fireId, title, clear])

return <></>
}
19 changes: 19 additions & 0 deletions src/npm-fastui/src/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type FastProps =
| FormFieldSelect
| FormFieldSelectSearch
| ModelForm
| Toast
export type ClassName =
| string
| ClassName[]
Expand Down Expand Up @@ -460,3 +461,21 @@ export interface ModelForm {
| FormFieldSelectSearch
)[]
}
export interface Toast {
title: string
body: FastProps[]
position?:
| 'top-start'
| 'top-center'
| 'top-end'
| 'middle-start'
| 'middle-center'
| 'middle-end'
| 'bottom-start'
| 'bottom-center'
| 'bottom-end'
openTrigger?: PageEvent
openContext?: ContextType
className?: ClassName
type: 'Toast'
}
24 changes: 24 additions & 0 deletions src/python-fastui/fastui/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,29 @@ class Spinner(_p.BaseModel, extra='forbid'):
type: _t.Literal['Spinner'] = 'Spinner'


class Toast(_p.BaseModel, extra='forbid'):
title: str
body: '_t.List[AnyComponent]'
position: _t.Union[
_t.Literal[
'top-start',
'top-center',
'top-end',
'middle-start',
'middle-center',
'middle-end',
'bottom-start',
'bottom-center',
'bottom-end',
],
None,
] = None
open_trigger: _t.Union[events.PageEvent, None] = _p.Field(default=None, serialization_alias='openTrigger')
open_context: _t.Union[events.ContextType, None] = _p.Field(default=None, serialization_alias='openContext')
class_name: _class_name.ClassNameField = None
type: _t.Literal['Toast'] = 'Toast'


class Custom(_p.BaseModel, extra='forbid'):
data: _types.JsonData
sub_type: str = _p.Field(serialization_alias='subType')
Expand Down Expand Up @@ -343,6 +366,7 @@ class Custom(_p.BaseModel, extra='forbid'):
Form,
FormField,
ModelForm,
Toast,
],
_p.Field(discriminator='type'),
]

0 comments on commit 5469907

Please sign in to comment.