From bef43928def98c99b40cbe2f0aada512758d3c73 Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Tue, 5 Dec 2023 10:31:30 -0600 Subject: [PATCH 1/7] add FormattedText component --- demo/components_list.py | 8 ++++++ demo/main.py | 1 + .../src/components/FormattedText.tsx | 27 +++++++++++++++++++ src/npm-fastui/src/components/index.tsx | 5 ++++ .../fastui/components/__init__.py | 11 ++++++++ 5 files changed, 52 insertions(+) create mode 100644 src/npm-fastui/src/components/FormattedText.tsx diff --git a/demo/components_list.py b/demo/components_list.py index 5b76e1b7..6ae0c59e 100644 --- a/demo/components_list.py +++ b/demo/components_list.py @@ -28,6 +28,14 @@ def components_view() -> list[AnyComponent]: c.Text(text='This is a text component.'), ] ), + c.Div( + components=[ + c.Heading(text='FormattedText', level=2), + c.Markdown(text='`FormattedText` can be used to change the style of the text.'), + c.FormattedText(text='hola', text_color='red', background_color='blue', text_format='italic'), + ], + class_name='border-top mt-3 pt-1', + ), c.Div( components=[ c.Heading(text='Paragraph', level=2), diff --git a/demo/main.py b/demo/main.py index afbddd65..00b5f9b5 100644 --- a/demo/main.py +++ b/demo/main.py @@ -20,6 +20,7 @@ def api_index() -> list[AnyComponent]: * `Markdown` — that's me :-) * `Text`— example [here](/components#text) +* `FormattedText`— example [here](/components#FormattedText) * `Paragraph` — example [here](/components#paragraph) * `PageTitle` — you'll see the title in the browser tab change when you navigate through the site * `Heading` — example [here](/components#heading) diff --git a/src/npm-fastui/src/components/FormattedText.tsx b/src/npm-fastui/src/components/FormattedText.tsx new file mode 100644 index 00000000..87e2963e --- /dev/null +++ b/src/npm-fastui/src/components/FormattedText.tsx @@ -0,0 +1,27 @@ +import { FC } from 'react' + +import { ClassName } from '../hooks/className' + +export interface FormattedTextProps { + type: 'FormattedText' + text: string + textFormat?: 'bold' | 'italic' | 'underline' | 'strikethrough' + color?: string + backgroundColor?: string + className?: ClassName +} + +export const FormattedTextComp: FC = (props) => { + const { text, textFormat, color, backgroundColor } = props + + const style = { + backgroundColor, + color, + fontWeight: textFormat === 'bold' ? 'bold' : 'normal', + fontStyle: textFormat === 'italic' ? 'italic' : 'normal', + textDecoration: + textFormat === 'underline' ? 'underline' : textFormat === 'strikethrough' ? 'line-through' : 'none', + } + + return {text} +} diff --git a/src/npm-fastui/src/components/index.tsx b/src/npm-fastui/src/components/index.tsx index f500bc53..7dda43e5 100644 --- a/src/npm-fastui/src/components/index.tsx +++ b/src/npm-fastui/src/components/index.tsx @@ -40,6 +40,7 @@ import { JsonComp, JsonProps } from './Json' import { ServerLoadComp, ServerLoadProps } from './ServerLoad' import { ImageComp, ImageProps } from './image' import { IframeComp, IframeProps } from './Iframe' +import { FormattedTextComp, FormattedTextProps } from './FormattedText' export type { TextProps, @@ -67,6 +68,7 @@ export type { ServerLoadProps, ImageProps, IframeProps, + FormattedTextProps, } // TODO some better way to export components @@ -97,6 +99,7 @@ export type FastProps = | ServerLoadProps | ImageProps | IframeProps + | FormattedTextProps export type FastClassNameProps = Exclude @@ -179,6 +182,8 @@ export const AnyComp: FC = (props) => { return case 'Iframe': return + case 'FormattedText': + return default: unreachable('Unexpected component type', type, props) return diff --git a/src/python-fastui/fastui/components/__init__.py b/src/python-fastui/fastui/components/__init__.py index 5cdcb223..01a952de 100644 --- a/src/python-fastui/fastui/components/__init__.py +++ b/src/python-fastui/fastui/components/__init__.py @@ -202,6 +202,17 @@ class Iframe(pydantic.BaseModel, extra='forbid'): type: _t.Literal['Iframe'] = 'Iframe' +class FormattedText(pydantic.BaseModel, extra='forbid'): + text: str + text_format: _t.Literal['bold', 'italic', 'underline', 'strikethrough'] | None = pydantic.Field( + None, serialization_alias='textFormat' + ) + # TODO, use pydantic-extra-types Color? + text_color: str | None = pydantic.Field(None, serialization_alias='color') + background_color: str | None = pydantic.Field(None, serialization_alias='backgroundColor') + type: _t.Literal['FormattedText'] = 'FormattedText' + + AnyComponent = _te.Annotated[ _t.Union[ Text, From 5f76caac6e7e83accafa73dc0a5cd8dbf1850a0c Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 6 Dec 2023 10:55:53 -0600 Subject: [PATCH 2/7] fix '|' to _t.Union[] --- src/python-fastui/fastui/components/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python-fastui/fastui/components/__init__.py b/src/python-fastui/fastui/components/__init__.py index 01a952de..b69cc91f 100644 --- a/src/python-fastui/fastui/components/__init__.py +++ b/src/python-fastui/fastui/components/__init__.py @@ -204,12 +204,12 @@ class Iframe(pydantic.BaseModel, extra='forbid'): class FormattedText(pydantic.BaseModel, extra='forbid'): text: str - text_format: _t.Literal['bold', 'italic', 'underline', 'strikethrough'] | None = pydantic.Field( + text_format: _t.Union[_t.Literal['bold', 'italic', 'underline', 'strikethrough'], None] = pydantic.Field( None, serialization_alias='textFormat' ) # TODO, use pydantic-extra-types Color? - text_color: str | None = pydantic.Field(None, serialization_alias='color') - background_color: str | None = pydantic.Field(None, serialization_alias='backgroundColor') + text_color: _t.Union[str, None] = pydantic.Field(None, serialization_alias='color') + background_color: _t.Union[str, None] = pydantic.Field(None, serialization_alias='backgroundColor') type: _t.Literal['FormattedText'] = 'FormattedText' From 6c6e9a5367b40583ff0d44faca8306bf5bdce966 Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 6 Dec 2023 11:44:25 -0600 Subject: [PATCH 3/7] update text type Button & Paragraph --- src/python-fastui/fastui/components/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python-fastui/fastui/components/__init__.py b/src/python-fastui/fastui/components/__init__.py index b69cc91f..9e50b81c 100644 --- a/src/python-fastui/fastui/components/__init__.py +++ b/src/python-fastui/fastui/components/__init__.py @@ -56,7 +56,7 @@ class Text(pydantic.BaseModel, extra='forbid'): class Paragraph(pydantic.BaseModel, extra='forbid'): - text: str + text: '_t.List[_t.Union[str, FormattedText, Link]]' type: _t.Literal['Paragraph'] = 'Paragraph' @@ -114,7 +114,7 @@ class Code(pydantic.BaseModel, extra='forbid'): class Button(pydantic.BaseModel, extra='forbid'): - text: str + text: '_t.List[_t.Union[str, FormattedText, Link]]' on_click: _t.Union[events.AnyEvent, None] = pydantic.Field(default=None, serialization_alias='onClick') html_type: _t.Union[_t.Literal['button', 'submit', 'reset'], None] = pydantic.Field( default=None, serialization_alias='htmlType' From bc87be2a0644cd6b37e0b3a6392777e203c996f1 Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 6 Dec 2023 11:59:38 -0600 Subject: [PATCH 4/7] update demo FormattedText --- demo/components_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/components_list.py b/demo/components_list.py index 6ae0c59e..a77e2c12 100644 --- a/demo/components_list.py +++ b/demo/components_list.py @@ -32,7 +32,7 @@ def components_view() -> list[AnyComponent]: components=[ c.Heading(text='FormattedText', level=2), c.Markdown(text='`FormattedText` can be used to change the style of the text.'), - c.FormattedText(text='hola', text_color='red', background_color='blue', text_format='italic'), + c.FormattedText(text='This is a FormattedText component.', text_color='red', background_color='blue', text_format='italic'), ], class_name='border-top mt-3 pt-1', ), From 975d48e2b74b4d2d15fb7b1fd8aa068d9ce3b20d Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 13 Dec 2023 17:27:01 -0600 Subject: [PATCH 5/7] update Paragraph, Button & Text support just str --- src/python-fastui/fastui/components/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python-fastui/fastui/components/__init__.py b/src/python-fastui/fastui/components/__init__.py index 9e50b81c..a650a67d 100644 --- a/src/python-fastui/fastui/components/__init__.py +++ b/src/python-fastui/fastui/components/__init__.py @@ -51,12 +51,12 @@ class Text(pydantic.BaseModel, extra='forbid'): - text: str + text: '_t.Union[str, _t.List[_t.Union[str, FormattedText, Link]]]' type: _t.Literal['Text'] = 'Text' class Paragraph(pydantic.BaseModel, extra='forbid'): - text: '_t.List[_t.Union[str, FormattedText, Link]]' + text: '_t.Union[str, _t.List[_t.Union[str, FormattedText, Link]]]' type: _t.Literal['Paragraph'] = 'Paragraph' @@ -114,7 +114,7 @@ class Code(pydantic.BaseModel, extra='forbid'): class Button(pydantic.BaseModel, extra='forbid'): - text: '_t.List[_t.Union[str, FormattedText, Link]]' + text: '_t.Union[str, _t.List[_t.Union[str, FormattedText, Link]]]' on_click: _t.Union[events.AnyEvent, None] = pydantic.Field(default=None, serialization_alias='onClick') html_type: _t.Union[_t.Literal['button', 'submit', 'reset'], None] = pydantic.Field( default=None, serialization_alias='htmlType' From c96b1d648df9489a76ea5a4a157d9c533c77aa49 Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 13 Dec 2023 17:31:55 -0600 Subject: [PATCH 6/7] update FormattedText.tsx --- src/npm-fastui/src/components/FormattedText.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npm-fastui/src/components/FormattedText.tsx b/src/npm-fastui/src/components/FormattedText.tsx index 87e2963e..ed0dda39 100644 --- a/src/npm-fastui/src/components/FormattedText.tsx +++ b/src/npm-fastui/src/components/FormattedText.tsx @@ -17,8 +17,8 @@ export const FormattedTextComp: FC = (props) => { const style = { backgroundColor, color, - fontWeight: textFormat === 'bold' ? 'bold' : 'normal', - fontStyle: textFormat === 'italic' ? 'italic' : 'normal', + fontWeight: textFormat, + fontStyle: textFormat, textDecoration: textFormat === 'underline' ? 'underline' : textFormat === 'strikethrough' ? 'line-through' : 'none', } From 6d1c38631739f5988ef42a6a1439ee99f485988e Mon Sep 17 00:00:00 2001 From: Alonso Melgar Lopez Date: Wed, 13 Dec 2023 17:43:12 -0600 Subject: [PATCH 7/7] fix demo FormattedText --- demo/components_list.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/demo/components_list.py b/demo/components_list.py index a77e2c12..529b2d95 100644 --- a/demo/components_list.py +++ b/demo/components_list.py @@ -31,8 +31,16 @@ def components_view() -> list[AnyComponent]: c.Div( components=[ c.Heading(text='FormattedText', level=2), - c.Markdown(text='`FormattedText` can be used to change the style of the text.'), - c.FormattedText(text='This is a FormattedText component.', text_color='red', background_color='blue', text_format='italic'), + c.Markdown( + text="""`FormattedText` can be used to change the style of the text, this is particularly + useful to avoid the overhead of loading the markdown renderer, or when you're including user + generated content that you don't want to escape styling."""), + c.FormattedText( + text='This is a FormattedText component.', + text_color='red', + background_color='blue', + text_format='italic' + ), ], class_name='border-top mt-3 pt-1', ),