nanocomponent
Advanced tools
Comparing version 6.5.0 to 6.5.1
@@ -5,2 +5,6 @@ # nanocomponent Change Log | ||
## 6.5.1 - 2018-02-11 | ||
- Update nanotiming@7.2.0 | ||
- Update devdeps: tap-run, dependency-check, browserify, bankai | ||
## 6.4.6 - 2017-12-05 | ||
@@ -7,0 +11,0 @@ - Proxy elements are created matching the root node returned from the `createElement` method. (🙏@tornqvist🙏) |
module.exports = compare | ||
// included for compatability reasons only | ||
// included for compatibility reasons only | ||
// implements a simple shallow compare for simple values in arrays | ||
@@ -5,0 +5,0 @@ |
{ | ||
"name": "nanocomponent", | ||
"version": "6.5.0", | ||
"version": "6.5.1", | ||
"description": "Native DOM components that pair nicely with DOM diffing algorithms", | ||
@@ -46,3 +46,3 @@ "main": "index.js", | ||
"nanomorph": "^5.1.2", | ||
"nanotiming": "^6.1.3", | ||
"nanotiming": "^7.2.0", | ||
"on-load": "^3.3.4" | ||
@@ -52,8 +52,8 @@ }, | ||
"@tap-format/spec": "^0.2.0", | ||
"bankai": "^8.1.1", | ||
"bankai": "^9.5.1", | ||
"bel": "^5.1.1", | ||
"browserify": "^14.4.0", | ||
"browserify": "^16.0.0", | ||
"choo": "^6.0.1", | ||
"choo-log": "^7.0.1", | ||
"dependency-check": "^2.6.0", | ||
"choo-log": "^8.0.0", | ||
"dependency-check": "^3.0.0", | ||
"envify": "^4.0.0", | ||
@@ -68,4 +68,4 @@ "leaflet": "^1.1.0", | ||
"tape": "^4.7.0", | ||
"tape-run": "^3.0.0" | ||
"tape-run": "^3.0.4" | ||
} | ||
} |
233
README.md
# nanocomponent [![stability][0]][1] | ||
[![npm version][2]][3] [![build status][4]][5] | ||
@@ -8,2 +9,3 @@ [![downloads][8]][9] [![js-standard-style][10]][11] | ||
## Features | ||
- Isolate native DOM libraries from DOM diffing algorithms | ||
@@ -19,2 +21,3 @@ - Makes rendering elements _very fast™_ by avoiding unnecessary rendering | ||
## Usage | ||
```js | ||
@@ -25,22 +28,24 @@ // button.js | ||
function Button () { | ||
if (!(this instanceof Button)) return new Button() | ||
this.color = null | ||
Nanocomponent.call(this) | ||
} | ||
Button.prototype = Object.create(Nanocomponent.prototype) | ||
class Button extends Nanocomponent { | ||
constructor () { | ||
super() | ||
this.color = null | ||
} | ||
Button.prototype.createElement = function (color) { | ||
this.color = color | ||
return html` | ||
<button style="background-color: ${color}"> | ||
Click Me | ||
</button> | ||
` | ||
createElement (color) { | ||
this.color = color | ||
return html` | ||
<button style="background-color: ${color}"> | ||
Click Me | ||
</button> | ||
` | ||
} | ||
// Implement conditional rendering | ||
update (newColor) { | ||
return newColor !== this.color | ||
} | ||
} | ||
// Implement conditional rendering | ||
Button.prototype.update = function (newColor) { | ||
return newColor !== this.color | ||
} | ||
module.exports = Button | ||
``` | ||
@@ -51,5 +56,6 @@ | ||
var choo = require('choo') | ||
var html = require('bel') | ||
var Button = require('./button.js') | ||
var button = Button() | ||
var button = new Button() | ||
@@ -74,5 +80,7 @@ var app = choo() | ||
## Patterns | ||
These are some common patterns you might encounter when writing components. | ||
### Standalone | ||
Nanocomponent is part of the choo ecosystem, but works great standalone! | ||
@@ -97,3 +105,3 @@ | ||
Sometimes it's useful to be pass around prototype methods into other functions. | ||
Sometimes it's useful to pass around prototype methods into other functions. | ||
This can be done by binding the method that's going to be passed around: | ||
@@ -105,30 +113,29 @@ | ||
function Component () { | ||
if (!(this instanceof Component)) return new Component() | ||
Nanocomponent.call(this) | ||
class Component extends Nanocomponent { | ||
constructor () { | ||
super() | ||
// Bind the method so it can be passed around | ||
this.handleClick = this.handleClick.bind(this) | ||
} | ||
Component.prototype = Object.create(Nanocomponent.prototype) | ||
// Bind the method so it can be passed around | ||
this.handleClick = this.handleClick.bind(this) | ||
} | ||
Component.prototype.handleClick = function (ev) { | ||
console.log('element is', this.element) | ||
} | ||
handleClick (event) { | ||
console.log('element is', this.element) | ||
} | ||
Component.prototype.createElement = function () { | ||
return html`<button onClick=${this.handleClick}> | ||
My component | ||
</button>` | ||
} | ||
createElement () { | ||
return html`<button onClick=${this.handleClick}> | ||
My component | ||
</button>` | ||
} | ||
Component.prototype.update = function () { | ||
return false // Never re-render | ||
update () { | ||
return false // Never re-render | ||
} | ||
} | ||
``` | ||
### ES6 Class Syntax | ||
### ES5 Syntax | ||
Because Class syntax is just sugar for prototype code, Nanocomponent can be | ||
written using Classes too: | ||
Nanocomponent can be written using prototypal inheritance too: | ||
@@ -139,24 +146,26 @@ ```js | ||
class Component extends Nanocomponent { | ||
constructor () { | ||
super() | ||
this.color = null | ||
} | ||
function Component () { | ||
if (!(this instanceof Component)) return new Component() | ||
Nanocomponent.call(this) | ||
this.color = null | ||
} | ||
createElement (color) { | ||
this.color = color | ||
return html` | ||
<div style="background-color: ${color}"> | ||
Color is ${color} | ||
</div> | ||
` | ||
} | ||
Component.prototype = Object.create(Nanocomponent.prototype) | ||
update (newColor) { | ||
return newColor !== this.color | ||
} | ||
Component.prototype.createElement = function (color) { | ||
this.color = color | ||
return html` | ||
<div style="background-color: ${color}"> | ||
Color is ${color} | ||
</div> | ||
` | ||
} | ||
Component.prototype.update = function (newColor) { | ||
return newColor !== this.color | ||
} | ||
``` | ||
### Mutating the components instead of re-rendering | ||
Sometimes you might want to mutate the element that's currently mounted, rather | ||
@@ -170,24 +179,24 @@ than performing DOM diffing. Think cases like third party widgets that manage | ||
function Component () { | ||
if (!(this instanceof Component)) return new Component() | ||
Nanocomponent.call(this) | ||
this.text = '' | ||
} | ||
Component.prototype = Object.create(Nanocomponent.prototype) | ||
class Component extends Nanocomponent { | ||
constructor () { | ||
super() | ||
this.text = '' | ||
} | ||
Component.prototype.createElement = function (text) { | ||
this.text = text | ||
return html`<h1>${text}</h1>` | ||
} | ||
Component.prototype.update = function (text) { | ||
if (text !== this.text) { | ||
createElement (text) { | ||
this.text = text | ||
this.element.innerText = this.text // Directly update the element | ||
return html`<h1>${text}</h1>` | ||
} | ||
return false // Don't call createElement again | ||
} | ||
Component.prototype.unload = function (text) { | ||
console.log('No longer mounted on the DOM!') | ||
update (text) { | ||
if (text !== this.text) { | ||
this.text = text | ||
this.element.innerText = this.text // Directly update the element | ||
} | ||
return false // Don't call createElement again | ||
} | ||
unload (text) { | ||
console.log('No longer mounted on the DOM!') | ||
} | ||
} | ||
@@ -197,2 +206,3 @@ ``` | ||
### Nested components and component containers | ||
Components nest and can skip renders at intermediary levels. Components can | ||
@@ -207,28 +217,28 @@ also act as containers that shape app data flowing into view specific | ||
function Component () { | ||
if (!(this instanceof Component)) return new Component() | ||
Nanocomponent.call(this) | ||
this.button1 = new Button () | ||
this.button2 = new Button () | ||
this.button3 = new Button () | ||
} | ||
Component.prototype = Object.create(Nanocomponent.prototype) | ||
class Component extends Nanocomponent { | ||
constructor () { | ||
super() | ||
this.button1 = new Button() | ||
this.button2 = new Button() | ||
this.button3 = new Button() | ||
} | ||
Component.prototype.createElement = function (state) { | ||
var colorArray = shapeData(state) | ||
return html` | ||
<div> | ||
${this.button1.render(colorArray[0])} | ||
${this.button2.render(colorArray[1])} | ||
${this.button3.render(colorArray[2])} | ||
</div> | ||
` | ||
} | ||
createElement (state) { | ||
var colorArray = shapeData(state) | ||
return html` | ||
<div> | ||
${this.button1.render(colorArray[0])} | ||
${this.button2.render(colorArray[1])} | ||
${this.button3.render(colorArray[2])} | ||
</div> | ||
` | ||
} | ||
Component.prototype.update = function (state) { | ||
var colorArray = shapeData(state) // process app specific data in a container | ||
this.button1.render(colorArray[0]) // pass processed data to owned children components | ||
this.button2.render(colorArray[1]) | ||
this.button3.render(colorArray[2]) | ||
return false // always return false when mounted | ||
update (state) { | ||
var colorArray = shapeData(state) // process app specific data in a container | ||
this.button1.render(colorArray[0]) // pass processed data to owned children components | ||
this.button2.render(colorArray[1]) | ||
this.button3.render(colorArray[2]) | ||
return false // always return false when mounted | ||
} | ||
} | ||
@@ -243,10 +253,13 @@ | ||
## FAQ | ||
### What order do lifecycle events run in? | ||
<figure> | ||
<img src="lifecycle.jpg" alt="Lifecycle diagram"> | ||
<figcaption>Note: aftercreate should actually say afterupdate. Shoutout to <a href="https://github.com/lrlna">@lrlna</a> for the excellent diagram.</figcaption> | ||
</figure> | ||
![Lifecycle diagram](lifecycle.jpg) | ||
**Note:** `aftercreate` should actually say `afterupdate`. | ||
Shoutout to [@lrlna](https://github.com/lrlna) for the excellent diagram. | ||
### Where does this run? | ||
Nanocomponent was written to work well with [choo][choo], but it also works well | ||
@@ -260,2 +273,3 @@ with DOM diffing engines that check `.isSameNode()` like [nanomorph][nm] and | ||
### What's a proxy node? | ||
It's a node that overloads `Node.isSameNode()` to compare it to another node. | ||
@@ -286,2 +300,3 @@ This is needed because a given DOM node can only exist in one DOM tree at the | ||
### How does it work? | ||
[`nanomorph`][nm] is a diffing engine that diffs real DOM trees. It runs a series | ||
@@ -302,2 +317,3 @@ of checks between nodes to see if they should either be replaced, removed, | ||
### Is this basically `react-create-class`? | ||
`nanocomponent` is very similar to `react-create-class`, but it leaves more decisions up | ||
@@ -310,3 +326,5 @@ to you. For example, there is no built in `props` or `state` abstraction in `nanocomponent` | ||
## API | ||
### `component = Nanocomponent([name])` | ||
Create a new Nanocomponent instance. Additional methods can be set on the | ||
@@ -316,2 +334,3 @@ prototype. Takes an optional name which is used when emitting timings. | ||
### `component.render([arguments…])` | ||
Render the component. Returns a proxy node if already mounted on the DOM. Proxy | ||
@@ -321,5 +340,7 @@ nodes make it so DOM diffing algorithms leave the element alone when diffing. Call this when `arguments` have changed. | ||
### `component.rerender()` | ||
Re-run `.render` using the last `arguments` that were passed to the `render` call. Useful for triggering component renders if internal state has changed. Arguments are automatically cached under `this._arguments` (🖐 hands off, buster! 🖐). The `update` method is bypassed on re-render. | ||
### `component.element` | ||
A [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) | ||
@@ -330,2 +351,3 @@ property that returns the component's DOM node if its mounted in the page and | ||
### `DOMNode = Nanocomponent.prototype.createElement([arguments…])` | ||
__Must be implemented.__ Component specific render function. Optionally cache | ||
@@ -337,2 +359,3 @@ argument values here. Run anything here that needs to run along side node | ||
### `Boolean = Nanocomponent.prototype.update([arguments…])` | ||
__Must be implemented.__ Return a boolean to determine if | ||
@@ -344,2 +367,3 @@ `prototype.createElement()` should be called. The `update` method is analogous to | ||
### `Nanocomponent.prototype.beforerender(el)` | ||
A function called right after `createElement` returns with `el`, but before the fully rendered | ||
@@ -350,2 +374,3 @@ element is returned to the `render` caller. Run any first render hooks here. The `load` and | ||
### `Nanocomponent.prototype.load(el)` | ||
Called when the component is mounted on the DOM. Uses [on-load][onload] under | ||
@@ -355,2 +380,3 @@ the hood. | ||
### `Nanocomponent.prototype.unload(el)` | ||
Called when the component is removed from the DOM. Uses [on-load][onload] under | ||
@@ -360,2 +386,3 @@ the hood. | ||
### `Nanocomponent.prototype.afterupdate(el)` | ||
Called after a mounted component updates (e.g. `update` returns true). You can use this hook to call | ||
@@ -365,2 +392,3 @@ `element.scrollIntoView` or other dom methods on the mounted component. | ||
### `Nanocomponent.prototype.afterreorder(el)` | ||
Called after a component is re-ordered. This method is rarely needed, but is handy when you have a component | ||
@@ -370,2 +398,3 @@ that is sensitive to temorary removals from the DOM, such as externally controlled iframes or embeds (e.g. embedded tweets). | ||
## Installation | ||
```sh | ||
@@ -401,2 +430,3 @@ $ npm install nanocomponent | ||
## Similar Packages | ||
- [shama/base-element](https://github.com/shama/base-element) | ||
@@ -408,2 +438,3 @@ - [yoshuawuyts/cache-element](https://github.com/yoshuawuyts/cache-element) | ||
## License | ||
[MIT](https://tldrlegal.com/license/mit-license) | ||
@@ -410,0 +441,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
438
236553
+ Addednanoscheduler@1.0.3(transitive)
+ Addednanotiming@7.3.1(transitive)
- Removednanotiming@6.1.5(transitive)
Updatednanotiming@^7.2.0