byteface / domonic

Create HTML with python 3 using a standard DOM API. Includes a python port of JavaScript for interoperability and tons of other cool features. A fast prototyping library.
https://domonic.readthedocs.io/
MIT License
129 stars 13 forks source link

htmx integration #69

Open CRY-D opened 4 months ago

CRY-D commented 4 months ago

HeyπŸ‘‹ I'm exploring ways to integrate htmx with domonic. Although the **{"":""} method works just fine, but it tends to result in spaghetti-like code just like React or Vue 😝

Screenshot_20240218_184043

To avoid this, I've worked around. However, the challenge lies in creating custom elements inherited from base elements for inputs, links, buttons, forms, and perhaps divs each one for each one . here is an example of my simple cutom button:

from domonic import button

class Button(button):
    def __init__(self, text, accent, icon):
        super().__init__(text)
        self.setAttribute("accent", accent)

    def change_accent(self, accent):
        self.setAttribute("accent", accent)

    def htmx_get(self, url: str):
        self.setAttribute("hx-get", url)

    def htmx_post(self, url: str):
        self.setAttribute("hx-post", url)

    def htmx_trigger(self, event: str):
        self.setAttribute("hx-trigger", event)

    def htmx_target(self, target: str):
        self.setAttribute("hx-target", target)

    def htmx_swap(self, swap: str):
        self.setAttribute("hx-swap", swap)

the question, Is there a way to achieve this without having to inherit from each element and create a custom one? It would be fantastic if domonic had a built-in htmx functions for buttons, inputs, forms, hrefs, or even divs, similar to the div.html() For example:

htmx_button = button('some action').htmx_post('/post').htmx_target('.post')
# or like so
htmx_button = button('some action')
htmx_button.set_hxpost("/post")
htmx_button.set_hxtarget(".post")

You get the point.

byteface commented 4 months ago

Hi @CRY-D ... sorry its been ages. I recall doing some kind of undocumented htmx features a long time ago.

https://github.com/byteface/domonic/blob/master/domonic/dom.py#L212

You just had to set:

DOMConfig.HTMX_ENABLED = True

But I'm not sure if htmx has changed since. It might need updating if so.

I guess if it is obsolete, for now as a work around you could monkey patch def __attributes__(self): on Node and have it check for attributes? literally copy out the attributes function and set it with your own method formatted exactly how you'd like it.

CRY-D commented 4 months ago

Thank you, and It's quite interesting, now I have an idea that doesn't require altering the source code of the library. What if I create a class that generates dynamic methods from the attributes provided by HTMX and directly applies them to the corresponding DOMONIC elements? Just like that. What do you think? I know it ain't much, but it's more friendly for my eyes πŸ˜…

from domonic import a  
from static_strings import HTMX_ATTR
class HtmxElement:
    def __init__(self, element):
        self.element = element
        for attr in HTMX_ATTR:
            htmx_attr = f"hx-{attr.replace('_', '-')}" # just to handle attrs like push_url, history_elt...
            setattr(self, attr, lambda value, htmx_attr=htmx_attr: self.element.setAttribute(htmx_attr, value))

element = a("Post", _href="/post")
htmx_element = HtmxElement(element)
htmx_element.push_url("true")
htmx_element.target("#result")
htmx_element.swap("outerHTML swap:200ms settle:200ms")
print(element)
# output: <a href="/post" hx-push-url="true" hx-target="#result" hx-swap="outerHTML swap:200ms settle:200ms">Post</a>

static_strings.py


HTMX_ATTR = [
    "boost",
    "confirm",
    "delete",
    "disable",
    "disinherit",
    "encoding",
    "ext",
    "get",
    "headers",
    "history_elt",
    "include",
    "indicator",
    "params",
    "patch",
    "post",
    "preserve",
    "prompt",
    "push_url",
    "put",
    "request",
    "select",
    "sse",
    "swap",
    "swap_oob",
    "sync",
    "target",
    "trigger",
    "vals",
    "vars",
    "ws",
]
byteface commented 4 months ago

Oh @CRY-D I see.. actual method names. push_url etc. Yes that does look like a good idea.

CRY-D commented 4 months ago

Looks promising! By the way, I'm currently developing a set of useful components, and domonic seems very promising. Thank you again.

Screenshot_20240223_230317

Screenshot_20240223_230431