Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: ci
env:
OPENAI_API_KEY: "dummy"
on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
check-pyright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install UV
uses: astral-sh/setup-uv@v6
with:
python-version: "3.10"
enable-cache: true
activate-environment: true
- name: Install Reflex
run: uv sync
- name: Run Pyright
run: pyright .

check-ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install UV
uses: astral-sh/setup-uv@v6
with:
python-version: "3.10"
enable-cache: true
activate-environment: true
- name: Install Reflex
run: uv sync
- name: Run Ruff
uses: astral-sh/ruff-action@v3
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
```reflex-suneditor``` is [suneditor](http://suneditor.com/sample/index.html) based package.

package is avaiable at https://pypi.org/project/reflex-suneditor/0.0.11/
package is avaiable at https://pypi.org/project/reflex-suneditor

Installation:

Expand Down
1,155 changes: 0 additions & 1,155 deletions poetry.lock

This file was deleted.

26 changes: 18 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
[tool.poetry]
[project]
name = "reflex-suneditor"
version = "0.0.11"
version = "0.1.0"
description = "Reflex suneditor"
authors = ["Akshay Awate <[email protected]>"]
authors = [{ name = "Akshay Awate", email = "[email protected]" }]
readme = "README.md"
packages = [{include = "reflex_suneditor"}]
requires-python = ">=3.10"

[tool.poetry.dependencies]
python = "^3.7"
reflex = "0.6.2"
reflex = "0.7.14"

[dependency-groups]
dev = ["ruff", "pyright"]

[tool.ruff]
target-version = "py310"
output-format = "concise"
lint.isort.split-on-trailing-comma = false
lint.pydocstyle.convention = "google"
lint.select = ["ALL"]
lint.ignore = ["COM", "PLC0414", "RUF012", "TC002"]


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
requires = ["hatchling"]
build-backend = "hatchling.build"
6 changes: 4 additions & 2 deletions reflex_suneditor/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Editor component."""

from .editor import Editor, EditorButtonList, EditorOptions
from .editor import Editor as Editor
from .editor import EditorButtonList as EditorButtonList
from .editor import EditorOptions as EditorOptions

editor = Editor.create
editor = Editor.create
141 changes: 84 additions & 57 deletions reflex_suneditor/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from __future__ import annotations

import enum
from typing import Dict, List, Literal, Optional, Union
from typing import Literal

from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent
from reflex.event import EventHandler
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
Expand Down Expand Up @@ -48,70 +48,99 @@ class EditorButtonList(list, enum.Enum):

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: Optional[str] = None
default_tag: str | None = None

# The mode of the editor ('classic', 'inline', 'balloon', 'balloon-always').
# default: 'classic' {String}
mode: Optional[str] = None
mode: str | None = None

# If true, the editor is set to RTL(Right To Left) mode.
# default: false {Boolean}
rtl: Optional[bool] = None
rtl: bool | None = None

# List of buttons to use in the toolbar.
button_list: Optional[List[Union[List[str], str]]]
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"
library = "suneditor-react@3.6.1"

tag = "SunEditor"

is_default = True

lib_dependencies: List[str] = ["suneditor"]
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"
# "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,
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.
Expand All @@ -121,7 +150,7 @@ class Editor(NoSSRComponent):

# 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
# If you want the on_change method to be called on render use the set_contents prop
default_value: Var[str]

# Sets the width of the editor.
Expand All @@ -140,10 +169,10 @@ class Editor(NoSSRComponent):
auto_focus: Var[bool]

# Pass an EditorOptions instance to modify the behaviour of Editor even more.
set_options: Var[Dict]
set_options: Var[dict]

# Whether all SunEditor plugins should be loaded.
# default: True
# default: True.
set_all_plugins: Var[bool]

# Set the content of the editor.
Expand All @@ -162,52 +191,47 @@ class Editor(NoSSRComponent):
set_default_style: Var[str]

# Disable the editor
# default: False
# default: False.
disable: Var[bool]

# Hide the editor
# default: False
# default: False.
hide: Var[bool]

# Hide the editor toolbar
# default: False
# default: False.
hide_toolbar: Var[bool]

# Disable the editor toolbar
# default: False
# default: False.
disable_toolbar: Var[bool]

# Fired when the editor content changes.
on_change: EventHandler[lambda content: [content]]
on_change: EventHandler[passthrough_event_spec(str)]

# Fired when the something is inputted in the editor.
on_input: EventHandler[lambda e: [e]]
on_input: EventHandler[no_args_event_spec]

# Fired when the editor loses focus.
on_blur: EventHandler[lambda e, content: [content]]
on_blur: EventHandler[on_blur_spec]

# Fired when the editor is loaded.
on_load: EventHandler[lambda reload: [reload]]

# Fired when the editor is resized.
on_resize_editor: EventHandler[lambda height, prev_height: [height, prev_height]]
on_load: EventHandler[passthrough_event_spec(bool)]

# Fired when the editor content is copied.
on_copy: EventHandler[lambda e, clipboard_data: [clipboard_data]]
on_copy: EventHandler[no_args_event_spec]

# Fired when the editor content is cut.
on_cut: EventHandler[lambda e, clipboard_data: [clipboard_data]]
on_cut: EventHandler[no_args_event_spec]

# Fired when the editor content is pasted.
on_paste: EventHandler[
lambda e, clean_data, max_char_count: [clean_data, max_char_count]
]
on_paste: EventHandler[on_paste_spec]

# Fired when the code view is toggled.
toggle_code_view: EventHandler[lambda is_code_view: [is_code_view]]
toggle_code_view: EventHandler[passthrough_event_spec(bool)]

# Fired when the full screen mode is toggled.
toggle_full_screen: EventHandler[lambda is_full_screen: [is_full_screen]]
toggle_full_screen: EventHandler[passthrough_event_spec(bool)]

def add_imports(self) -> ImportDict:
"""Add imports for the Editor component.
Expand All @@ -220,11 +244,13 @@ def add_imports(self) -> ImportDict:
}

@classmethod
def create(cls, set_options: Optional[EditorOptions] = None, **props) -> Component:
def create(
cls, set_options: EditorOptions | None = None, **props: object
) -> Component:
"""Create an instance of Editor. No children allowed.

Args:
set_options(Optional[EditorOptions]): Configuration object to further configure the instance.
set_options: Configuration object to further configure the instance.
**props: Any properties to be passed to the Editor

Returns:
Expand All @@ -235,10 +261,11 @@ def create(cls, set_options: Optional[EditorOptions] = None, **props) -> Compone
"""
if set_options is not None:
if isinstance(set_options, Var):
raise ValueError("EditorOptions cannot be a state Var")
msg = "EditorOptions cannot be a state Var"
raise ValueError(msg)
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)
return super().create(*[], **props)
Empty file removed tests/__init__.py
Empty file.
Loading
Loading