New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

funtags

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

funtags

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

latest
Source
npmnpm
Version
1.0.7
Version published
Maintainers
1
Created
Source

<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.

Keywords

dom

FAQs

Package last updated on 02 Aug 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts