Socket
Socket
Sign inDemoInstall

@thi.ng/hdom

Package Overview
Dependencies
6
Maintainers
1
Versions
263
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.35 to 4.0.0

32

api.d.ts

@@ -16,2 +16,34 @@ import { IObjectOf } from "@thi.ng/api/api";

}
export interface HDOMOpts {
/**
* Root element or ID (default: "app").
*/
root: Element | string;
/**
* Arbitrary user context object, passed to all component functions
* embedded in the tree.
*/
ctx?: any;
/**
* If true (default), text content will be wrapped in `<span>`
*/
span?: boolean;
/**
* If true (default false), the first frame will only be used to
* inject event listeners.
*
* *Important:* Enabling this option assumes that an equivalent DOM
* (minus listeners) already exists (i.e. generated via SSR) when
* hdom's `start()` function is called. Any other discrepancies
* between the pre-existing DOM and the hdom trees will cause
* undefined behavior.
*/
hydrate?: boolean;
/**
* If true (default), the hdom component tree will be first
* normalized before diffing (using `normalizeTree()`). Unless you
* know what you're doing, it's best to leave this enabled.
*/
normalize?: boolean;
}
export declare const DEBUG: boolean;

@@ -6,2 +6,19 @@ # Change Log

<a name="4.0.0"></a>
# [4.0.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom@3.0.35...@thi.ng/hdom@4.0.0) (2018-08-31)
### Features
* **hdom:** add DOM hydration support (SSR), update start() ([#39](https://github.com/thi-ng/umbrella/issues/39)) ([9f8010d](https://github.com/thi-ng/umbrella/commit/9f8010d))
* **hdom:** update HDOMOpts & start() ([5e74a9c](https://github.com/thi-ng/umbrella/commit/5e74a9c))
### BREAKING CHANGES
* **hdom:** start() args now as options object
<a name="3.0.35"></a>

@@ -8,0 +25,0 @@ ## [3.0.35](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom@3.0.34...@thi.ng/hdom@3.0.35) (2018-08-27)

2

diff.d.ts

@@ -20,2 +20,2 @@ /**

*/
export declare function diffElement(root: Element, prev: any, curr: any): void;
export declare const diffElement: (root: Element, prev: any, curr: any) => void;

@@ -31,7 +31,4 @@ "use strict";

*/
function diffElement(root, prev, curr) {
_diffElement(root, prev, curr, 0);
}
exports.diffElement = diffElement;
function _diffElement(parent, prev, curr, child) {
exports.diffElement = (root, prev, curr) => _diffElement(root, prev, curr, 0);
const _diffElement = (parent, prev, curr, child) => {
const delta = array_1.diffArray(prev, curr, equiv_1.equiv, true);

@@ -111,4 +108,4 @@ if (delta.distance === 0) {

}
}
function releaseDeep(tag) {
};
const releaseDeep = (tag) => {
if (isArray(tag)) {

@@ -124,4 +121,4 @@ if (tag.__release) {

}
}
function diffAttributes(el, prev, curr) {
};
const diffAttributes = (el, prev, curr) => {
let i, e, edits;

@@ -156,4 +153,4 @@ const delta = object_1.diffObject(prev, curr);

}
}
function extractEquivElements(edits) {
};
const extractEquivElements = (edits) => {
let k, v, e, ek;

@@ -171,2 +168,2 @@ const equiv = {};

return equiv;
}
};

@@ -14,8 +14,21 @@ /**

*/
export declare function createDOM(parent: Element, tag: any, insert?: number): any;
export declare function createElement(parent: Element, tag: string, attribs?: any, insert?: number): HTMLElement | SVGElement;
export declare function createTextElement(parent: Element, content: string, insert?: number): Text;
export declare function cloneWithNewAttribs(el: Element, attribs: any): Element;
export declare function setAttribs(el: Element, attribs: any): Element;
export declare const createDOM: (parent: Element, tag: any, insert?: number) => any;
/**
* Takes a DOM root element and normalized hdom tree, then walks tree
* and initializes any event listeners and components with lifecycle
* `init` methods. Assumes that an equivalent DOM (minus listeners)
* already exists (e.g. generated via SSR) when called. Any other
* discrepancies between the pre-existing DOM and the hdom tree will
* cause undefined behavior.
*
* @param parent
* @param tree
* @param i
*/
export declare const hydrateDOM: (parent: Element, tree: any, i?: number) => any;
export declare const createElement: (parent: Element, tag: string, attribs?: any, insert?: number) => HTMLElement | SVGElement;
export declare const createTextElement: (parent: Element, content: string, insert?: number) => Text;
export declare const cloneWithNewAttribs: (el: Element, attribs: any) => Element;
export declare const setAttribs: (el: Element, attribs: any) => Element;
/**
* Sets a single attribute on given element. If attrib name is NOT

@@ -41,7 +54,7 @@ * an event name and its value is a function, it is called with

*/
export declare function setAttrib(el: Element, id: string, val: any, attribs?: any): Element;
export declare function updateValueAttrib(el: HTMLInputElement, v: any): void;
export declare function removeAttribs(el: Element, attribs: string[], prev: any): void;
export declare function setStyle(el: Element, styles: any): Element;
export declare function clearDOM(el: Element): void;
export declare function removeChild(parent: Element, childIdx: number): void;
export declare const setAttrib: (el: Element, id: string, val: any, attribs?: any) => Element;
export declare const updateValueAttrib: (el: HTMLInputElement, v: any) => void;
export declare const removeAttribs: (el: Element, attribs: string[], prev: any) => void;
export declare const setStyle: (el: Element, styles: any) => Element;
export declare const clearDOM: (el: Element) => string;
export declare const removeChild: (parent: Element, childIdx: number) => void;

@@ -26,9 +26,9 @@ "use strict";

*/
function createDOM(parent, tag, insert) {
exports.createDOM = (parent, tag, insert) => {
if (isArray(tag)) {
const t = tag[0];
if (isFunction(t)) {
return createDOM(parent, t.apply(null, tag.slice(1)));
return exports.createDOM(parent, t.apply(null, tag.slice(1)));
}
const el = createElement(parent, t, tag[1], insert);
const el = exports.createElement(parent, t, tag[1], insert);
if (tag.__init) {

@@ -40,3 +40,3 @@ tag.__init.apply(tag.__this, [el, ...tag.__args]);

for (let i = 2; i < n; i++) {
createDOM(el, tag[i]);
exports.createDOM(el, tag[i]);
}

@@ -49,3 +49,3 @@ }

for (let t of tag) {
res.push(createDOM(parent, t));
res.push(exports.createDOM(parent, t));
}

@@ -57,6 +57,43 @@ return res;

}
return createTextElement(parent, tag);
}
exports.createDOM = createDOM;
function createElement(parent, tag, attribs, insert) {
return exports.createTextElement(parent, tag);
};
/**
* Takes a DOM root element and normalized hdom tree, then walks tree
* and initializes any event listeners and components with lifecycle
* `init` methods. Assumes that an equivalent DOM (minus listeners)
* already exists (e.g. generated via SSR) when called. Any other
* discrepancies between the pre-existing DOM and the hdom tree will
* cause undefined behavior.
*
* @param parent
* @param tree
* @param i
*/
exports.hydrateDOM = (parent, tree, i = 0) => {
if (isArray(tree)) {
const el = parent.children[i];
if (isFunction(tree[0])) {
return exports.hydrateDOM(parent, tree[0].apply(null, tree.slice(1)), i);
}
if (tree.__init) {
tree.__init.apply(tree.__this, [el, ...tree.__args]);
}
const attr = tree[1];
for (let a in attr) {
if (a.indexOf("on") === 0) {
el.addEventListener(a.substr(2), attr[a]);
}
}
for (let n = tree.length, i = 2; i < n; i++) {
exports.hydrateDOM(el, tree[i], i - 2);
}
}
else if (!isString(tree) && isIterable(tree)) {
for (let t of tree) {
exports.hydrateDOM(parent, t, i);
i++;
}
}
};
exports.createElement = (parent, tag, attribs, insert) => {
const el = api_1.SVG_TAGS[tag] ?

@@ -74,8 +111,7 @@ document.createElementNS(api_1.SVG_NS, tag) :

if (attribs) {
setAttribs(el, attribs);
exports.setAttribs(el, attribs);
}
return el;
}
exports.createElement = createElement;
function createTextElement(parent, content, insert) {
};
exports.createTextElement = (parent, content, insert) => {
const el = document.createTextNode(content);

@@ -91,18 +127,15 @@ if (parent) {

return el;
}
exports.createTextElement = createTextElement;
function cloneWithNewAttribs(el, attribs) {
};
exports.cloneWithNewAttribs = (el, attribs) => {
const res = el.cloneNode(true);
setAttribs(res, attribs);
exports.setAttribs(res, attribs);
el.parentNode.replaceChild(res, el);
return res;
}
exports.cloneWithNewAttribs = cloneWithNewAttribs;
function setAttribs(el, attribs) {
};
exports.setAttribs = (el, attribs) => {
for (let k in attribs) {
setAttrib(el, k, attribs[k], attribs);
exports.setAttrib(el, k, attribs[k], attribs);
}
return el;
}
exports.setAttribs = setAttribs;
};
/**

@@ -129,3 +162,3 @@ * Sets a single attribute on given element. If attrib name is NOT

*/
function setAttrib(el, id, val, attribs) {
exports.setAttrib = (el, id, val, attribs) => {
const isListener = id.indexOf("on") === 0;

@@ -138,6 +171,6 @@ if (!isListener && isFunction(val)) {

case "style":
setStyle(el, val);
exports.setStyle(el, val);
break;
case "value":
updateValueAttrib(el, val);
exports.updateValueAttrib(el, val);
break;

@@ -161,5 +194,4 @@ case "checked":

return el;
}
exports.setAttrib = setAttrib;
function updateValueAttrib(el, v) {
};
exports.updateValueAttrib = (el, v) => {
switch (el.type) {

@@ -182,5 +214,4 @@ case "text":

}
}
exports.updateValueAttrib = updateValueAttrib;
function removeAttribs(el, attribs, prev) {
};
exports.removeAttribs = (el, attribs, prev) => {
for (let i = attribs.length; --i >= 0;) {

@@ -195,14 +226,6 @@ const a = attribs[i];

}
}
exports.removeAttribs = removeAttribs;
function setStyle(el, styles) {
el.setAttribute("style", css_1.css(styles));
return el;
}
exports.setStyle = setStyle;
function clearDOM(el) {
el.innerHTML = "";
}
exports.clearDOM = clearDOM;
function removeChild(parent, childIdx) {
};
exports.setStyle = (el, styles) => (el.setAttribute("style", css_1.css(styles)), el);
exports.clearDOM = (el) => el.innerHTML = "";
exports.removeChild = (parent, childIdx) => {
const n = parent.children[childIdx];

@@ -212,3 +235,2 @@ if (n !== undefined) {

}
}
exports.removeChild = removeChild;
};

@@ -25,3 +25,3 @@ /**

*/
export declare function normalizeElement(spec: any[], keys: boolean): any[];
export declare const normalizeElement: (spec: any[], keys: boolean) => any[];
/**

@@ -68,2 +68,2 @@ * Calling this function is a prerequisite before passing a component

*/
export declare function normalizeTree(tree: any, ctx?: any, path?: number[], keys?: boolean, span?: boolean): any;
export declare const normalizeTree: (tree: any, ctx?: any, path?: number[], keys?: boolean, span?: boolean) => any;

@@ -41,3 +41,3 @@ "use strict";

*/
function normalizeElement(spec, keys) {
exports.normalizeElement = (spec, keys) => {
let tag = spec[0], hasAttribs = isPlainObject(spec[1]), match, id, clazz, attribs;

@@ -67,8 +67,2 @@ if (!isString(tag) || !(match = api_1.TAG_REGEXP.exec(tag))) {

return [match[1], attribs, ...spec.slice(hasAttribs ? 2 : 1)];
}
exports.normalizeElement = normalizeElement;
const NO_SPANS = {
option: 1,
text: 1,
textarea: 1,
};

@@ -116,3 +110,3 @@ /**

*/
function normalizeTree(tree, ctx, path = [0], keys = true, span = true) {
exports.normalizeTree = (tree, ctx, path = [0], keys = true, span = true) => {
if (tree == null) {

@@ -130,3 +124,3 @@ return;

if (isFunction(tag)) {
return normalizeTree(tag.apply(null, [ctx, ...tree.slice(1)]), ctx, path, keys, span);
return exports.normalizeTree(tag.apply(null, [ctx, ...tree.slice(1)]), ctx, path, keys, span);
}

@@ -137,3 +131,3 @@ // component object w/ life cycle methods

const args = [ctx, ...tree.slice(1)];
norm = normalizeTree(tag.render.apply(tag, args), ctx, path, keys, span);
norm = exports.normalizeTree(tag.render.apply(tag, args), ctx, path, keys, span);
if (isArray(norm)) {

@@ -147,3 +141,3 @@ norm.__this = tag;

}
norm = normalizeElement(tree, keys);
norm = exports.normalizeElement(tree, keys);
nattribs = norm[1];

@@ -156,3 +150,3 @@ if (keys && nattribs.key === undefined) {

const res = [tag, nattribs];
span = span && !NO_SPANS[tag];
span = span && !api_1.NO_SPANS[tag];
for (let i = 2, j = 2, k = 0, n = norm.length; i < n; i++) {

@@ -164,3 +158,3 @@ let el = norm[i];

for (let c of el) {
c = normalizeTree(c, ctx, path.concat(k), keys, span);
c = exports.normalizeTree(c, ctx, path.concat(k), keys, span);
if (c !== undefined) {

@@ -173,3 +167,3 @@ res[j++] = c;

else {
el = normalizeTree(el, ctx, path.concat(k), keys, span);
el = exports.normalizeTree(el, ctx, path.concat(k), keys, span);
if (el !== undefined) {

@@ -187,6 +181,6 @@ res[j++] = el;

if (isFunction(tree)) {
return normalizeTree(tree(ctx), ctx, path, keys, span);
return exports.normalizeTree(tree(ctx), ctx, path, keys, span);
}
if (implementsFunction(tree, "deref")) {
return normalizeTree(tree.deref(), ctx, path, keys, span);
return exports.normalizeTree(tree.deref(), ctx, path, keys, span);
}

@@ -196,3 +190,2 @@ return span ?

tree.toString();
}
exports.normalizeTree = normalizeTree;
};
{
"name": "@thi.ng/hdom",
"version": "3.0.35",
"version": "4.0.0",
"description": "Lightweight vanilla ES6 UI component & virtual DOM system",

@@ -36,3 +36,3 @@ "main": "./index.js",

"@thi.ng/equiv": "^0.1.7",
"@thi.ng/hiccup": "^2.0.11"
"@thi.ng/hiccup": "^2.1.0"
},

@@ -39,0 +39,0 @@ "keywords": [

@@ -11,3 +11,4 @@ # @thi.ng/hdom

- [About](#about)
- [Minimal example](#minimal-example)
- [Minimal example #1: Local state, RAF update](#minimal-example-1-local-state-raf-update)
- [Minimal example #2 (reactive state & transducer update)](#minimal-example-2-reactive-state--transducer-update)
- [Component tree translation](#component-tree-translation)

@@ -23,2 +24,3 @@ - [Event & state handling options](#event--state-handling-options)

- [Example projects](#example-projects)
- [Realtime crypto chart](#realtime-crypto-chart)
- [Interactive SVG grid generator](#interactive-svg-grid-generator)

@@ -32,7 +34,3 @@ - [Interactive additive waveform visualization](#interactive-additive-waveform-visualization)

- [Todo list](#todo-list)
- [Cellular automata](#cellular-automata)
- [SVG particles](#svg-particles)
- [JSON based components](#json-based-components)
- [@thi.ng/rstream dataflow graph](#thingrstream-dataflow-graph)
- [Basic usage patterns](#basic-usage-patterns)
- [Benchmark](#benchmark)

@@ -46,3 +44,3 @@ - [Authors](#authors)

Lightweight reactive DOM components & VDOM implementation using only
Lightweight reactive DOM components & VDOM-ish implementation using only
vanilla JS data structures (arrays, objects with life cycle functions,

@@ -59,2 +57,5 @@ closures, iterators), based on

arbitrary elements, attributes, events
- Suitable for server side rendering (by passing the same data structure
to @thi.ng/hiccup's `serialize()`) and then "hydrating" listeners and
components with life cycle methods
- Less verbose than HTML / JSX, resulting in smaller file sizes

@@ -65,11 +66,12 @@ - Static components can be distributed as JSON (or [transform JSON

component functions)
- auto-deref of embedded value wrappers which implement the
- CSS conversion from JS objects for `style` attribs
- Auto-deref of embedded value wrappers which implement the
[@thi.ng/api/IDeref](https://github.com/thi-ng/umbrella/tree/master/packages/api/api)
interface (e.g. atoms, cursors, derived views, streams etc.)
- CSS conversion from JS objects for `style` attribs
- Suitable for server side rendering (by passing the same data structure
to @thi.ng/hiccup's `serialize()`)
- Fairly fast (see benchmark example below)
- Only ~4.4KB gzipped
- Only ~5KB gzipped
hdom is *very* flexible and supports different workflows and means to
update a DOM...
In addition to the descriptions in this file, [further information and

@@ -83,3 +85,3 @@ examples are available in the

### Minimal example
### Minimal example #1: Local state, RAF update

@@ -107,3 +109,3 @@ ```ts

// start update loop (browser only, see diagram below)
hdom.start(document.body, app());
hdom.start(app(), { root: document.body });

@@ -129,8 +131,49 @@ // alternatively apply DOM tree only once

No template engine & no pre-compilation steps needed, just use the full
expressiveness of ES6/TypeScript to define your DOM tree. Using
TypeScript gives the additional benefit of making UI components strongly
typed, and since they're just normal functions, can use generics,
overrides, varargs etc.
### Minimal example #2 (reactive state & transducer update)
This example uses the
[@thi.ng/transducers-hdom](https://github.com/thi-ng/umbrella/tree/master/packages/transducers-hdom)
support library to perform reactive DOM updates (instead of regular
diffing via RAF).
```ts
import * as rs from "@thi.ng/rstream/stream";
import * as tx from "@thi.ng/rstream/transducers";
import { updateDOM } from "@thi.ng/rstream/transducers-hdom";
// root component function
const app = ({ ticks, clicks }) =>
["div",
`${ticks} ticks & `,
["a",
{ href: "#", onclick: () => clickStream.next(0)},
`${clicks} clicks`]
];
// click stream (click counter)
const clickStream = rs.stream().transform(tx.scan(tx.count(-1)));
// stream combinator
// waits until all inputs have produced at least one value,
// then updates whenever any input has changed
sync({
// streams to synchronize
src: {
ticks: rs.fromInterval(1000),
clicks: clickStream,
},
}).transform(
// transform tuple into hdom component
tx.map(app),
// apply hdom tree to real DOM
updateDOM({ root: document.body })
);
// kick off
clickStream.next(0);
```
[Live demo](https://demo.thi.ng/umbrella/transducers-hdom/) |
[standalone example](https://github.com/thi-ng/umbrella/tree/master/examples/transducers-hdom)
### Component tree translation

@@ -176,5 +219,4 @@

The overall "API" is stable, but there's further work planned on
generalizing the approach beyond standard browser DOM use cases (planned
for v4.0.0). The project has been used for several projects in
production since 2016.
generalizing the approach beyond standard browser DOM use cases. The
project has been used for several projects in production since 2016.

@@ -207,3 +249,2 @@ ## Installation

- [@thi.ng/hiccup](https://github.com/thi-ng/umbrella/tree/master/packages/hiccup)
- [@thi.ng/iterators](https://github.com/thi-ng/umbrella/tree/master/packages/iterators)

@@ -219,3 +260,3 @@ ## Usage

#### `start(parent: Element | string, tree: any, ctx?: any, path?: number[], keys?: boolean, span?: boolean): () => boolean`
#### `start(tree: any, opts?: Partial<HDOMOpts>): () => any`

@@ -244,6 +285,10 @@ Main user function of this package. For most use cases, this function

**Important:** The parent element given is assumed to have NO children at
the time when `start()` is called. Since hdom does NOT track the real
DOM, the resulting changes will result in potentially undefined behavior
if the parent element wasn't empty.
**Important:** Unless the `hydrate` option is enabled, the parent
element given is assumed to have NO children at the time when `start()`
is called. Since hdom does NOT track the real DOM, the resulting changes
will result in potentially undefined behavior if the parent element
wasn't empty. Likewise, if `hydrate` is enabled, it is assumed that an
equivalent DOM (minus listeners) already exists (i.e. generated via SSR)
when `start()` is called. Any other discrepancies between the
pre-existing DOM and the hdom trees will cause undefined behavior.

@@ -306,2 +351,10 @@ Returns a function, which when called, immediately cancels the update

#### `hydrateDOM(parent: Element, tag: any)`
Takes a DOM root element and normalized hdom tree, then walks tree and
initializes any event listeners and components with lifecycle init
methods. Assumes that an equivalent DOM (minus listeners) already exists
(e.g. generated via SSR) when called. Any other discrepancies between
the pre-existing DOM and the hdom tree will cause undefined behavior.
### User context injection

@@ -366,3 +419,3 @@

// start hdom update loop
start("app", root, ctx);
start(root, { ctx });
```

@@ -439,4 +492,4 @@

start(
document.body,
[canvas(), { width: 100, height: 100 }, "Hello world"]
[canvas(), { width: 100, height: 100 }, "Hello world"],
{ root: document.body }
);

@@ -464,3 +517,3 @@

start(document.body, app());
start(app(), { root: document.body });
```

@@ -470,3 +523,3 @@

Most of the
Most of the 25
[examples](https://github.com/thi-ng/umbrella/tree/master/examples)

@@ -479,2 +532,7 @@ included in this repo are using this package in one way or another.

### Realtime crypto chart
[Source](https://github.com/thi-ng/umbrella/tree/master/examples/crypto-chart) |
[Live version](https://demo.thi.ng/umbrella/crypto-chart/)
### Interactive SVG grid generator

@@ -526,6 +584,2 @@

### Cellular automata
[Source](https://github.com/thi-ng/umbrella/tree/master/examples/cellular-automata) | [Live version](https://demo.thi.ng/umbrella/cellular-automata/)
### SVG particles

@@ -535,18 +589,2 @@

### JSON based components
[Source](https://github.com/thi-ng/umbrella/tree/master/examples/json-components) | [Live version](https://demo.thi.ng/umbrella/json-components/)
### @thi.ng/rstream dataflow graph
A small, interactive dataflow graph example:
[Source](https://github.com/thi-ng/umbrella/tree/master/examples/rstream-dataflow) | [Live version](https://demo.thi.ng/umbrella/rstream-dataflow)
### Basic usage patterns
The code below is also available as standalone project in: [/examples/dashboard](https://github.com/thi-ng/umbrella/tree/master/examples/dashboard)
[Source](https://github.com/thi-ng/umbrella/tree/master/examples/dashboard) | [Live version](https://demo.thi.ng/umbrella/dashboard/)
### Benchmark

@@ -564,4 +602,4 @@

600 / 800 DOM every single frame**, very unlikely for a typical web app.
In Chrome 64 on a MBP2016 this still runs at a stable 60fps (192 cells)
/ 32fps (256 cells). Both FPS readings based the 50 frame
In Chrome 68 on a MBP2016 this still runs at a stable 60fps (192 cells)
/ 37fps (256 cells). Both FPS readings based the 50 frame
[SMA](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average).

@@ -568,0 +606,0 @@

@@ -0,1 +1,2 @@

import { HDOMOpts } from "./api";
/**

@@ -22,6 +23,11 @@ * Takes a parent DOM element (or ID), hiccup tree (array, function or

*
* Important: The parent element given is assumed to have NO children at
* the time when `start()` is called. Since hdom does NOT track the real
* DOM, the resulting changes will result in potentially undefined
* behavior if the parent element wasn't empty.
* **Important:** Unless the `hydrate` option is enabled, the parent
* element given is assumed to have NO children at the time when
* `start()` is called. Since hdom does NOT track the real DOM, the
* resulting changes will result in potentially undefined behavior if
* the parent element wasn't empty. Likewise, if `hydrate` is enabled,
* it is assumed that an equivalent DOM (minus listeners) already exists
* (i.e. generated via SSR) when `start()` is called. Any other
* discrepancies between the pre-existing DOM and the hdom trees will
* cause undefined behavior.
*

@@ -31,7 +37,5 @@ * Returns a function, which when called, immediately cancels the update

*
* @param parent root element or ID
* @param tree hiccup DOM tree
* @param ctx arbitrary user context object
* @param spans true (default), if text should be wrapped in `<span>`
* @param opts options
*/
export declare function start(parent: Element | string, tree: any, ctx?: any, spans?: boolean): () => boolean;
export declare const start: (tree: any, opts?: Partial<HDOMOpts>) => () => boolean;

@@ -6,2 +6,3 @@ "use strict";

const normalize_1 = require("./normalize");
const dom_1 = require("@thi.ng/hdom/src/dom");
/**

@@ -28,6 +29,11 @@ * Takes a parent DOM element (or ID), hiccup tree (array, function or

*
* Important: The parent element given is assumed to have NO children at
* the time when `start()` is called. Since hdom does NOT track the real
* DOM, the resulting changes will result in potentially undefined
* behavior if the parent element wasn't empty.
* **Important:** Unless the `hydrate` option is enabled, the parent
* element given is assumed to have NO children at the time when
* `start()` is called. Since hdom does NOT track the real DOM, the
* resulting changes will result in potentially undefined behavior if
* the parent element wasn't empty. Likewise, if `hydrate` is enabled,
* it is assumed that an equivalent DOM (minus listeners) already exists
* (i.e. generated via SSR) when `start()` is called. Any other
* discrepancies between the pre-existing DOM and the hdom trees will
* cause undefined behavior.
*

@@ -37,18 +43,25 @@ * Returns a function, which when called, immediately cancels the update

*
* @param parent root element or ID
* @param tree hiccup DOM tree
* @param ctx arbitrary user context object
* @param spans true (default), if text should be wrapped in `<span>`
* @param opts options
*/
function start(parent, tree, ctx, spans = true) {
exports.start = (tree, opts) => {
opts = Object.assign({ root: "app", span: true, normalize: true }, opts);
let prev = [];
let isActive = true;
parent = is_string_1.isString(parent) ?
document.getElementById(parent) :
parent;
function update() {
const root = is_string_1.isString(opts.root) ?
document.getElementById(opts.root) :
opts.root;
const update = () => {
if (isActive) {
const curr = normalize_1.normalizeTree(tree, ctx, [0], true, spans);
const curr = opts.normalize ?
normalize_1.normalizeTree(tree, opts.ctx, [0], true, opts.span) :
tree;
if (curr != null) {
diff_1.diffElement(parent, prev, curr);
if (opts.hydrate) {
dom_1.hydrateDOM(root, curr);
opts.hydrate = false;
}
else {
diff_1.diffElement(root, prev, curr);
}
prev = curr;

@@ -59,6 +72,5 @@ }

}
}
};
requestAnimationFrame(update);
return () => (isActive = false);
}
exports.start = start;
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc