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

hypnode

v1.3.1

Published

A super fast, lightweight (roughly **1kb** gzipped) and reactive series of utility functions, used to build HTML node trees and stateful functional components. Can be used either directly via the `h` function, or from transpiled `JSX`.

Downloads

22

Readme

A super fast, lightweight (roughly 1kb gzipped) and reactive series of utility functions, used to build HTML node trees and stateful functional components. Can be used either directly via the h function, or from transpiled JSX.

Due to it's size, hypnode is a useful companion utility for writing WebComponents, simplifying HTML structures, element references and state management. See section entitled "WebComponents" for an example, click to jump there.

Getting Started

To install hypnode, you can use one of the following in your project:

yarn add hypnode or npm install hypnode

hypode can be used in one of two ways, either as a target for JSX transpilation, or directly using the exposed h function. It's exported as ES6, so if you need to support older environments, you'll need to transpile down to ES5 in your build tasks.

The h function can be imported in one of the following ways:

import { h } from 'hypnode';
const { h } = require('hypnode');

Direct Usage

Once imported, use the function to generate your tree of DOM Nodes. The function takes 3 arguments, the last two of which are optional:

h([type]: string | Function, [attributes]?: object, [children]?: array[]);

Simple Example

The code below:

import { h, render } from 'hypnode';

/*[...]*/

const result = render(
  h('div', { title: 'A DIV!' }, [
    h('h1', { class: 'title' }, 'Hypnode'),
    h('p', { id: 'text'}, 'My text value'),
  )
);

console.log(result.outerHTML);

Will produce the following:

<div title="A DIV!">
  <h1 class="title">Hypnode</h1>
  <p id="text">My text value</p>
</div>

JSX Elements

hypnode can be used with JSX to provide a more familiar API when building DOM structures. This will need a transpilation step, see below for examples.

TypeScript

Transpilation of JSX is provided out of the box by custom factories (TypeScript 1.8+), to apply this, add the following to your tsconfig.json file:

"compilerOptions": {
   "jsx": "react",
   "jsxFactory": "h",
   /*[...]*/
}

This tells the TypeScript compiler to convert all JSX elements into function calls, in this case using our exported h function. You'll still need to import the h function in every file where you're using JSX.

To apply the correct types, all files that contain JSX must have the extension .tsx.

Simple Example

The code below:

import { h, render } from 'hypnode';

/*[...]*/

const root = document.getElementId('root');

const result = render(
  <div class="wrapper">
    <a id="link" onClick={(ev = console.log(ev))}>
      Click here
    </a>
  </div>
);

root.appendChild(result);

Will produce the following:

<div class="wrapper">
  <a id="link">
    Click here
  </a>
</div>

Rendering

As the render() function exported by hypnode returns a fully formed HTMLElement, you can handle it's output easily using native DOM API's like root.appendChild or root.replaceChild. There is, however, an optional secondary argument that can handle this for you, e.g:

const result = h('div', { class: 'wrapper' }, 'Lorem ipsum');

/*[...]*/

render(result, document.getElementById('root'));

or, with JSX:

const result = <div class="wrapper">Lorem ipsum</div>;

/*[...]*/

render(result, document.getElementById('root'));

Event Binding

hypnode provides a set of properties for you to apply DOM events. All native events are supported, formatted in camelCase and prefixed with on. For example:

h('a', { onClick: (ev) => console.log(ev) }, 'Click Here');

or, with JSX:

<input onKeyUp={(ev) => console.log(ev)} />

Element References

If you need access to a particular node in your tree, use the ref property. For example:

let myElement;

/*[...]*/

h('div', { id: 'container' }, [
  h('p', { ref: (el) => (myElement = el) }, 'Lorem ipsum dolor sit amet, consectetur'),
]);

or with JSX:

let myElement;

/*[...]*/

<div class="wrapper">
  <a href="//link.co" ref={(el) => (myElement = el)}>
    Click here
  </a>
</div>;

Components

hypnode can be used to create re-usable, functional components, below is a simple example:

import { h, render } from 'hypnode';

/*[...]*/

function Button({ className = '', children }) {
  return h('a', { class: `button ${className}` }, children);
}

/*[...]*/

const button = h(Button, { className: 'big' }, buttonText));

render(button, document.getElementById('root'))

or with JSX:

import { h, render } from 'hypnode';

/*[...]*/

function Button({ className = '', children }) {
  return <a class={`button ${className}`}>{children}</a>;
}

/*[...]*/

const button = <Button className="big">Click here</Button>;

render(button, document.getElementById('root'));

WebComponents

Creating and managing complex HTML structures using WebComponents can become tricky as their size increases. hypnode simplifies this by incorporating a familiar component and state pattern into your custom elements. You can find more info on WebComponents here. As hypnode is fast and lightweight, WebComponents can be more easily shared between projects without significant dependency overhead.

A quick example can be found below:

// myComponent.tsx (TypeScript + JSX)

import { h, render, useState, State } from  'hypnode';

/*[...]*/

class MyComponent extends HTMLElement {
  private state: State<number>;

  public connectedCallback() {
    const Button = () => this.renderButton();

    this.appendChild(render(<Button  />));
  }

  private  renderButton = () => {
    const [counter] = (this.state =  useState(0));

    return (
      <div class="my-component">
        <p>Counter: {counter}</p>
        <button onClick={this.onClick}>Click Here</button>
      </div>
    );
  }

  private onClick = (ev: Event) => {
    const [counter, setState] = this.state;

    setState(counter + 1);
  }
}

State

hypnode exposes a simple, declarative hook to provide state into your functional application.

First, you'll need to import the hook function:

import { h, useState } from 'hypnode';

Once imported, you can initialize a state registry in your components by doing the following:

const [state, setState] = useState(([value]: any));

The useState function takes a single argument, the initial value you wish to assign to the state. This can be anything, a primitive or something more complex like an object. For example:

function Button({ buttonText }) {
  const [state, setState] = useState(10);

  return h('button', { onClick: () => setState(state + 1) }, `${buttonText}: ${state}`);
}

You provide mutations to your state via the setState function, this accepts a new value you wish to assign. Whenever this function is called, the component will be re-rendered with the replaced state value.

Effects

hypnode exports a simple effect hook, useEffect. This takes a callback as it's only argument which will be called on "mount". You can optionally return another function from it that will be called on "un-mount". The lifecycle of this function works in a similar way to React's hook by the same name.

See example below:

import { h, useEffect } from 'hypnode';

/*[...]*/

function Banner({ children }) {
  useEffect(() => {
    console.log('onMount');

    return () => console.log('onUnMount (optional)');
  });

  return h('div', { class: 'banner' }, children);
}

Server Side Rendering

hypnode provides a Virtual DOM representation for server side rendering (universal rendering). You can use this output to generate a complete HTML representation of your app. A prebuilt utility that can convert this into an HTML string can be found here: hypnode-server

TypeScript

This utility was created with TypeScript and comes pre-bundled with a definition file.