bigskysoftware / idiomorph

A DOM-merging algorithm
BSD 2-Clause "Simplified" License
641 stars 32 forks source link

Ignore specified attributes or elements from morph #7

Closed owickstrom closed 7 months ago

owickstrom commented 1 year ago

Hi! Thanks for the nice library! I'm using it together with HTMX for a commercial project. Lots of fun!

I'm wondering wether idiomorph might accept a list of attributes (or entire elements) that can be excluded from the morph operation? In my case, I want to use elements such as the HTML details element inside a tree that gets morphed on a HTMX swap. But there's what I'd consider ephemeral state in the DOM, in particular the open attribute on the details element. At least Chrome writes that back to the DOM when you expand the details. When the HTMX swap happens, the attribute is removed and the user's view state is reset, essentially.

Here's a small reproduction using only idiomorph:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <title>Document</title>
  </head>
  <body>
    <script src="https://unpkg.com/idiomorph"></script>
    <div id="test">

      <details>
        <summary>Show the details</summary>
        <p>OK, here are the details.</p>
        <button id="refresh">Refresh</button>
      </details>
    </div>

    <script>
     const original = document.querySelector("#test").outerHTML;
     const refresh = document.querySelector("#refresh");

     refresh.addEventListener("click", () => {
        Idiomorph.morph(document.querySelector("#test"), original);
     });
    </script>
  </body>
</html>

Maybe the details element could have some data attribute that lists open as excluded? I can probably submit a PR if that'd be helpful.

Or I'm going about this all wrong, and maybe you have a better design pattern to suggest?

Thanks!

owickstrom commented 1 year ago

So, for now I've worked around this by passing query parameters that represent the state of these elements. It's a bit of busywork I guess, but the user experience is all right. It works for partials with a single details element, but when there are multiple, it gets cumbersome.

ADIX7 commented 9 months ago

Will this be implemented? It would be perfect for keeping lightweight client state (in my case display: none and display: block for an inline edit element). For now, I made a webcomponents for it to hide it in shadowroot, but it would be much better, if i could just prevent idiomorph the overwrite that, as the current code is quite long compared to a im-ignore-attibute or im-ignore-style.

1cg commented 7 months ago

Hello. I'm willing to look at a PR for this, but it seems like it would be difficult to do without a custom syntax that would get complicated. We could add a callback here:

https://github.com/bigskysoftware/idiomorph/blob/fdc079e22f0ef5d7420e2d98fdd8eccd8ed01a84/src/idiomorph.js#L264

and use that to allow per-attribute morphing. Would that be acceptable?

1cg commented 7 months ago

I have a proof of concept for this here:

https://github.com/bigskysoftware/idiomorph/commit/abf6c948ed60098b5471d474b5fd0c5b254b258b

Please take a look at it and let me know if it satisfies your needs. It doesn't have a large perf implication, which I like.

1cg commented 7 months ago

Supported in latest version of idiomorph (v0.2.0) in the beforeAttributeUpdated callback.