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

htmf

v1.0.8

Published

Hypertext Markup Function. Express HTML/DOM trees using native javascript.

Downloads

4

Readme

HTMF

HTMF (Hypertext Markup Function) is a method for constructing HTML or DOM trees using native javascript. It looks something like this:

import { toString } from 'htmf';

toString($ => { $
  .a('html')
    .b('head')
    .b('body')
      .c('h1').text('Hello World')
      .c('span').text('HTMF can express:')
      .c('ul')
        .d('li .first').text('classes')
        .d('li #second').text('ids')
        .d('li')
          .e('a', {href: 'google.com'}).text('and attributes')
})

which creates

<html>
  <head></head>
  <body>
    <h1>Hello World</h1>
    <span>HTMF can express:</span>
    <ul>
      <li class="first">classes</li>
      <li id="second">ids</li>
      <li>
        <a href="google.com">and attributes</a>
      </li>
    </ul>
  </body>
</html>

HTMF has different implementations for different frameworks and environments:

|Framework|Module| |---|---| | Vue | brue | | React | htmf-react |

This module is intended to be used as a starting step for an implentation that will add features and/or tie into a framework.

How it works

HTMF accepts a function that it will pass a "builder" ($). The builder has the functions a through z which can be used to create a node. The node's place in the tree is expressed by the letter used. b nodes are children of the last a node, etc. This is made more clear by properly indenting the nodes. Every builder method returns itself, which allows the chaining of calls.

Nodes accept any number of arguments, and string arguments separated by spaces are treated as separate arguments:

  • Strings with no prefix indicate the element type
  • Strings with . prefix indicate a class
  • Strings with # prefix indicate the id
  • Objects that are not the first argument indicate attributes

And in special cases:

  • Functions indicate the element type (imagine a component class in React) note - this now works with included toString() method as well
  • Objects placed as the first argument indicate the element type (a Vue component for instance)

So the following two builds are equivalent:

$.a('div')
  .b('div .someclass .green #id', {onclick: 'script', title: 'tooltip'})
$.a('div')
  .b('div', '.someclass','.green','#id', {onclick: 'script'}, {title: 'tooltip'})

which creates:

<div>
  <div class="someclass green" id="id" onclick="script" title="tooltip"></div>
</div>

Node modifiers

Node modifers are other functions of the builder besides a through z. They will always modify the last designated node. The core HTMF module only has the .text() node modifier.

Text nodes

Expressing text nodes (no element) can be done in a number of ways:

$.a('div').text('some text')
$.a('div')
  .b().text('some text')
$.a('div')
  .b(String, 'some text')

All equivalent. As you can see, passing the global String constructor as the first argument of a node will break from the normal parsing of node arguments and create a text node using the second argument.

Single node shorthand

Passing an array instead of a function to an HTMF implementation is an easy way to create a single node. The second argument can be used to add a text node:

Mf.toString(['a .someclass',{href: 'google.com'}], 'A link to google')

will create <a href="google.com">A link to google</a>

Api

.process(buildFunction, nodeModifiersObject:optional, ...furtherArgs)

HTMF.process() is intended to be used by other HTMF implementations. It returns an array of the root nodes of a tree created by the buildFunction. Any futher arguments will be passed to the build function, An example of the node structure:

{
  element: 'div',
  classes: ['link','green'],
  attributes: {id: 'greenlink'},
  children: []
}
//or a text node:
{
  element: null,
  classes: [],
  attributes: {},
  children: [],
  text: 'some text'
}

An example showing a node modifiers object:

import { process } from HTMF;

const api = {
  click: (node, func) => {
    node.attributes.onClick = func;
  },
  hide: node => {
    node.attributes.style = "display: none;"
  }
}
const roots = process($ => { $
  $.a('div')
    .b('div .hidden').hide()
    .b('div .button').click(() => { console.log('clicked!') }) 
}, api);

.toString(buildFunction)

An implenetation of HTMF using .process(). It returns an html string created with the buildFunction. Besides just simple HTML elements, it can handle "component functions" as well (similiar to react)

Here's an example:

let innerComponent = params => {
  let timesTwo = params.value * 2;
  return $ => { $
    .a('div .inner')
      .b('p').text(`twice the value: ${timesTwo}`)
  }
}

let outterComponent = params => {
  return $ => { $
    .a('div .outer')
      .b(innerComponent, {value: params.count})
      .b('div').text('after')
  }
}

toString(outterComponent({count: 2}));

would create

<div class="outer">
  <div class="inner">
    <p>twice the value: 4</p>
  </div>
  <div>after</div>
</div>