jorgebucaran / hyperapp

1kB-ish JavaScript framework for building hypertext applications
MIT License
19.06k stars 781 forks source link

Multiple apps on single page #1115

Open collinglass opened 4 months ago

collinglass commented 4 months ago

Hey, I’m looking to use this to rewrite my current widget. Our customers add our JavaScript lib to the head tag. And then we inject html CTAs inside DOM elements where they put our CSS classes. Usually 3-4 CTAs per page. Clicking any of these CTAs opens up a modal with an iframe.

what is the best way to accomplish this with hyperapp?

zaceno commented 1 month ago

What is a CTA, if I may ask?

zaceno commented 1 month ago

Anyway, this doesn’t sound much like the kind of use-case hyperapp is best for. Unless you’re talking about the iframe content - but each iframe will be its own isolated page so using hyperapp in there shouldn’t be a problem

skanne commented 1 month ago

Isn't CTA spelled out "call-to-action", in other words, a button?

collinglass commented 1 month ago

Yes. In general, something that we want users to click on or do. Can be just a button, in our case, it can also be an ad-like banner or inline block

skanne commented 1 month ago

Regarding "Multiple apps on single page": It's perfectly valid/feasible to have multiple Hyperapp apps running at the same time on the same page. I personally like to have them run inside dedicated web components. This way, such mini-apps can even be nested. Think <outer-app><inner-app></inner-app></outer-app>.

I've outlined it for you here:

<script type="module">
  import { h, app } from "https://unpkg.com/hyperapp";

  const styleSheets = new CSSStyleSheet();
  styleSheets.replaceSync(`
    :host {
      /* call-to-action styles */
    }
    button {
      /* button styles */
    }
  `);

  class CallToAction extends HTMLElement {
    #dispatch;

    constructor() {
      const shadowRoot = super().attachShadow({ mode: "open" });
      shadowRoot.adoptedStyleSheets = [styleSheets];
      shadowRoot.innerHTML = "<button></button>";
    }

    connectedCallback() {
      this.#dispatch = app({
        init: {
          /* component state */
        },
        view: (state) =>
          h(
            "button",
            {
              /* button attributes */
            },
            h("slot", {})
          ),
        node: this.shadowRoot.firstChild,
      });
    }

    disconnectedCallback() {
      this.#dispatch((state) => undefined);
    }
  }

  customElements.define("call-to-action", CallToAction);
</script>

<call-to-action>CTA</call-to-action>

You can either import Hyperapp from a CDN, like import { h, text, app, memo } from "https://unpkg.com/hyperapp"; and do so in each of your app modules, or you do it once and put Hyperapp into the global scope (yes, you'd soil the window somewhat) via import * as hyperapp from "https://unpkg.com/hyperapp"; window.hyperapp = hyperapp; and then destructure from the global hyperapp object: const { h, text, app, memo } = window.hyperapp;.