From 6682629612491d1e3f820eb66e52b8c9a76e6e7b Mon Sep 17 00:00:00 2001 From: Omar MHAIMDAT Date: Sat, 2 Dec 2023 21:52:00 +0100 Subject: [PATCH 1/4] Add Image component support --- packages/fastui/src/components/image.tsx | 31 ++++++++++++++++++++++++ packages/fastui/src/components/index.tsx | 5 ++++ python/demo/components_list.py | 1 + python/fastui/components/__init__.py | 11 +++++++++ 4 files changed, 48 insertions(+) create mode 100644 packages/fastui/src/components/image.tsx diff --git a/packages/fastui/src/components/image.tsx b/packages/fastui/src/components/image.tsx new file mode 100644 index 00000000..97d7bd8a --- /dev/null +++ b/packages/fastui/src/components/image.tsx @@ -0,0 +1,31 @@ +import {FC} from 'react' + +import {ClassName, useClassName} from '../hooks/className' +import {useFireEvent, AnyEvent} from '../events' + +export interface ImageProps { + type: 'Image' + src: string + alt?: string + width?: number | string + height?: number | string + onClick?: AnyEvent + className?: ClassName +} + +export const ImageComp: FC = (props) => { + const {src, alt, width, height, onClick} = props + + const {fireEvent} = useFireEvent() + + return ( + {alt} fireEvent(onClick)} + /> + ) +} diff --git a/packages/fastui/src/components/index.tsx b/packages/fastui/src/components/index.tsx index ee58e6d0..d6a04156 100644 --- a/packages/fastui/src/components/index.tsx +++ b/packages/fastui/src/components/index.tsx @@ -38,6 +38,7 @@ import { } from './display' import { JsonComp, JsonProps } from './Json' import { ServerLoadComp, ServerLoadProps } from './ServerLoad' +import { ImageComp, ImageProps } from './image' export type { TextProps, @@ -63,6 +64,7 @@ export type { DisplayPrimitiveProps, JsonProps, ServerLoadProps, + ImageProps, } // TODO some better way to export components @@ -91,6 +93,7 @@ export type FastProps = | AllDisplayProps | JsonProps | ServerLoadProps + | ImageProps export type FastClassNameProps = Exclude @@ -169,6 +172,8 @@ export const AnyComp: FC = (props) => { return case 'ServerLoad': return + case 'Image': + return default: unreachable('Unexpected component type', type, props) return diff --git a/python/demo/components_list.py b/python/demo/components_list.py index 80b2fe53..910bf818 100644 --- a/python/demo/components_list.py +++ b/python/demo/components_list.py @@ -160,6 +160,7 @@ class Delivery(BaseModel): ], class_name='border-top mt-3 pt-1', ), + c.Image(src='https://avatars.githubusercontent.com/u/110818415', alt='Pydantic Logo'), title='Components', ) diff --git a/python/fastui/components/__init__.py b/python/fastui/components/__init__.py index 2093783e..72669178 100644 --- a/python/fastui/components/__init__.py +++ b/python/fastui/components/__init__.py @@ -47,6 +47,7 @@ 'Table', 'Display', 'Details', + 'Image', ) @@ -169,6 +170,15 @@ class ServerLoad(pydantic.BaseModel, extra='forbid'): sse: bool | None = None type: typing.Literal['ServerLoad'] = 'ServerLoad' +class Image(pydantic.BaseModel, extra='forbid'): + src: str + alt: str | None = None + width: int | str | None = None + height: int | str | None = None + on_click: events.AnyEvent | None = pydantic.Field(default=None, serialization_alias='onClick') + class_name: _class_name.ClassName = None + type: typing.Literal['Image'] = 'Image' + AnyComponent = typing.Annotated[ Text @@ -191,6 +201,7 @@ class ServerLoad(pydantic.BaseModel, extra='forbid'): | Details | Form | ModelForm + | Image | FormField, pydantic.Field(discriminator='type'), ] From cda858439eed956da0c687988e90cc93f09e0503 Mon Sep 17 00:00:00 2001 From: Omar MHAIMDAT Date: Sat, 2 Dec 2023 21:58:32 +0100 Subject: [PATCH 2/4] Fix linting issues --- packages/fastui/src/components/image.tsx | 44 ++++++++++++------------ python/fastui/components/__init__.py | 1 + 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/fastui/src/components/image.tsx b/packages/fastui/src/components/image.tsx index 97d7bd8a..191ba1d2 100644 --- a/packages/fastui/src/components/image.tsx +++ b/packages/fastui/src/components/image.tsx @@ -1,31 +1,31 @@ -import {FC} from 'react' +import { FC } from 'react' -import {ClassName, useClassName} from '../hooks/className' -import {useFireEvent, AnyEvent} from '../events' +import { ClassName, useClassName } from '../hooks/className' +import { useFireEvent, AnyEvent } from '../events' export interface ImageProps { - type: 'Image' - src: string - alt?: string - width?: number | string - height?: number | string - onClick?: AnyEvent - className?: ClassName + type: 'Image' + src: string + alt?: string + width?: number | string + height?: number | string + onClick?: AnyEvent + className?: ClassName } export const ImageComp: FC = (props) => { - const {src, alt, width, height, onClick} = props + const { src, alt, width, height, onClick } = props - const {fireEvent} = useFireEvent() + const { fireEvent } = useFireEvent() - return ( - {alt} fireEvent(onClick)} - /> - ) + return ( + {alt} fireEvent(onClick)} + /> + ) } diff --git a/python/fastui/components/__init__.py b/python/fastui/components/__init__.py index 72669178..5015c1ff 100644 --- a/python/fastui/components/__init__.py +++ b/python/fastui/components/__init__.py @@ -170,6 +170,7 @@ class ServerLoad(pydantic.BaseModel, extra='forbid'): sse: bool | None = None type: typing.Literal['ServerLoad'] = 'ServerLoad' + class Image(pydantic.BaseModel, extra='forbid'): src: str alt: str | None = None From e6fe7cb74f4ffd32630f83528b774059667c8ab9 Mon Sep 17 00:00:00 2001 From: Omar MHAIMDAT Date: Sun, 3 Dec 2023 09:40:52 +0100 Subject: [PATCH 3/4] Add referrepolicy and loading attribute to ImageProps Add float as possible type for width and height --- packages/fastui/src/components/image.tsx | 14 +++++++++++++- python/demo/components_list.py | 17 ++++++++++++++++- python/fastui/components/__init__.py | 15 +++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/fastui/src/components/image.tsx b/packages/fastui/src/components/image.tsx index 191ba1d2..8e04b118 100644 --- a/packages/fastui/src/components/image.tsx +++ b/packages/fastui/src/components/image.tsx @@ -9,12 +9,22 @@ export interface ImageProps { alt?: string width?: number | string height?: number | string + referrerPolicy?: + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url' + loading?: 'eager' | 'lazy' onClick?: AnyEvent className?: ClassName } export const ImageComp: FC = (props) => { - const { src, alt, width, height, onClick } = props + const { src, alt, width, height, referrerPolicy, loading, onClick } = props const { fireEvent } = useFireEvent() @@ -25,6 +35,8 @@ export const ImageComp: FC = (props) => { alt={alt} width={width} height={height} + referrerPolicy={referrerPolicy} + loading={loading} onClick={() => fireEvent(onClick)} /> ) diff --git a/python/demo/components_list.py b/python/demo/components_list.py index 910bf818..65092778 100644 --- a/python/demo/components_list.py +++ b/python/demo/components_list.py @@ -160,7 +160,22 @@ class Delivery(BaseModel): ], class_name='border-top mt-3 pt-1', ), - c.Image(src='https://avatars.githubusercontent.com/u/110818415', alt='Pydantic Logo'), + c.Div( + components=[ + c.Heading(text='Image', level=2), + c.Paragraph(text='An image component.'), + c.Image( + src='https://avatars.githubusercontent.com/u/110818415', + alt='Pydantic Logo', + width=200, + height=200, + loading='lazy', + referrerpolicy='no-referrer', + class_name='border rounded', + ), + ], + class_name='border-top mt-3 pt-1', + ), title='Components', ) diff --git a/python/fastui/components/__init__.py b/python/fastui/components/__init__.py index 5015c1ff..e6926d11 100644 --- a/python/fastui/components/__init__.py +++ b/python/fastui/components/__init__.py @@ -174,8 +174,19 @@ class ServerLoad(pydantic.BaseModel, extra='forbid'): class Image(pydantic.BaseModel, extra='forbid'): src: str alt: str | None = None - width: int | str | None = None - height: int | str | None = None + width: int | float | str | None = None + height: int | float | str | None = None + referrerpolicy: typing.Literal[ + 'no-referrer', + 'no-referrer-when-downgrade', + 'origin', + 'origin-when-cross-origin', + 'same-origin', + 'strict-origin', + 'strict-origin-when-cross-origin', + 'unsafe-url', + ] | None = None + loading: typing.Literal['eager', 'lazy'] | None = None on_click: events.AnyEvent | None = pydantic.Field(default=None, serialization_alias='onClick') class_name: _class_name.ClassName = None type: typing.Literal['Image'] = 'Image' From b5850b3800b480615924cf0bf1ffea4badba08b0 Mon Sep 17 00:00:00 2001 From: Omar MHAIMDAT Date: Mon, 4 Dec 2023 19:27:33 +0100 Subject: [PATCH 4/4] Fix linting issues --- python/fastui/components/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/fastui/components/__init__.py b/python/fastui/components/__init__.py index 3891775c..ccfd68b2 100644 --- a/python/fastui/components/__init__.py +++ b/python/fastui/components/__init__.py @@ -190,7 +190,8 @@ class Image(pydantic.BaseModel, extra='forbid'): on_click: events.AnyEvent | None = pydantic.Field(default=None, serialization_alias='onClick') class_name: _class_name.ClassName = None type: typing.Literal['Image'] = 'Image' - + + class Iframe(pydantic.BaseModel, extra='forbid'): src: pydantic.HttpUrl title: str | None = None