123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- """A Rich Text Editor based on SunEditor."""
- from __future__ import annotations
- import enum
- from typing import Any, Literal
- 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[
- 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)
|