From c399da72308106d75877b45d81d25f6eece16663 Mon Sep 17 00:00:00 2001 From: Jorge Bucaran Date: Fri, 4 May 2018 02:02:46 +0900 Subject: [PATCH] 3.1.0 --- .babelrc | 13 ---------- .travis.yml | 3 ++- README.md | 59 ++++++++++++++++++------------------------ package.json | 17 ++++-------- src/patch.js | 23 +++++++--------- test/dom.test.js | 30 ++++++++++++++++++++- test/h.test.js | 2 +- test/lifecycle.test.js | 27 ++++++++++--------- test/svg.test.js | 30 --------------------- test/ts/index.tsx | 6 ----- test/ts/tsconfig.json | 13 ---------- ultradom.d.ts | 42 ------------------------------ 12 files changed, 84 insertions(+), 181 deletions(-) delete mode 100644 .babelrc delete mode 100644 test/svg.test.js delete mode 100644 test/ts/index.tsx delete mode 100644 test/ts/tsconfig.json delete mode 100644 ultradom.d.ts diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 1e78999..0000000 --- a/.babelrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "presets": [ - "env", - "react", - "stage-0" - ], - "plugins": [ - "transform-class-properties", - "transform-decorators", - "transform-react-constant-elements", - "transform-react-inline-elements" - ] -} diff --git a/.travis.yml b/.travis.yml index dfb0832..369bd9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: node_js node_js: + - "10" + - "9" - "8" - - "7" env: - NODE_ENV=development diff --git a/README.md b/README.md index c1a03e1..8ec570b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,30 @@ -# Ultradom +# _Ultradom_ [![Travis CI](https://img.shields.io/travis/jorgebucaran/ultradom/master.svg)](https://travis-ci.org/jorgebucaran/ultradom) [![Codecov](https://img.shields.io/codecov/c/github/jorgebucaran/ultradom/master.svg)](https://codecov.io/gh/jorgebucaran/ultradom) [![npm](https://img.shields.io/npm/v/ultradom.svg)](https://www.npmjs.org/package/ultradom) [![Slack](https://hyperappjs.herokuapp.com/badge.svg)](https://hyperappjs.herokuapp.com "#ultradom") -Ultradom is a minimal (1 kB) view layer for building declarative web user interfaces. Mix it with your favorite state management library or use it standalone for unlimited flexibility. +Ultradom is a minimal (1 kB) view layer for building declarative web user interfaces. Includes a virtual DOM diff algorithm, keyed-based node [reconciliation](#keys), element-level [lifecycle](#lifecycle-events) events and browser support all the way back to IE9. Mix it with your favorite state management library or use it standalone for maximum flexibility. -What's in the bundle? A virtual DOM and diff algorithm, keyed-based node [reconciliation](#keys), element-level [lifecycle](#lifecycle-events) events and browser support all the way back to IE9. +

Table of Contents

+ + +* [Installation](#installation) +* [Getting Started](#getting-started) +* [Supported Attributes](#supported-attributes) + * [Styles](#styles) + * [Lifecycle Events](#lifecycle-events) + * [oncreate](#oncreate) + * [onupdate](#onupdate) + * [onremove](#onremove) + * [ondestroy](#ondestroy) + * [Keys](#keys) +* [JSX](#jsx) +* [Community](#community) +* [License](#license) + + ## Installation @@ -23,7 +40,7 @@ Don't want to set up a build environment? Download Ultradom from a CDN such as [ ## Getting Started -Let's walkthrough a simple ticking clock. You can [try it online](https://codepen.io/jorgebucaran/pen/LdLJXX?editors=0010) to see what it looks like. +Let's walkthrough a simple ticking clock. You can [try it online](https://codepen.io/jorgebucaran/pen/wjvEBj?editors=0010) to see what it looks like. ```js import { h, render } from "ultradom" @@ -43,49 +60,23 @@ setInterval( Ultradom consists of a two-function API. ultradom.h creates a new virtual DOM node and ultradom.render renders it into the supplied container. -A virtual DOM is a description of what a DOM should look like using a tree of nested JavaScript objects known as virtual nodes. Think of it as a lightweight representation of the DOM. - -```jsx -{ - name: "div", - attributes: {}, - children: [ - { - name: "h1", - attributes: {}, - children: "Hello World!" - }, - { - name: "h2", - attributes: {}, - children: `The time is: ${new Date().toLocaleTimeString()}` - } - ] -} -``` - -The virtual DOM allows us to write code as if the entire document is thrown away and rebuilt every time we render a node, while we only update the parts of the DOM that actually changed. +A virtual DOM is a description of what a DOM should look like using a tree of nested JavaScript objects known as virtual nodes. It allows us to write code as if the entire document is rebuilt every time we render a node, while we only update the parts of the DOM that actually changed. We try to do this in the least number of steps possible, by comparing the new virtual DOM against the previous one. This leads to high efficiency, since typically only a small percentage of nodes need to change, and changing real DOM nodes is costly compared to recalculating the virtual DOM. ## Supported Attributes -* [HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes) -* [SVG attributes](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) -* [DOM events](https://developer.mozilla.org/en-US/docs/Web/Events) -* [Styles](#styles) -* [Lifecycle Events](#lifecycle-events) -* [Keys](#keys) +Ultradom elements support the standard [HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes), [SVG attributes](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) and [DOM events](https://developer.mozilla.org/en-US/docs/Web/Events). Some attributes like [Styles](#styles) are handled specially. Non-standard attributes include [Lifecycle Events](#lifecycle-events) and [Keys](#keys). ### Styles The style attribute expects a plain object rather than a string as in HTML. -Each declaration consists of a style name property written in camelCase and a value. CSS variables are also supported. +Each declaration consists of a style name property written in camelCase and a value. ```jsx import { h } from "ultradom" -export const Jumbotron = text => +export const Banner = text => h( "div", { diff --git a/package.json b/package.json index a3de891..afd14d1 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,7 @@ "repository": "jorgebucaran/ultradom", "files": [ "src", - "dist", - "ultradom.d.ts" + "dist" ], "author": "Jorge Bucaran", "keywords": [ @@ -20,12 +19,11 @@ "vdom" ], "scripts": { - "test": "jest --coverage --no-cache && tsc -p test/ts", + "test": "jest --coverage --no-cache", "build": "npm run bundle && npm run minify", - "bundle": "rollup -i src/index.js -o dist/ultradom.js -m -f umd -n ultradom", + "bundle": "rollup -i src/index.js -o dist/ultradom.js -m -f iife -n ultradom", "minify": "uglifyjs dist/ultradom.js -o dist/ultradom.js -mc pure_funcs=['Object.defineProperty'] --source-map includeSources,url=ultradom.js.map", "prepare": "npm run build", - "format": "prettier --write {src,test}/**/*.js {,test/ts/}*.{ts,tsx}", "release": "npm run build && npm test && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" }, "babel": { @@ -34,12 +32,7 @@ "devDependencies": { "babel-env": "2.4.1", "jest": "^22.4.3", - "prettier": "~1.12.1", - "rollup": "^0.58.0", - "uglify-js": "^3.3.21", - "typescript": "^2.8.1" - }, - "prettier": { - "semi": false + "rollup": "^0.58.2", + "uglify-js": "^3.3.23" } } diff --git a/src/patch.js b/src/patch.js index ebd91c2..4458fb8 100644 --- a/src/patch.js +++ b/src/patch.js @@ -6,9 +6,11 @@ import { getKey } from "./getKey" export function patch(parent, element, oldNode, node, lifecycle, isSVG) { if (node === oldNode) { } else if (oldNode == null || oldNode.name !== node.name) { - var newElement = createElement(node, lifecycle, isSVG) + var newElement = parent.insertBefore( + createElement(node, lifecycle, isSVG), + element + ) - parent.insertBefore(newElement, element) if (oldNode != null) { removeElement(parent, element, oldNode) } @@ -74,23 +76,16 @@ export function patch(parent, element, oldNode, node, lifecycle, isSVG) { } i++ } else { - var keyedNode = oldKeyed[newKey] || [] + var keyed = oldKeyed[newKey] || [] if (oldKey === newKey) { - patch( - element, - keyedNode[0], - keyedNode[1], - children[k], - lifecycle, - isSVG - ) + patch(element, keyed[0], keyed[1], children[k], lifecycle, isSVG) i++ - } else if (keyedNode[0]) { + } else if (keyed[0]) { patch( element, - element.insertBefore(keyedNode[0], oldElements[i]), - keyedNode[1], + element.insertBefore(keyed[0], oldElements[i]), + keyed[1], children[k], lifecycle, isSVG diff --git a/test/dom.test.js b/test/dom.test.js index 7e324b4..d577fb8 100644 --- a/test/dom.test.js +++ b/test/dom.test.js @@ -6,7 +6,6 @@ function testTrees(name, trees) { render(tree.node, document.body) expect(document.body.innerHTML).toBe(tree.html.replace(/\s{2,}/g, "")) }) - done() }) } @@ -736,3 +735,32 @@ test("event handlers", done => { document.body ) }) + +const deepExpectNS = (element, ns) => + Array.from(element.childNodes).map(child => { + expect(child.namespaceURI).toBe(ns) + deepExpectNS(child, ns) + }) + +test("svg", () => { + const SVG_NS = "http://www.w3.org/2000/svg" + + const node = h("div", {}, [ + h("p", { id: "foo" }, "foo"), + h("svg", { id: "bar", viewBox: "0 0 10 10" }, [h("foo")]), + h("p", { id: "baz" }, "baz") + ]) + + render(node, document.body) + + const foo = document.getElementById("foo") + const bar = document.getElementById("bar") + const baz = document.getElementById("baz") + + expect(foo.namespaceURI).not.toBe(SVG_NS) + expect(baz.namespaceURI).not.toBe(SVG_NS) + expect(bar.namespaceURI).toBe(SVG_NS) + expect(bar.getAttribute("viewBox")).toBe("0 0 10 10") + + deepExpectNS(bar, SVG_NS) +}) diff --git a/test/h.test.js b/test/h.test.js index 51c2785..9c77c20 100644 --- a/test/h.test.js +++ b/test/h.test.js @@ -1,4 +1,4 @@ -import { h } from "../src" +import { h, render } from "../src" test("empty vnode", () => { expect(h("div")).toEqual({ diff --git a/test/lifecycle.test.js b/test/lifecycle.test.js index a27e923..a38d333 100644 --- a/test/lifecycle.test.js +++ b/test/lifecycle.test.js @@ -1,14 +1,13 @@ -import * as ultradom from "../src" +import { h, render } from "../src" -const { h } = ultradom -const render = node => ultradom.render(node, document.body) +const app = (view, state) => render(view(state), document.body) beforeEach(() => { document.body.innerHTML = "" }) test("oncreate", () => { - render( + app(() => h( "div", { @@ -37,8 +36,8 @@ test("onupdate", done => { state ) - render(view("foo")) - render(view("bar")) + app(view, "foo") + app(view, "bar") }) test("onremove", done => { @@ -56,8 +55,8 @@ test("onremove", done => { ]) : h("ul", {}, [h("li")]) - render(view(true)) - render(view(false)) + app(view, true) + app(view, false) }) test("ondestroy", done => { @@ -81,8 +80,8 @@ test("ondestroy", done => { ]) : h("ul", {}, [h("li")]) - render(view(true)) - render(view(false)) + app(view, true) + app(view, false) }) test("onremove/ondestroy", done => { @@ -106,8 +105,8 @@ test("onremove/ondestroy", done => { ]) : h("ul", {}, [h("li")]) - render(view(true)) - render(view(false)) + app(view, true) + app(view, false) }) test("event bubbling", done => { @@ -153,6 +152,6 @@ test("event bubbling", done => { ] ) - render(view()) - render(view()) + app(view) + app(view) }) diff --git a/test/svg.test.js b/test/svg.test.js deleted file mode 100644 index 9eb4c91..0000000 --- a/test/svg.test.js +++ /dev/null @@ -1,30 +0,0 @@ -import { h, render } from "../src" - -const SVG_NS = "http://www.w3.org/2000/svg" - -const deepExpectNS = (element, ns) => - Array.from(element.childNodes).map(child => { - expect(child.namespaceURI).toBe(ns) - deepExpectNS(child, ns) - }) - -test("svg", () => { - const node = h("div", {}, [ - h("p", { id: "foo" }, "foo"), - h("svg", { id: "bar", viewBox: "0 0 10 10" }, [h("foo")]), - h("p", { id: "baz" }, "baz") - ]) - - render(node, document.body) - - const foo = document.getElementById("foo") - const bar = document.getElementById("bar") - const baz = document.getElementById("baz") - - expect(foo.namespaceURI).not.toBe(SVG_NS) - expect(baz.namespaceURI).not.toBe(SVG_NS) - expect(bar.namespaceURI).toBe(SVG_NS) - expect(bar.getAttribute("viewBox")).toBe("0 0 10 10") - - deepExpectNS(bar, SVG_NS) -}) diff --git a/test/ts/index.tsx b/test/ts/index.tsx deleted file mode 100644 index dc18ef5..0000000 --- a/test/ts/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { h, render, VNode } from "ultradom" - -type View = (value: string) => VNode -const view: View = value =>

{value}

- -render(view("Hello World"), document.body) diff --git a/test/ts/tsconfig.json b/test/ts/tsconfig.json deleted file mode 100644 index 09fd114..0000000 --- a/test/ts/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "noEmit": true, - "jsx": "react", - "jsxFactory": "h", - "baseUrl": "../..", - "paths": { - "ultradom": ["src", "ultradom.d.ts"] - } - }, - "include": ["*.ts", "*.tsx", "**/*.ts", "**/*.tsx"] -} diff --git a/ultradom.d.ts b/ultradom.d.ts deleted file mode 100644 index 32c59a2..0000000 --- a/ultradom.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -export as namespace ultradom - -export type Children = VNode | string | number | null - -/** - * The virtual DOM representation of an Element. - */ -export interface VNode { - name: string - attributes?: Attributes - children: Array - key: string -} - -/** - * Create a new virtual DOM node. A virtual DOM is a description of what a DOM should look like using a tree of nested JavaScript objects known as virtual nodes. - * @param name The name of an Element or a function that returns a virtual DOM node. - * @param attributes HTML attributes, SVG attributes, DOM events, Lifecycle Events, and Keys. Note that non-standard HTML attribute names are not supported, onclick and class are valid, but onClick or className are not. - * @param children The element's child nodes. - */ -export function h( - name: string, - attributes?: Attributes | null, - ...children: Array -): VNode - -/** - * Render a virtual DOM node in a DOM container. - * - * @param {VNode} node The virtual DOM node. - * @param {Element?} element A DOM element. - **/ -export function render(node: VNode, container: Element): void - -declare global { - namespace JSX { - interface Element extends VNode {} - interface IntrinsicElements { - [elemName: string]: any - } - } -}