-
Hello, I would like to see TODOMVC implemented in ReactPy. Would someone be kind enough to provide an implementation? For comparison, here is TODOMVC in Solara: |
Beta Was this translation helpful? Give feedback.
Answered by
rmorshea
May 15, 2023
Replies: 1 comment 1 reply
-
The main difference between Solara and ReactPy is that Solara was built to integrate with the existing Jupyter Widget ecosystem. Most of the differences between ReactPy and Solara arise from this fact. However, both attempt to replicate the API of React and thus will this look fairly similar. With that said, here's my take on a simple todo app: from __future__ import annotations
from dataclasses import dataclass
from typing import Any, TypeAlias
import reactpy as rp
TodoItems: TypeAlias = "tuple[TodoItem, ...]"
TodoItemState: TypeAlias = "rp.types.State[TodoItems]"
PICO_CSS = rp.html.link(
{
"rel": "stylesheet",
"href": "https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css",
}
)
@rp.component
def todo_app():
"""A todo app with a list of todo items and an input for new items."""
item_state = rp.use_state(())
return rp.html.div(
{"style": {"margin-top": "var(--block-spacing-vertical)"}},
PICO_CSS,
rp.html.main(
{"class": "container"},
todo_input_form(item_state),
todo_completion(item_state.value),
rp.html.ul(
*[
todo_item(index, item, item_state, key=item.text)
for index, item in enumerate(item_state.value)
]
),
),
)
@rp.component
def todo_input_form(item_state: TodoItemState) -> rp.types.VdomDict:
"""An input form for a new todo item"""
text, set_text = rp.hooks.use_state("")
item_already_exists = any(text == item.text for item in item_state.value)
disable_add = item_already_exists or not text
@rp.event(prevent_default=True)
def handle_submit(event: dict[str, Any]) -> None:
if not disable_add:
new_item = TodoItem(text)
item_state.set_value(item_state.value + (new_item,))
set_text("")
return rp.html.div(
rp.html.form(
{"on_submit": handle_submit},
rp.html.input(
{
"type": "text",
"placeholder": "Enter a new todo item",
"value": text,
"on_change": lambda event: set_text(event["target"]["value"]),
}
),
# disable button if already exists
rp.html.button({"type": "submit", "disabled": disable_add}, "Add"),
)
)
@rp.component
def todo_completion(items: TodoItems) -> rp.types.VdomDict:
"""Display a progress bar showing how many todo items are done."""
done_count = sum(1 for item in items if item.done)
total_count = len(items)
return rp.html.div(
rp.html.progress(
{"value": done_count, "max": total_count},
f"{done_count} / {total_count} done",
)
)
@rp.component
def todo_item(index: int, item: TodoItem, item_state: TodoItemState) -> rp.types.VdomDict:
"""Display a todo item as a list item with a checkbox to mark it as done."""
def toggle_done(event: dict[str, Any]) -> None:
new_item = TodoItem(item.text, not item.done)
item_state.set_value(
item_state.value[:index] + (new_item,) + item_state.value[index + 1 :]
)
return rp.html.li(
{"style": {"text-decoration": "line-through" if item.done else "none"}},
rp.html.input(
{"type": "checkbox", "on_change": toggle_done, "checked": item.done}
),
item.text,
)
@dataclass(frozen=True)
class TodoItem:
text: str
done: bool = False
rp.run(todo_app) |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
metaperl
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The main difference between Solara and ReactPy is that Solara was built to integrate with the existing Jupyter Widget ecosystem. Most of the differences between ReactPy and Solara arise from this fact. However, both attempt to replicate the API of React and thus will this look fairly similar.
With that said, here's my take on a simple todo app: