271 lines
7.8 KiB
Python
271 lines
7.8 KiB
Python
"""A Rich Text Editor based on SunEditor."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
from typing import Any, Dict, Literal, Union
|
|
|
|
from reflex.base import Base
|
|
from reflex.components.component import Component, NoSSRComponent
|
|
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
|
|
from reflex.utils.format import to_camel_case
|
|
from reflex.utils.imports import ImportDict, ImportVar
|
|
from reflex.vars.base import Var
|
|
|
|
|
|
class EditorButtonList(list, enum.Enum):
|
|
"""List enum that provides three predefined button lists."""
|
|
|
|
BASIC = [
|
|
["font", "fontSize"],
|
|
["fontColor"],
|
|
["horizontalRule"],
|
|
["link", "image"],
|
|
]
|
|
FORMATTING = [
|
|
["undo", "redo"],
|
|
["bold", "underline", "italic", "strike", "subscript", "superscript"],
|
|
["removeFormat"],
|
|
["outdent", "indent"],
|
|
["fullScreen", "showBlocks", "codeView"],
|
|
["preview", "print"],
|
|
]
|
|
COMPLEX = [
|
|
["undo", "redo"],
|
|
["font", "fontSize", "formatBlock"],
|
|
["bold", "underline", "italic", "strike", "subscript", "superscript"],
|
|
["removeFormat"],
|
|
"/",
|
|
["fontColor", "hiliteColor"],
|
|
["outdent", "indent"],
|
|
["align", "horizontalRule", "list", "table"],
|
|
["link", "image", "video"],
|
|
["fullScreen", "showBlocks", "codeView"],
|
|
["preview", "print"],
|
|
["save", "template"],
|
|
]
|
|
|
|
|
|
class EditorOptions(Base):
|
|
"""Some of the additional options to configure the Editor.
|
|
Complete list of options found here:
|
|
https://github.com/JiHong88/SunEditor/blob/master/README.md#options.
|
|
"""
|
|
|
|
# Specifies default tag name of the editor.
|
|
# default: 'p' {String}
|
|
default_tag: str | None = None
|
|
|
|
# The mode of the editor ('classic', 'inline', 'balloon', 'balloon-always').
|
|
# default: 'classic' {String}
|
|
mode: str | None = None
|
|
|
|
# If true, the editor is set to RTL(Right To Left) mode.
|
|
# default: false {Boolean}
|
|
rtl: bool | None = None
|
|
|
|
# List of buttons to use in the toolbar.
|
|
button_list: list[list[str] | str] | None
|
|
|
|
|
|
def on_blur_spec(e: Var, content: Var[str]) -> tuple[Var[str]]:
|
|
"""A helper function to specify the on_blur event handler.
|
|
|
|
Args:
|
|
e: The event.
|
|
content: The content of the editor.
|
|
|
|
Returns:
|
|
A tuple containing the content of the editor.
|
|
"""
|
|
return (content,)
|
|
|
|
|
|
def on_paste_spec(
|
|
e: Var, clean_data: Var[str], max_char_count: Var[bool]
|
|
) -> tuple[Var[str], Var[bool]]:
|
|
"""A helper function to specify the on_paste event handler.
|
|
|
|
Args:
|
|
e: The event.
|
|
clean_data: The clean data.
|
|
max_char_count: The maximum character count.
|
|
|
|
Returns:
|
|
A tuple containing the clean data and the maximum character count.
|
|
"""
|
|
return (clean_data, max_char_count)
|
|
|
|
|
|
class Editor(NoSSRComponent):
|
|
"""A Rich Text Editor component based on SunEditor.
|
|
Not every JS prop is listed here (some are not easily usable from python),
|
|
refer to the library docs for a complete list.
|
|
"""
|
|
|
|
library = "suneditor-react"
|
|
|
|
tag = "SunEditor"
|
|
|
|
is_default = True
|
|
|
|
lib_dependencies: list[str] = ["suneditor"]
|
|
|
|
# Language of the editor.
|
|
# Alternatively to a string, a dict of your language can be passed to this prop.
|
|
# Please refer to the library docs for this.
|
|
# options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" |
|
|
# "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it"
|
|
# default: "en".
|
|
lang: Var[
|
|
Union[
|
|
Literal[
|
|
"en",
|
|
"da",
|
|
"de",
|
|
"es",
|
|
"fr",
|
|
"ja",
|
|
"ko",
|
|
"pt_br",
|
|
"ru",
|
|
"zh_cn",
|
|
"ro",
|
|
"pl",
|
|
"ckb",
|
|
"lv",
|
|
"se",
|
|
"ua",
|
|
"he",
|
|
"it",
|
|
],
|
|
dict,
|
|
]
|
|
]
|
|
|
|
# This is used to set the HTML form name of the editor.
|
|
# This means on HTML form submission,
|
|
# it will be submitted together with contents of the editor by the name provided.
|
|
name: Var[str]
|
|
|
|
# Sets the default value of the editor.
|
|
# This is useful if you don't want the on_change method to be called on render.
|
|
# If you want the on_change method to be called on render please use the set_contents prop
|
|
default_value: Var[str]
|
|
|
|
# Sets the width of the editor.
|
|
# px and percentage values are accepted, eg width="100%" or width="500px"
|
|
# default: 100%
|
|
width: Var[str]
|
|
|
|
# Sets the height of the editor.
|
|
# px and percentage values are accepted, eg height="100%" or height="100px"
|
|
height: Var[str]
|
|
|
|
# Sets the placeholder of the editor.
|
|
placeholder: Var[str]
|
|
|
|
# Should the editor receive focus when initialized?
|
|
auto_focus: Var[bool]
|
|
|
|
# Pass an EditorOptions instance to modify the behaviour of Editor even more.
|
|
set_options: Var[Dict]
|
|
|
|
# Whether all SunEditor plugins should be loaded.
|
|
# default: True.
|
|
set_all_plugins: Var[bool]
|
|
|
|
# Set the content of the editor.
|
|
# Note: To set the initial contents of the editor
|
|
# without calling the on_change event,
|
|
# please use the default_value prop.
|
|
# set_contents is used to set the contents of the editor programmatically.
|
|
# You must be aware that, when the set_contents's prop changes,
|
|
# the on_change event is triggered.
|
|
set_contents: Var[str]
|
|
|
|
# Append editor content
|
|
append_contents: Var[str]
|
|
|
|
# Sets the default style of the editor's edit area
|
|
set_default_style: Var[str]
|
|
|
|
# Disable the editor
|
|
# default: False.
|
|
disable: Var[bool]
|
|
|
|
# Hide the editor
|
|
# default: False.
|
|
hide: Var[bool]
|
|
|
|
# Hide the editor toolbar
|
|
# default: False.
|
|
hide_toolbar: Var[bool]
|
|
|
|
# Disable the editor toolbar
|
|
# default: False.
|
|
disable_toolbar: Var[bool]
|
|
|
|
# Fired when the editor content changes.
|
|
on_change: EventHandler[passthrough_event_spec(str)]
|
|
|
|
# Fired when the something is inputted in the editor.
|
|
on_input: EventHandler[no_args_event_spec]
|
|
|
|
# Fired when the editor loses focus.
|
|
on_blur: EventHandler[on_blur_spec]
|
|
|
|
# Fired when the editor is loaded.
|
|
on_load: EventHandler[passthrough_event_spec(bool)]
|
|
|
|
# Fired when the editor content is copied.
|
|
on_copy: EventHandler[no_args_event_spec]
|
|
|
|
# Fired when the editor content is cut.
|
|
on_cut: EventHandler[no_args_event_spec]
|
|
|
|
# Fired when the editor content is pasted.
|
|
on_paste: EventHandler[on_paste_spec]
|
|
|
|
# Fired when the code view is toggled.
|
|
toggle_code_view: EventHandler[passthrough_event_spec(bool)]
|
|
|
|
# Fired when the full screen mode is toggled.
|
|
toggle_full_screen: EventHandler[passthrough_event_spec(bool)]
|
|
|
|
def add_imports(self) -> ImportDict:
|
|
"""Add imports for the Editor component.
|
|
|
|
Returns:
|
|
The import dict.
|
|
"""
|
|
return {
|
|
"": ImportVar(tag="suneditor/dist/css/suneditor.min.css", install=False)
|
|
}
|
|
|
|
@classmethod
|
|
def create(
|
|
cls, set_options: EditorOptions | None = None, **props: Any
|
|
) -> Component:
|
|
"""Create an instance of Editor. No children allowed.
|
|
|
|
Args:
|
|
set_options: Configuration object to further configure the instance.
|
|
**props: Any properties to be passed to the Editor
|
|
|
|
Returns:
|
|
An Editor instance.
|
|
|
|
Raises:
|
|
ValueError: If set_options is a state Var.
|
|
"""
|
|
if set_options is not None:
|
|
if isinstance(set_options, Var):
|
|
raise ValueError("EditorOptions cannot be a state Var")
|
|
props["set_options"] = {
|
|
to_camel_case(k): v
|
|
for k, v in set_options.dict().items()
|
|
if v is not None
|
|
}
|
|
return super().create(*[], **props)
|