WebComPy
  • Home
  • Documents
    • Documents

  • Demos
    • HelloWorld
    • FizzBuzz
    • ToDo List
    • Matplotlib Sample
    • Fetch Sample
ToDo List

Title:

  • Try WebComPy
  • Create WebComPy project

Code
import uuid
from typing import Any, TypedDict
from webcompy.elements import html, repeat, DomNodeRef
from webcompy.components import define_component, ComponentContext
from webcompy.signal import Signal, computed, ReactiveDict


class TodoData(TypedDict):
    title: Signal[str]
    done: Signal[bool]


@define_component
def ToDoItem(context: ComponentContext[TodoData]):
    input_ref = DomNodeRef()

    def on_change_state(_: Any):
        context.props["done"].value = input_ref.checked

    return html.LI(
        {},
        html.LABEL(
            {},
            html.INPUT(
                {
                    "type": "checkbox",
                    "@change": on_change_state,
                    ":ref": input_ref,
                },
            ),
        ),
        " ",
        html.SPAN(
            {
                "style": computed(
                    lambda: "text-decoration: line-through;"
                    if context.props["done"].value
                    else ""
                )
            },
            context.props["title"],
        ),
    )


ToDoItem.scoped_style = {
    "li": {
        "color": "#2d8fdd",
        "border-left": " solid 6px #2d8fdd",
        "background": "#f1f8ff",
        "line-height": "1.5",
        "margin": "5px",
        "padding": "5px",
        "vertical-align": "middle",
        "list-style-type": "none",
    }
}


@define_component
def ToDoList(_: ComponentContext[None]):
    input_ref = DomNodeRef()
    data: ReactiveDict[str, TodoData] = ReactiveDict(
        {
            str(uuid.uuid4()): {
                "title": Signal("Try WebComPy"),
                "done": Signal(False),
            },
            str(uuid.uuid4()): {
                "title": Signal("Create WebComPy project"),
                "done": Signal(False),
            },
        }
    )

    def append_item(_: Any):
        title = input_ref.value
        if title:
            data[str(uuid.uuid4())] = {
                "title": Signal(title),
                "done": Signal(False),
            }
        input_ref.value = ""

    def remove_done_items(_: Any):
        keys_to_remove = [
            k for k, v in data.value.items() if v["done"].value
        ]
        for k in keys_to_remove:
            del data[k]

    return html.DIV(
        {},
        html.P(
            {},
            "Title: ",
            html.INPUT({":ref": input_ref}),
            html.BUTTON({"@click": append_item}, "Add ToDo"),
            html.BUTTON({"@click": remove_done_items}, "Remove Done Items"),
        ),
        html.UL(
            {},
            repeat(
                data,
                lambda v, k: ToDoItem(v),
            ),
        ),
    )


ToDoList.scoped_style = {
    "button": {
        "display": "inline-block",
        "text-decoration": "none",
        "border": "solid 2px #668ad8",
        "border-radius": "3px",
        "transition": "0.2s",
        "color": "black",
    },
    "button:hover": {
        "background": "#668ad8",
        "color": "white",
    },
}