Skip to content
This repository has been archived by the owner on Feb 16, 2021. It is now read-only.

HAST and lit-html #4

Closed
Hypercubed opened this issue Oct 27, 2018 · 6 comments
Closed

HAST and lit-html #4

Hypercubed opened this issue Oct 27, 2018 · 6 comments
Labels
🧘 status/waiting This may go somewhere but needs more information

Comments

@Hypercubed
Copy link

Hypercubed commented Oct 27, 2018

I've been thinking about how HAST can work with https://github.com/Polymer/lit-html . Some potential ideas:

  • Converting the HAST to a lit-html template could allow us to use the lit-html's efficiently rendering?
  • Maybe using plugins to add directives and event binding? Some experimental examples are below. I'm debating if this is any more useful than just writing custom elements.

Add a click event tolis:

export const click = () => {
  return (tree: UNIST.Node, vfile: VFile) => {
    
    visit(tree, ['element'], (node: MDAST.Link, index, parent) => {
      if (node.tagName === 'li') {
        const n = {
          type: LIT_TYPE,
          template: c => html`<li @click="${onClick}">${c}</li>`, // children are added back later
          children: node.children
        };

        parent.children.splice(index, 1, n);
        return true; 
      }
    });
  };

  function onClick(e) {
    e.stopPropagation();
    this.classList.toggle('hidden')
  }
};

Convert an elements to a timed counter:

export const clock = () => {
  const wait = (t) => new Promise((resolve) => setTimeout(resolve, t));

  async function* countUp() {
    let i = 0;
    while (true) {
      yield i++;
      await wait(1000);
    }
  }

  return (tree: UNIST.Node, vfile: VFile) => {
    visit(tree, ['element'], (node: MDAST.Link, index, parent) => {
      if (node.tagName === 'strong') {
        const n = {
          type: LIT_TYPE,
          template: c => html`<span>Count: ${asyncReplace(countUp())}</span>`,
          children: node.children
        };

        parent.children.splice(index, 1, n);
        return true; 
      }
    });
  };
};
@wooorm
Copy link
Member

wooorm commented Oct 28, 2018

@Hypercubed Hmmm, interesting! I never had a need to use lit-html, but have always found it interesting.

Now: what is the main use case to use HAST with it? Wouldn’t HAST be too big in the browser? Can’t lit-html itself do pluggable stuff like this already?

@Hypercubed
Copy link
Author

Hypercubed commented Oct 28, 2018

@wooorm It's a great question, one I'm still thinking about myself. Here are my thoughts. (I'm somewhat new to each so... FWIW).

I think rehype and lit-HTML are tangental:

rehype (and unified, remark, etc) consists of a series of static conversions. The content is always static and can be done as part of a prerender step outside the browser.

lit-html is dynamic. It generates an HTML template (and eventually DOM) that is aware of the parts of the template that are dynamic. This allows for efficient updates of only the dynamic portions. There is no concept of plugins.

Here is my contrived example. Consider this markdown:

# Title

## Table of Contents

[[toc]]

## Current Time

[[current-time]]

Now, the [[toc]] smart code can be converted to a TOC using a remark plugin. But if we wanted the nested list to be collapsable we would need to write some JS that would find and add click event listeners to each li after rendering.

For the [[current-time]] smart code we would need to write a plugin that converts this to a custom element that would likely use lit-html inside. The plugin would need to be added to the processor and the custom element would need to be registered in the browser. Again making this a two-step process.

For each of these I'm thinking if we could write a unified plugin that eats the MDAST or HAST and returns a lit-html template. This templates can have event listeners attached and dynamic content embedded (see my examples in the first post). They would be fully contained within the plugin and immediately renderable using lit-html's render method.

At the end of the day, I'm not sure if this approach is any better than using straight unified plugins and custom elements. That's why I'm here soliciting thoughts.

(P.S. Here is my experimentation so far: https://stackblitz.com/edit/typescript-naqxbo)

@wooorm
Copy link
Member

wooorm commented Nov 10, 2018

I think this all looks amazing and makes a lot of sense!

At the end of the day, I'm not sure if this approach is any better than using straight unified plugins and custom elements.

How would that look? Maybe both have a reason to exist?

@Hypercubed
Copy link
Author

Hypercubed commented Nov 10, 2018

No reason they can't both exists... in fact the unified plugins and custom elements approach works already. I see three options to use lit-html in unified:

  1. Using allowDangerousHTML and rehype-raw simply include a predefined custom element.
  2. Write a plugin that outputs a custom element that is later rendered in DOM, also requires a predefined custom element.
  3. What I am discussing above, writing a plugin that returns a lit-html render function with no need to define a custom element.

You can see all three here: https://stackblitz.com/edit/typescript-xewcch

Option #3 can get really interesting combined with what @matthewp is doing here: matthewp/haunted#31 !

@wooorm
Copy link
Member

wooorm commented Nov 19, 2018

Anything we can do on the HAST side?

@wooorm wooorm added the 🧘 status/waiting This may go somewhere but needs more information label Aug 13, 2019
@ChristianMurphy
Copy link
Member

Thanks for starting the discussion @Hypercubed!
We're in the process unifying ideas in with discussions unifiedjs/collective#44
If you'd like to continue this thread, or start a new one https://github.com/rehypejs/rehype/discussions/categories/ideas will be the home for ideas going forward.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🧘 status/waiting This may go somewhere but needs more information
Development

No branches or pull requests

3 participants