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

skatejs-dom-diff

v1.0.1

Published

Library for efficiently diffing and patching DOM fragments.

Downloads

134

Readme

Dom Diff

Skate's DOM Diff is a virtual DOM library for diffing, patching and converting between virtual and real DOM trees.

Sauce Test Status

  • Serialise to and from read DOM trees
  • Diff virtual trees and patch real trees
  • Web worker support
npm install skatejs-dom-diff

Usage

Where options are accepted, you may provide:

  • done If specified, diffing is performed in a web worker and this callback is called when it's done.

diff(source, target, options)

Diffs two virtual trees.

/** @jsx h **/
import { diff, h } from 'skatejs-dom-diff';

const source = <div><span>source</span></div>;
const target = <div><span>target</span></div>;
const instructions = diff(source, target);

The patchInstructions is an array that can be passed to patch() to update the source tree. Before passing the instructions to patch(), however, your source tree must be associated to real DOM nodes. This can be done by using mount() or by converting them to a tree using toDom().

fragment([virtualNodeOrNodes])

Creates a virtual fragment. You can pass nothing to create an empty fragment:

import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment();

A single virtual node:

import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment(<div />);

An array of virtual nodes:

import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment([<div />, <span />]);

Or even a virtual fragment:

import { fragment } from 'skatejs-dom-diff';

const vFrag = fragment(fragment(<div />));

h(name, props, ...childrenOrText)

Creates a virtual node.

// <div class="my-class">text or...<span /></div>
h('div', { className: 'my-class' }, 'text or...', h('span'));

Or you could just use JSX:

/** @jsx h **/
// <div class="my-class">text or...<span /></div>
<div className="my-class">text or...<span /></div>

Attributes

By default, h only sets properties, but you can specify attributes you want to set by passing the special attributes prop:

// <div class="my-class" />
<div attributes={{ class: 'my-class' }} />

Aria attributes

You can pass aria-* attributes using attributes but you can also specify the aria prop:

// <div aria-label="my label" />
<div aria={{ label: 'my label' }} />

Data attributes

Like the aria prop, you can also use the data prop:

// <div data-something="my data" />
<div data={{ something: 'my data' }} />

Events

Events are bound using the special events prop:

const click = e => doSomethingWith(e);
<div events={{ click }} />

merge()

The merge() function is convenience for calling diff() and patch() sequentially. As with diff(), you must ensure the source virtual tree has been associated to real nodes first.

/** @jsx h **/
import { diff, h } from 'skatejs-dom-diff';

const source = <div><span>source</span></div>;
const target = <div><span>target</span></div>;
const dom = mount(source);
merge(source, target);

mount(vdom[, root])

Mounts the vdom to the real root DOM node. It returns the root node. If the root node was not specified, it automatically creates a <div /> and returns it.

/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

const div = mount(<p>some text</p>);

Is the same thing as:

/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

const div = document.createElement('div');
mount(<p>some text</p>, div);

It's more than likely that you'll just mount it directly to the document:

/** @jsx h **/
import { h, mount } from 'skatejs-dom-diff';

mount(<p>some text</p>, document.getElementById('app'));

patch()

Takes instructiosn created using diff() and performs them on the associated DOM nodes that each instructions is for.

/** @jsx h **/
import { diff, h, mount, patch } from 'skatejs-dom-diff';

const source = <p>source tree</p>;
const target = <p>target tree</p>;
const instructions = diff(source, target);

mount(source, document.getElementById('app'));
patch(instructions);

render()

A highly convenient function for continually rendering a given template.

/** @jsx h **/
import { h, render } from 'skatejs-dom-diff';

const root = document.getElementById('app');
const renderer = render((root) => (
  <p>{root.someProp}</p>
));

// Set the prop to render with
root.someProp = 'test 1';

// Initial render: <p>test 1</p>
renderer(root);

// Update the prop
root.someProp = 'test 2';

// Re-render: <p>test 2</p>
renderer(root);

text()

Returns a virtual text node:

import { text } from 'skatejs-dom-diff';

const vText = text('my text node');

toDom()

Convers a virtual tree to a real DOM tree, event listeners and all:

import { toDom } from 'skatejs-dom-diff';

const vdom = <p>I will soon be real!</p>
const dom = toDom(vdom);

// <p>I will soon be real!</p>
console.log(dom.outerHTML);

toVdom()

Converts a real DOM tree into a virtual tree. It only copies over attributes. Event listeners can't be copied because the standard DOM APIs don't provide a way to get bound listeners.

Properties currently aren't copied either, but is being worked on.

import { toVdom } from 'skatejs-dom-diff';

const dom = document.createElement('p');
dom.textContent = 'I will soon be fake!';

const vdom = toVdom(dom);

types

The types of patches that can occur. Currently these are:

import { types } from 'skatejs-dom-diff';

const {
  APPEND_CHILD,
  REMOVE_CHILD,
  REMOVE_ATTRIBUTE,
  REPLACE_CHILD,
  SET_ATTRIBUTE,
  SET_EVENT,
  SET_PROPERTY,
  TEXT_CONTENT
} = types;

Web workers

You can tell the differ to do its work in a web worker simply by passing a done callback option to any of the three major entry functions (diff(), merge(), render()).

diff(source, target, options)

In the case of diff(), it's called once the diffing algorithm has finished in the worker and passed the instructions. The patch instructions are the only argument passed into the callback.

/** @jsx h */
import { h, diff } from 'skatejs-dom-diff';

function done (instructions) {
  patch(instructions);
}
diff(<p>source</p>, <p>target</p>, { done });

merge(source, target, options)

For done(), it's passed in the same exact way. The only difference is that it's called after the patch is performed but it's still passed the instructions that were performed by the patch algorithm.

/** @jsx h */
import { h, merge } from 'skatejs-dom-diff';

function done (instructions) {
  // The DOM has been updated, do what you want here.
}
merge(<p>source</p>, <p>target</p>, { done });

render(source, target, options)

And for render(), it is the same as the merge() function. So once the vDOM is rendered and DOM is patched, done() is called with the instructions that were performed.

import { h, render } from 'skatejs-dom-diff';

function done (instructions) {
  // Renering and patching is done...
}
const root = document.createElement('div');
const doRender = render((root) => (
  <div>{root.test}</div>
));

div.test = 'initial text';
doRender(div, done);

div.test = 'updated text';
doRender(div, done);