npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

funtags

v1.0.7

Published

Create DOM trees from plain vanilla javascript functions. No transpilation nor alien languages. Just a little bit trick.

Downloads

33

Readme

<FunTags :)> - Functional Tags

Create DOM trees from plain vanilla javascript functions. No transpilation nor alien languages. Just a little bit of magic with Proxy Objects.

How to Use

Option 1 - From JSDeliver

<script src="https://cdn.jsdelivr.net/gh/renato-mauro/funtags/dist/main.min.js"></script>

Option 2 - From Repository

<script src="dist/main.min.js"></script>

Option 3 - From NPM

npm install funtags

Option 4 - ObservableHQ

You can play (and use) FunTags in ObservableHQ. If you want to import in your own notebook, just import and have fun!

import { ft } from "@rmauro/funtags"

Option 5 - Copy and Paste entire library in your code

const ft = (function(){
    const HTML_NS = "http://www.w3.org/1999/xhtml";
    const SVG_NS = "http://www.w3.org/2000/svg";
    function tagFactory(NS,tagName) {
        return function(...args) {
            let element = document.createElementNS(NS,tagName);
            function flatten(e) {
                if(e !== null && e !== "") {
                    if(e.forEach) {
                        e.forEach(flatten);
                    } else {
                        if (e instanceof Node) {
                            element.append(e);
                        } else if(e instanceof Object) {
                            for(let k in e) {
                                let v = e[k];
                                if(v !== null) {
                                    let evname = (/^on(.+)$/.exec(k)||[])[1];
                                    if(evname) {
                                        element.addEventListener(evname,v);
                                    } else if(k === 'style') {
                                        for(let ks in v) {
                                            element.style[ks] = v[ks];
                                        }
                                    } else {
                                        element.setAttribute(k,v);
                                    }
                                }
                            }
                        } else {
                            element.append(document.createTextNode(e));
                            element.normalize();
                        }
                    }
                }
            }
            flatten(args);        
            return element;
        }
    }
    return {
        html: new Proxy({}, {get:(target,name)=>(name in target)?target[name]:tagFactory(HTML_NS,name)}),
        svg: new Proxy({}, {get:(target,name)=>(name in target)?target[name]:tagFactory(SVG_NS,name)})
    }
})();

How it Works (Hello World!)

function sayHello() {
    /* "desconstruct" from ft.html tags used by this template */
    const { div, h1, p } = ft.html;

    /* create dom hierarchy by composing function call */
    return div(
        h1("Hello World"),
        p("Lorem ipsum dolor sit amet, consectetur adipiscing elit."),
        p("Donec a nunc mi."),
        p("Vestibulum at felis tempus, suscipit nisi in, semper nisl.")
    );
}

Here we have a function to generate our DOM fragment. As we are going to use tags like div, h1, and p, we have to desconstruct them from the magic object ft.html. They are functions that create DOM elements with the same variable name.

The object ft.html is indeed a Proxy object. Any X property that is requested will be returned as a factory for creating an element of type X, regardless of whether X is a known element type or a custom element.

The value returned from tag factories is a regular DOM tree so that they can be inserted into documents as usual. In this example, we replaced the content of body element with replaceChildren method.

document.body.replaceChildren(sayHello());

See live code in code pen.

More Examples

List of Objects

function fruitList(fruits) {
    /* "desconstruct" from ftags.html tags used by this template */
    const { div, h1, ul, li } = ft.html;

    /* create dom hierarchy by composing function call */
    return div(
        h1("Fruit List"),
        ul(
          ...fruits.map(fruit => li(fruit))
        )
    );
}

document.body.replaceChildren(fruitList(["apple","orange","lemon"]));

In this example we are using array map method with spread operator (...). Each element in array is passed as argument to function.

See live code in code pen.

Attributes and Events

function nameList() {
    const { div, h1, ul, li, input, button } = ft.html;
    let names = [];

    function addName() {
      names.push(nameInput.value);
      nameList.replaceChildren(...names.map(name=>li(name)));
      nameInput.value = "";
      nameInput.focus();
    }
  
    let nameList = ul();
    let nameInput = input({type:"text",placeholder:"new name"});
    let addButton = button({onclick:addName},"add");
  
    return div(
        h1("Name List"),
        div(nameInput, addButton),
        div(nameList)
    );
}

document.body.replaceChildren(nameList());

Attributes are defined as javascript objects. The line

input({type:"text",placeholder:"new name"})

will produce

<input type="text" placeholder="new name">

Attributes starting with the prefix "on" is treated as event handlers.

button({onclick:addName},"add");

will produce

<button>add</button>

with click event handler registered to function addName.

See live code in code pen.

Table with async data

Function userTable creates a HTML table for an array of user objects.

function userTable(data) {
    const { table, thead, tbody, tr, th, td } = ft.html;

    return table(
      thead(
        tr(
          th("#"),th("First Name"),th("Last Name"),th("Gender"),th("Email"),th("Birth Date")
        )
      ),
      tbody(
        ...data.map(d=>tr(
          td(d.id),
          td(d.firstName),
          td(d.lastName),
          td(d.gender),
          td(d.email),
          td(d.birthDate)
        ))
      )
    );
}

Function page bellow creates a HTML fragment with a title and a placeHolder, initially with "loading..." message. An API request is done by fetch function and once fullfilled the request, placeHolder content is replaced by data table.

function page() {
  const { div, h1, p } = ft.html;  
  let placeHolder = div(p("Loading..."));
  
  fetch("https://dummyjson.com/users")
    .then(response=>response.json())
    .then(data=>{placeHolder.replaceChildren(userTable(data.users))})
  ;
  
  return div(
    h1("User Data"),
    placeHolder
  );
}

document.body.replaceChildren(page());

See live code in code pen.