diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..9e27feb
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,7 @@
+{
+ "presets": ["es2015", "stage-2"],
+ "sourceMaps": true,
+ "plugins": [
+ ["transform-react-jsx", {"pragma": "h"}]
+ ]
+}
diff --git a/.gitignore b/.gitignore
index f6467ff..daf7a12 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
node_modules
-components
.DS_Store
+_book
diff --git a/.npmignore b/.npmignore
index d55582f..121ef01 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,8 +1,2 @@
-node_modules
-test/
-docs/
-.npmignore
-.zuul
-History.md
-LICENSE.md
-Makefile
\ No newline at end of file
+test
+src
diff --git a/.zuul.yml b/.zuul.yml
index 002c144..3d476b5 100644
--- a/.zuul.yml
+++ b/.zuul.yml
@@ -2,9 +2,9 @@ ui: tape
concurrency: 2
browsers:
- name: chrome
- version: 43..latest
+ version: latest
- name: firefox
- version: 38..latest
+ version: latest
- name: iphone
version: latest
- name: ipad
@@ -15,4 +15,3 @@ browsers:
version: 7..latest
browserify:
- transform: babelify
- - transform: envify
diff --git a/History.md b/History.md
deleted file mode 100644
index 3a504e2..0000000
--- a/History.md
+++ /dev/null
@@ -1,478 +0,0 @@
-
-1.0.0 / 2015-12-04
-==================
-
- * Add load event
- * fix counter example
- * Fixed bug with adding events
- * Add HTML5 media events
- * add babel 6 instructions yet point back to babel@5
- * alias npm test script to make test for sake of convention
- * add to install guide using webpack
- * Don't treat number as a falsy attribute
- * Add failing test for input values
- * getting examples working using duo-serve
-
-0.5.6 / 2015-09-21
-==================
-
- * meta: updating dist for duo/component
-
-0.5.5 / 2015-09-11
-==================
-
- * return result of calling event handler (return `false` to cancel bubbling)
-
-0.5.4 / 2015-08-14
-==================
-
- * Merge pull request #232 from dekujs/stringify/empty-attrs
- * properly handling empty attrs, with tests to prevent regression
- * Merge pull request #231 from dekujs/stringify/no-children
- * fixing stringify for components with children
- * Update events.js
-
-0.5.3 / 2015-08-12
-==================
-
- * Merge pull request #230 from dekujs/text-selection-active-only
- * ie handles focus differently, so gotta make sure we account for that
- * only adjust text selection for the active element
-
-0.5.2 / 2015-08-12
-==================
-
- * Fixed issue selecting text with some input types
- * Update history. I'll fix that makefile one day
-
-0.5.1 / 2015-08-11
-==================
-
- * adding some helpful form-related events
- * Corrected afterMount arity. Fixes #225.
- * Keep cursor position when changing input value
-
-0.5.0 / 2015-08-03
-==================
-
- * Adding a heuristic to determine the best HTMLElement on which to attach events listener. The intention here is to enable deku to render into document fragments such as Shadow DOM.
- * Components can be functions instead of objects
- * Update dependencies
- * Fixed bug with replacing text nodes with undefined
- * Refactored the tests
- * Removed DOM pooling
- * Switch to use virtual-element
-
-0.4.12 / 2015-07-28
-==================
-
- * Merge pull request #212 from dekujs/flatmap-children
- * Fixed failing tests
- * Update index.js
- * Flattening the virtual element children array
-
-0.4.11 / 2015-07-17
-==================
-
- * Fixed deprecation warnings
- * Updated history
-
-0.4.10 / 2015-07-16
-==================
-
- * Added validate hook
- * Attach events to document instead of document.body
- * added ability to cancel events
- * Possibility to pass `false` as well as `null` in component children
- * Remove prop validation
- * Added deprecation warnings for magic class and style transformations.
- * No longer flattening children in virtual nodes
- * Faster SVG element lookups
-
-0.4.9 / 2015-07-07
-==================
-
- * Merge pull request #191 from timmak/svg-missing-animate
- * Add animate to svg list
-
-0.4.8 / 2015-07-01
-==================
-
- * Merge branch 'master' of ssh://github.com/dekujs/deku
- * Merge pull request #188 from xdissent/fix-remove-null-el
- * Handle null element in isElement(). fixes #180
-
-0.4.7 / 2015-07-01
-==================
-
- * Not pooling select elements
-
-0.4.6 / 2015-06-29
-==================
-
- * Merge pull request #187 from dekujs/should-render
- * Fixed: State not committed during shouldUpdate
- * Merge pull request #177 from mpal9000/patch-1
- * docs - initialState props
-
-0.4.5 / 2015-06-13
-==================
-
- * We made it smaller!
- * Merge pull request #173 from foray1010/master
- * Added wheel event
- * Update README.md
- * Update README.md
- * Merge pull request #166 from xdissent/patch-1
- * Merge pull request #167 from DylanPiercey/patch-1
- * Update jsx.md
- * Update events link in README
-
-0.4.4 / 2015-06-05
-==================
-
- * Added `createElement` alias for `element`
- * Update components.md
- * Updated changelog
-
-0.4.3 / 2015-06-04
-==================
-
- * Remove event throttling. Fixes #159
- * added keypress event
- * Fixed issue with rendering event handlers when using renderString
-
-0.4.2 / 2015-05-28
-==================
-
- * fixed event handling so events bubble to parent handlers
-
-0.4.1 / 2015-05-26
-==================
-
- * propTypes validation - support for array of types, type as function
-
-0.4.0 / 2015-05-22
-==================
-
- * Fixed: Fixed issue with components rendered as root nodes.
- * New: initialState now takes the props as a param
- * New: afterMount, afterRender and event handlers can now return a promise. This means you can use ES7 async functions to have pure lifecycle functions too.
- * New: You can nest propTypes now. Just set the `type` field to be another propTypes object.
- * Fixed: `afterRender` and `afterMount` are now called when the element is in the DOM.
- * Updated: Added phantomjs to the dev deps
-
-0.3.3 / 2015-05-22
-==================
-
- * Added mouseenter/mouseleave
- * Merge pull request #137 from Frikki/issue-134/modular-fastjs
- * Replaced fast.js require with modular requirement.
-
-0.3.2 / 2015-05-20
-==================
-
-
-
-0.3.1 / 2015-05-21
-==================
-
- * fixed error with swapping component using sources
-
-0.3.0 / 2015-05-18
-==================
-
- * Added: warnings and nicer error messages
- * Added: Always emptying the container when rendering
- * Added: Deku.d.ts file
- * Removed: the `defaultX` attributes from checkboxes, selects and inputs
- * Fixed: rendering for `checked`, `selected` and `disabled` attributes
- * Fixed: multiple components depending on the same `source`
-
-0.2.17 / 2015-05-11
-==================
-
- * set sources on update
-
-0.2.16 / 2015-05-11
-==================
-
- * Using a different component object each render
- * Cleaned up tests and build
- * Calling .set will always trigger an update instead of checking equality with the previous data value.
- * Added React comparison examples
- * Fixed bug where handler references weren't removed
- * Skip rendering if element is the same
-
-0.2.15 / 2015-05-04
-==================
-
- * add svg support
- * Throw errors for empty types on elements
-
-0.2.14 / 2015-05-03
-==================
-
- * Using fast.js
- * Added some simple examples
-
-0.2.13 / 2015-04-30
-==================
-
- * Added workaround for diffChildren bug
-
-0.2.12 / 2015-04-29
-==================
-
- * Merge pull request #83 from segmentio/fix/child-key-diffing
- * Removed key diffing for elements
- * Passing tests for the keys with events
- * Tests passing with janky first version
- * Added failing test
- * Only flatten children one level deep
-
-0.2.11 / 2015-04-29
-==================
-
- * Added test for virtual node indexes
- * Correctly casting key to a string
-
-0.2.10 / 2015-04-29
-==================
-
- * Improved performance by removing 'omit'
- * IE10 fix
- * Running all tests
- * Added tests for components with keys
- * Coercing keys to strings
- * Code style
-
-0.2.9 / 2015-04-28
-==================
-
- * Passing tests
- * The patch returns the updated element
- * Code style
- * Removing elements first when diffing
- * Cleaned up the key diffing
-
-0.2.8 / 2015-04-28
-==================
-
- * Fixed more issues with falsy keys
-
-0.2.7 / 2015-04-28
-==================
-
- * Fixed falsy keys
-
-0.2.6 / 2015-04-28
-==================
-
- * Fixed incorrect path
-
-0.2.5 / 2015-04-28
-==================
-
- * Avoid touching elements that haven't moved
- * Added test for adding nodes with new keys
-
-0.2.4 / 2015-04-28
-==================
-
- * Fixed bug with creating new nodes in the diff
-
-0.2.3 / 2015-04-27
-==================
-
- * Fixed issue with initial mount
-
-0.2.2 / 2015-04-27
-==================
-
- * Merge branch 'docs'
- * Updated docs
- * Removed old docs and examples
- * Allowing easier initial mounting
- * Adding docs
-
-0.2.1 / 2015-04-25
-==================
-
- * Fixed bug with diffing keyed nodes
-
-0.2.0 / 2015-04-25
-==================
-
- * Updated the hook API
- * Removed defaults
-
-0.1.1 / 2015-04-22
-==================
-
- * Replaced lodash and removed unused modules
-
-0.1.0 / 2015-04-21
-==================
-
-Breaking
- * Updated the top-level API. It now mounts virtual nodes instead of components directly.
- * Removed the `component()` DSL. Components are just objects now with no concept of `this`. This is one step towards making hook functions pure.
- * There is no more `this` in any of the functions used in a component. Instead of `this.setState`, the last argument to the function is `setState`, or `send` (think of it as sending changes to the UI).
- * Removed tagName parsing (eg. `dom('div.foo')`) as it was slowing things down
-
-New Features
- * Added key diffing using the `key` attribute on virtual nodes
- * Added optional prop validation via `propTypes`
- * Added defaultProps hook to components
- * Added the ability for components to access data on the app. This makes it easy to side-load data.
-
-Fixes
- * Fixed bug with inputs/textarea being pooled incorrectly
- * Merge pull request #72 from segmentio/attr-modification-bug
- * Fixed a bug in the renderer for falsy attributes
- * Numerous speed improvements
- * Fixed bug with string renderer not calling `beforeMount`
- * Removed the raf loop and just batches
-
-0.0.33 / 2015-04-02
-==================
-
- * Fixed bug with nested components not being unmounted
- * Added test for nested components disabling pooling
-
-0.0.32 / 2015-04-01
-==================
-
- * dom: Fixed disablePooling flag for nested components
-
-0.0.31 / 2015-04-01
-==================
-
- * dom: Tests for scene removal
- * dom: Cleaned up removing of elements
-
-0.0.30 / 2015-03-27
-==================
-
- * Added DOM pooling
-
-0.0.29 / 2015-03-24
-==================
-
- * Breaking change: Updated the scene/renderer API to allow for more powerful plugins. The Component API is now decoupled from the renderer.
- * Tests now using ES6
- * Fixed beforeMount not firing with renderString
- * Fixed innerHTML rendering with renderString
-
-0.0.28 / 2015-03-11
-==================
-
- * Interactions bind to the body
- * Update component#render() to throw if container is empty
- * Fixed tests in IE9. Fixed SauceLab tests.
- * Removed all the crap from the repo
-
-0.0.27 / 2015-02-26
-==================
-
- * Fixed bug with re-rendering child nodes
-
-0.0.26 / 2015-02-26
-==================
-
-* The renderer now renders the entire tree whenever it is dirty and no longer performs shallow equality checks to determine if a component should update. This means that when a component changes, the entire tree below it is re-rendered, including all nested components. This helps to prevent annoying bugs with objects changing and the UI not updating.
-* The scene continues to update on every frame, but will still only actually render a component in the tree has changed.
-* There is a new shouldUpdate hook available to components to optimize this. You can stop it from re-rendering a component by returning false from this method.
-* Removed channels from the API. This was an experimental API and it turned out to be the wrong abstraction when using it in practice. It was making the library responsible for more than it should be.
-* The entities now don't know about the scene at all, making them completely decoupled from it.
-* The HTMLRenderer now keeps track of the entity state and structure. This allows the entity to become a wrapper around the user component and only provide managing the state/props from the component.
-* The scene will now pause when there is an error during rendering to prevent endless errors.
-* The scene methods no longer return a promise. It was never used in practice because the top level components are never used in flow control.
-* The diff is now slightly more decoupled, which will allow it to be extracted from deku.
-* Removed some unused dependencies. This should make the whole library smaller.
-* The logic around commiting changes to props/state in the entity has been reworked. It's now much simpler and less prone to bugs.
-
-
-0.0.25 / 2015-02-22
-==================
-
- * JSX support
-
-0.0.24 / 2015-02-11
-==================
-
- * Added failing test for nested events
- * added hasFunction to fix #47
- * added failing test to demo function diffing
-
-0.0.23 / 2015-02-09
-==================
-
- * Added innerHTML support
- * Fixed drag and drop test event
- * Added test for #47
-
-0.0.22 / 2015-02-03
-==================
-
- * Pulled virtual DOM lib out
-
-0.0.21 / 2015-02-03
-==================
-
- * Added ability to render component at the root
-
-0.0.20 / 2015-01-29
-==================
-
- * Value attribute gets a special case in the diff
- * Using raf-loop instead of local module
- * Using uid module
-
-0.0.19 / 2015-01-25
-==================
-
- * Moved to browserify for the build
-
-0.0.18 / 2015-01-25
-==================
-
- * Fixed event delegation
- * Added some super basic perf tests
- * Fixed issue with scene not removing listeners
-
-0.0.17 / 2015-01-24
-==================
-
- * Fixed bug when changing root node. Closes #33
-
-0.0.16 / 2015-01-23
-==================
-
- * Fixed issue with channels not being sent to render
-
-0.0.15 / 2015-01-23
-==================
-
- * Added .channel and .prop methods
- * Removed .send and .onMessage in favour of channels
- * Scene is no longer immediately rendered
-
-0.0.14 / 2015-01-21
-==================
-
- * Add .send and .onMessage methods. You can call this.send(name, payload) within components and listen for those events on the scene with scene.onMessage(name, fn);
-
-0.0.13 / 2015-01-20
-==================
-
- * Fixed a bug with IDs being identical
- * Added History.md
-
-0.0.12 / 2015-01-19
-==================
-
- * Add repo field
- * Updated bump
- * Updated release task
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index e5f2164..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,7 +0,0 @@
-The MIT License (MIT) Copyright (c) 2015 Anthony Short
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index db97944..a74cb84 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,11 @@
#
-# Binaries.
+# Vars.
#
-export PATH := ./node_modules/.bin:${PATH}
BIN := ./node_modules/.bin
-#
-# Wildcards.
-#
-
-src = $(shell find lib/*.js)
-tests = $(shell find test/**/*.js)
+src = $(shell find src/*.js)
+tests = $(shell find test/*.js)
#
# Targets.
@@ -20,54 +15,34 @@ default: test
$(src): node_modules
$(tests): node_modules
-standalone: $(src)
- @mkdir -p build
- @NODE_ENV=production browserify \
+build: $(src)
+ @mkdir -p dist
+ @NODE_ENV=production ${BIN}/browserify \
--standalone deku \
- -t envify \
- -e lib/index.js | bfc > build/deku.js
+ -t babelify \
+ -e src/index.js > dist/deku.js
-test: $(src) $(tests)
- @NODE_ENV=development hihat test/index.js -- \
+test: lint
+ @NODE_ENV=development ${BIN}/hihat test/index.js -- \
--debug \
- -t envify \
-t babelify \
-p tap-dev-tool
-test-cloud: node_modules
- @TRAVIS_BUILD_NUMBER=$(CIRCLE_BUILD_NUM) zuul -- ./test/index.js
+ci: node_modules lint
+ @TRAVIS_BUILD_NUMBER=$(CIRCLE_BUILD_NUM) ${BIN}/zuul -- ./test/index.js
node_modules: package.json
@npm install
-clean:
- @-rm -rf build build.js node_modules
-
lint: $(src) $(tests)
- standard lib/**/*.js | snazzy
-
-size: standalone
- @minify build/deku.js | gzip -9 | wc -c
-
-#
-# Releases.
-#
+ ${BIN}/standard src/*.js test/*.js | ${BIN}/snazzy
-release: standalone
- bump $$VERSION && \
- git changelog --tag $$VERSION && \
- git commit --all -m "Release $$VERSION" && \
- git tag $$VERSION && \
- git push origin master --tags && \
- npm publish
+docs:
+ gitbook serve
#
-# These tasks will be run every time regardless of dependencies.
+# Always run these tasks.
#
-.PHONY: standalone
-.PHONY: clean
-.PHONY: lint
-.PHONY: size
-.PHONY: release
-.PHONY: test-cloud
+.PHONY: build
+.PHONY: docs
diff --git a/README.md b/README.md
index 01aa084..c9e1d61 100644
--- a/README.md
+++ b/README.md
@@ -1,207 +1,63 @@
-# Deku
+# Deku [](https://circleci.com/gh/dekujs/deku/tree/2.0.0)
-[](https://www.npmjs.com/package/deku) [](https://circleci.com/gh/dekujs/deku) [](https://github.com/feross/standard) [](https://discord.gg/0gNkyCAVkDYsBaFe)
+[](https://www.npmjs.com/package/deku)
+[](https://github.com/feross/standard)
+[](https://www.npmjs.com/package/deku)
-A library for creating UI components using virtual DOM as an alternative to [React](https://github.com/facebook/react). Deku has a smaller footprint (~6kb), a functional API, and doesn't support legacy browsers.
+Deku is a library for rendering interfaces using pure functions.
-```
-npm install deku virtual-element
-```
-
-You can also use Duo, Bower or [download the files manually](https://github.com/dekujs/deku/releases).
-
-## Example
-
-```js
-import element from 'virtual-element'
-import {render,tree} from 'deku'
-import MyButton from './button'
-
-var app = tree(
-
- Hello World!
-
-)
-
-render(app, document.body)
-```
+Instead of using classes and local state, Deku just uses functions and pushes the responsibility of all state management and side-effects onto tools like [Redux](http://redux.js.org/). It also aims to support only modern browsers to keep things simple.
-## Introduction
+It can be used in place of libraries like React and works well with Redux and other libraries in the React ecosystem.
-Deku is a DOM renderer for virtual elements that also allows us to define custom element types. It runs diffing algorithm on these virtual elements to update the real DOM in a performant way.
+Deku consists of 4 modules packaged together for convenience:
-**Heads up:** These examples are written using ES2015 syntax. You'll want to make sure you're familiar with [modules](https://babeljs.io/docs/learn-es2015/#modules) and [destructuring](https://babeljs.io/docs/learn-es2015/#destructuring) to follow along.
+* `element`: Creating virtual elements
+* `diff`: Computing the difference between two virtual elements
+* `dom`: DOM renderer
+* `string`: HTML string renderer
-Virtual elements are plain objects that represent real DOM elements:
+### Installation
-```js
-{
- type: 'button',
- attributes: { class: 'Button' },
- children: props.children
-}
```
-
-Which can then be rendered by Deku to the DOM. This example will render a button to the `document.body` with a class of `Button`:
-
-```js
-import {render,tree} from 'deku'
-
-var button = {
- type: 'button',
- attributes: { class: 'Button' }
-}
-
-// Create an app
-var app = tree(button)
-
-// Automatically re-renders the app when state changes
-render(app, document.body)
+npm install --save deku
```
-You can define your own custom elements that can contain their own state. These are called **components**. Components are objects that (at the very least) have a render function. This render function is passed in a component object with these properties:
-
-* `props`: This is any external data
-* `state`: This is any internal data that is hidden from the world
-* `id`: The instance id of the component
-
-Here's an example `App` component that renders a paragraph:
-
-```js
-import {render,tree} from 'deku'
-
-// Define our custom element. The render method should
-// return a new virtual element.
-var App = {
- render: function ({ props, state }) {
- return {
- type: 'p',
- attributes: { color: props.color }
- }
- }
-}
-
-// Then create a virtual element with our custom type
-var app = tree({
- type: App, // <- custom type instead of a string
- attributes: { color: 'red' } // <- these become 'props'
-})
-
-// And render it to the DOM
-render(app, document.body)
-```
-
-## Virtual Elements
-
-But these virtual elements aren't very easy to read. The good news is that you can use other libraries to add a DSL for creating these objects:
-
-* [virtual-element](https://github.com/dekujs/virtual-element)
-* [magic-virtual-element](https://github.com/dekujs/magic-virtual-element)
-
-So you can use the `virtual-element` module to easily create these objects instead:
+We support the latest two versions of each browser. This means we only support IE10+.
-```js
-element('div', { class: "App" }, [
- element('button', { class: "Button" }, 'Click Me!')
-])
-```
-
-And if you're using `virtual-element` [you can also use JSX](https://github.com/dekujs/deku/blob/master/docs/guides/jsx.md) to make rendering nodes more developer friendly. This is equivalent to the previous example:
-
-```jsx
-
-
-
-```
-
-JSX might seem offensive at first, but if you're already using Babel you get JSX for free. Think of it as a more familiar way to define tree structures. **The rest of the examples will assume we're using JSX.** You can go ahead and imagine the same syntax using the `virtual-element` DSL or the raw object format.
+[](https://saucelabs.com/u/deku)
-So the previous app example would look like this using JSX (notice that we're importing the `virtual-element` module this time):
+### Example
```js
-import element from 'virtual-element'
-import {render,tree} from 'deku'
+import {dom, element} from 'deku'
+import {createStore} from 'redux'
+import reducer from './reducer'
-// Define our custom element
-var App = {
- render: function ({ props }) {
- return
Hello World
- }
-}
-
-var app = tree()
-
-// And render it to the DOM
-render(app, document.body)
-```
+// Create a Redux store to handle actions and side-effects
+let store = createStore(reducer)
-## Custom Elements
-
-So now we can start defining components in their own module and export them. Let's create a custom button element:
-
-```js
-// button.js
-import element from 'virtual-element'
+// Create a renderer that can turn vnodes into real DOM elements
+let render = dom.createRenderer(document.body, store.dispatch)
+// Define a state-less component
let MyButton = {
- render ({props}) {
- return
- }
+ render: ({ props, children }) {
+ return
+ }
}
-export {MyButton}
-```
-
-Then we can import it and render it in the same way:
-
-```js
-// app.js
-import element from 'virtual-element'
-import {MyButton} from './button'
-import {render,tree} from 'deku'
-
-// We're using our custom MyButton element
-var app = tree(
-
- Hello World!
-
+// Update the page and add redux state to the context
+render(
+ Hello World!,
+ store.getState()
)
-
-render(app, document.body)
```
-You can also render these same elements and custom elements on the server using `renderString` instead of `render`:
+### Documentation
-```js
-// server.js
-import element from 'virtual-element'
-import {MyButton} from './button'
-import {renderString,tree} from 'deku'
-
-let html = renderString(tree(
-
- Hello World!
-
-))
-```
-
-That's all there is to it. Components can also have [hook functions](https://github.com/dekujs/deku/blob/master/docs/guides/components.md) so you can do some work when they are created, removed or updated, and you can [add state](https://github.com/dekujs/deku/blob/master/docs/guides/components.md) to your components.
-
-## Next steps
-
-* [Installing](https://github.com/dekujs/deku/blob/master/docs/guides/install.md)
-* [Component API](https://github.com/dekujs/deku/blob/master/docs/guides/components.md)
-* [Using JSX](https://github.com/dekujs/deku/blob/master/docs/guides/jsx.md)
-* [Client + Server Rendering Example](https://github.com/dekujs/todomvc)
-* [Community resources](https://github.com/stevenmiller888/awesome-deku)
-* [Contributing to Deku](https://github.com/dekujs/deku/blob/master/docs/guides/development.md)
-
-## Tests
-
-Deku is built with Browserify. You can run the tests in a browser by running `make test`. Learn how to build and work on Deku [in the documentation](https://github.com/dekujs/deku/blob/master/docs/guides/development.md).
-
-[](https://saucelabs.com/u/deku)
+You can [read the documentation online](https://anthonyshort.gitbooks.io/dekujs/content/) at Gitbook.
-## License
+### License
The MIT License (MIT) Copyright (c) 2015 Anthony Short
diff --git a/book.json b/book.json
index 9e26dfe..507d0d7 100644
--- a/book.json
+++ b/book.json
@@ -1 +1,18 @@
-{}
\ No newline at end of file
+{
+ "gitbook": "2.x.x",
+ "title": "Deku",
+ "description": "Learn how to use Deku",
+ "structure": {
+ "summary": "docs/README.md"
+ },
+ "plugins": ["edit-link", "prism", "-highlight", "github"],
+ "pluginsConfig": {
+ "edit-link": {
+ "base": "https://github.com/dekujs/deku/tree/master",
+ "label": "Edit This Page"
+ },
+ "github": {
+ "url": "https://github.com/dekujs/deku/"
+ }
+ }
+}
diff --git a/build/deku.js b/build/deku.js
deleted file mode 100644
index e9c413c..0000000
--- a/build/deku.js
+++ /dev/null
@@ -1,4333 +0,0 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.deku = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof _require=="function"&&_require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof _require=="function"&&_require;for(var o=0;o 0) {
- console.info('deku: The container element is not empty. These elements will be removed. Read more: http://cl.ly/b0Sr')
- }
- if (container === document.body) {
- console.warn('deku: Using document.body is allowed but it can cause some issues. Read more: http://cl.ly/b0SC')
- }
- removeAllChildren(container)
- container.appendChild(currentNativeElement)
- } else if (currentElement !== app.element) {
- currentNativeElement = patch(rootId, currentElement, app.element, currentNativeElement)
- currentElement = app.element
- updateChildren(rootId)
- } else {
- updateChildren(rootId)
- }
-
- // Call mount events on all new entities
- flushMountQueue()
-
- // Allow rendering again.
- isRendering = false
- }
-
- /**
- * Call hooks for all new entities that have been created in
- * the last render from the bottom up.
- */
-
- function flushMountQueue () {
- while (mountQueue.length > 0) {
- var entityId = mountQueue.shift()
- var entity = entities[entityId]
- trigger('afterRender', entity, [entity.context, entity.nativeElement])
- trigger('afterMount', entity, [entity.context, entity.nativeElement, setState(entity)])
- }
- }
-
- /**
- * Clear the current scheduled frame
- */
-
- function clearFrame () {
- if (!frameId) return
- raf.cancel(frameId)
- frameId = 0
- }
-
- /**
- * Update a component.
- *
- * The entity is just the data object for a component instance.
- *
- * @param {String} id Component instance id.
- */
-
- function updateEntity (entityId) {
- var entity = entities[entityId]
- setSources(entity)
-
- if (!shouldUpdate(entity)) {
- commit(entity)
- return updateChildren(entityId)
- }
-
- var currentTree = entity.virtualElement
- var nextProps = entity.pendingProps
- var nextState = entity.pendingState
- var previousState = entity.context.state
- var previousProps = entity.context.props
-
- // hook before rendering. could modify state just before the render occurs.
- trigger('beforeUpdate', entity, [entity.context, nextProps, nextState])
- trigger('beforeRender', entity, [entity.context])
-
- // commit state and props.
- commit(entity)
-
- // re-render.
- var nextTree = renderEntity(entity)
-
- // if the tree is the same we can just skip this component
- // but we should still check the children to see if they're dirty.
- // This allows us to memoize the render function of components.
- if (nextTree === currentTree) return updateChildren(entityId)
-
- // apply new virtual tree to native dom.
- entity.nativeElement = patch(entityId, currentTree, nextTree, entity.nativeElement)
- entity.virtualElement = nextTree
- updateChildren(entityId)
-
- // trigger render hook
- trigger('afterRender', entity, [entity.context, entity.nativeElement])
-
- // trigger afterUpdate after all children have updated.
- trigger('afterUpdate', entity, [entity.context, previousProps, previousState, setState(entity)])
- }
-
- /**
- * Update all the children of an entity.
- *
- * @param {String} id Component instance id.
- */
-
- function updateChildren (entityId) {
- forEach(children[entityId], function (childId) {
- updateEntity(childId)
- })
- }
-
- /**
- * Remove all of the child entities of an entity
- *
- * @param {Entity} entity
- */
-
- function unmountChildren (entityId) {
- forEach(children[entityId], function (childId) {
- unmountEntity(childId)
- })
- }
-
- /**
- * Remove the root element. If this is called synchronously we need to
- * cancel any pending future updates.
- */
-
- function removeNativeElement () {
- clearFrame()
- removeElement(rootId, '0', currentNativeElement)
- currentNativeElement = null
- }
-
- /**
- * Create a native element from a virtual element.
- *
- * @param {String} entityId
- * @param {String} path
- * @param {Object} vnode
- *
- * @return {HTMLDocumentFragment}
- */
-
- function toNative (entityId, path, vnode) {
- switch (nodeType(vnode)) {
- case 'text': return toNativeText(vnode)
- case 'empty': return toNativeEmptyElement(entityId, path)
- case 'element': return toNativeElement(entityId, path, vnode)
- case 'component': return toNativeComponent(entityId, path, vnode)
- }
- }
-
- /**
- * Create a native text element from a virtual element.
- *
- * @param {Object} vnode
- */
-
- function toNativeText (text) {
- return document.createTextNode(text)
- }
-
- /**
- * Create a native element from a virtual element.
- */
-
- function toNativeElement (entityId, path, vnode) {
- var el
- var attributes = vnode.attributes
- var tagName = vnode.type
- var childNodes = vnode.children
-
- // create element either from pool or fresh.
- if (svg.isElement(tagName)) {
- el = document.createElementNS(svg.namespace, tagName)
- } else {
- el = document.createElement(tagName)
- }
-
- // set attributes.
- forEach(attributes, function (value, name) {
- setAttribute(entityId, path, el, name, value)
- })
-
- // add children.
- forEach(childNodes, function (child, i) {
- var childEl = toNative(entityId, path + '.' + i, child)
- if (!childEl.parentNode) el.appendChild(childEl)
- })
-
- // store keys on the native element for fast event handling.
- el.__entity__ = entityId
- el.__path__ = path
-
- return el
- }
-
- /**
- * Create a native element from a virtual element.
- */
-
- function toNativeEmptyElement (entityId, path) {
- var el = document.createElement('noscript')
- el.__entity__ = entityId
- el.__path__ = path
- return el
- }
-
- /**
- * Create a native element from a component.
- */
-
- function toNativeComponent (entityId, path, vnode) {
- var child = new Entity(vnode.type, assign({ children: vnode.children }, vnode.attributes), entityId)
- children[entityId][path] = child.id
- return mountEntity(child)
- }
-
- /**
- * Patch an element with the diff from two trees.
- */
-
- function patch (entityId, prev, next, el) {
- return diffNode('0', entityId, prev, next, el)
- }
-
- /**
- * Create a diff between two trees of nodes.
- */
-
- function diffNode (path, entityId, prev, next, el) {
- var leftType = nodeType(prev)
- var rightType = nodeType(next)
-
- // Type changed. This could be from element->text, text->ComponentA,
- // ComponentA->ComponentB etc. But NOT div->span. These are the same type
- // (ElementNode) but different tag name.
- if (leftType !== rightType) return replaceElement(entityId, path, el, next)
-
- switch (rightType) {
- case 'text': return diffText(prev, next, el)
- case 'empty': return el
- case 'element': return diffElement(path, entityId, prev, next, el)
- case 'component': return diffComponent(path, entityId, prev, next, el)
- }
- }
-
- /**
- * Diff two text nodes and update the element.
- */
-
- function diffText (previous, current, el) {
- if (current !== previous) el.data = current
- return el
- }
-
- /**
- * Diff the children of an ElementNode.
- */
-
- function diffChildren (path, entityId, prev, next, el) {
- var positions = []
- var hasKeys = false
- var childNodes = Array.prototype.slice.apply(el.childNodes)
- var leftKeys = reduce(prev.children, keyMapReducer, {})
- var rightKeys = reduce(next.children, keyMapReducer, {})
- var currentChildren = assign({}, children[entityId])
-
- function keyMapReducer (acc, child, i) {
- if (child && child.attributes && child.attributes.key != null) {
- acc[child.attributes.key] = {
- element: child,
- index: i
- }
- hasKeys = true
- }
- return acc
- }
-
- // Diff all of the nodes that have keys. This lets us re-used elements
- // instead of overriding them and lets us move them around.
- if (hasKeys) {
- // Removals
- forEach(leftKeys, function (leftNode, key) {
- if (rightKeys[key] == null) {
- var leftPath = path + '.' + leftNode.index
- removeElement(
- entityId,
- leftPath,
- childNodes[leftNode.index]
- )
- }
- })
-
- // Update nodes
- forEach(rightKeys, function (rightNode, key) {
- var leftNode = leftKeys[key]
-
- // We only want updates for now
- if (leftNode == null) return
-
- var leftPath = path + '.' + leftNode.index
-
- // Updated
- positions[rightNode.index] = diffNode(
- leftPath,
- entityId,
- leftNode.element,
- rightNode.element,
- childNodes[leftNode.index]
- )
- })
-
- // Update the positions of all child components and event handlers
- forEach(rightKeys, function (rightNode, key) {
- var leftNode = leftKeys[key]
-
- // We just want elements that have moved around
- if (leftNode == null || leftNode.index === rightNode.index) return
-
- var rightPath = path + '.' + rightNode.index
- var leftPath = path + '.' + leftNode.index
-
- // Update all the child component path positions to match
- // the latest positions if they've changed. This is a bit hacky.
- forEach(currentChildren, function (childId, childPath) {
- if (leftPath === childPath) {
- delete children[entityId][childPath]
- children[entityId][rightPath] = childId
- }
- })
- })
-
- // Now add all of the new nodes last in case their path
- // would have conflicted with one of the previous paths.
- forEach(rightKeys, function (rightNode, key) {
- var rightPath = path + '.' + rightNode.index
- if (leftKeys[key] == null) {
- positions[rightNode.index] = toNative(
- entityId,
- rightPath,
- rightNode.element
- )
- }
- })
- } else {
- var maxLength = Math.max(prev.children.length, next.children.length)
- // Now diff all of the nodes that don't have keys
- for (var i = 0; i < maxLength; i++) {
- var leftNode = prev.children[i]
- var rightNode = next.children[i]
-
- // Removals
- if (rightNode === undefined) {
- removeElement(
- entityId,
- path + '.' + i,
- childNodes[i]
- )
- continue
- }
-
- // New Node
- if (leftNode === undefined) {
- positions[i] = toNative(
- entityId,
- path + '.' + i,
- rightNode
- )
- continue
- }
-
- // Updated
- positions[i] = diffNode(
- path + '.' + i,
- entityId,
- leftNode,
- rightNode,
- childNodes[i]
- )
- }
- }
-
- // Reposition all the elements
- forEach(positions, function (childEl, newPosition) {
- var target = el.childNodes[newPosition]
- if (childEl && childEl !== target) {
- if (target) {
- el.insertBefore(childEl, target)
- } else {
- el.appendChild(childEl)
- }
- }
- })
- }
-
- /**
- * Diff the attributes and add/remove them.
- */
-
- function diffAttributes (prev, next, el, entityId, path) {
- var nextAttrs = next.attributes
- var prevAttrs = prev.attributes
-
- // add new attrs
- forEach(nextAttrs, function (value, name) {
- if (events[name] || !(name in prevAttrs) || prevAttrs[name] !== value) {
- setAttribute(entityId, path, el, name, value)
- }
- })
-
- // remove old attrs
- forEach(prevAttrs, function (value, name) {
- if (!(name in nextAttrs)) {
- removeAttribute(entityId, path, el, name)
- }
- })
- }
-
- /**
- * Update a component with the props from the next node. If
- * the component type has changed, we'll just remove the old one
- * and replace it with the new component.
- */
-
- function diffComponent (path, entityId, prev, next, el) {
- if (next.type !== prev.type) {
- return replaceElement(entityId, path, el, next)
- } else {
- var targetId = children[entityId][path]
-
- // This is a hack for now
- if (targetId) {
- updateEntityProps(targetId, assign({ children: next.children }, next.attributes))
- }
-
- return el
- }
- }
-
- /**
- * Diff two element nodes.
- */
-
- function diffElement (path, entityId, prev, next, el) {
- if (next.type !== prev.type) return replaceElement(entityId, path, el, next)
- diffAttributes(prev, next, el, entityId, path)
- diffChildren(path, entityId, prev, next, el)
- return el
- }
-
- /**
- * Removes an element from the DOM and unmounts and components
- * that are within that branch
- *
- * side effects:
- * - removes element from the DOM
- * - removes internal references
- *
- * @param {String} entityId
- * @param {String} path
- * @param {HTMLElement} el
- */
-
- function removeElement (entityId, path, el) {
- var childrenByPath = children[entityId]
- var childId = childrenByPath[path]
- var entityHandlers = handlers[entityId] || {}
- var removals = []
-
- // If the path points to a component we should use that
- // components element instead, because it might have moved it.
- if (childId) {
- var child = entities[childId]
- el = child.nativeElement
- unmountEntity(childId)
- removals.push(path)
- } else {
- // Just remove the text node
- if (!isElement(el)) return el && el.parentNode.removeChild(el)
- // Then we need to find any components within this
- // branch and unmount them.
- forEach(childrenByPath, function (childId, childPath) {
- if (childPath === path || isWithinPath(path, childPath)) {
- unmountEntity(childId)
- removals.push(childPath)
- }
- })
-
- // Remove all events at this path or below it
- forEach(entityHandlers, function (fn, handlerPath) {
- if (handlerPath === path || isWithinPath(path, handlerPath)) {
- removeEvent(entityId, handlerPath)
- }
- })
- }
-
- // Remove the paths from the object without touching the
- // old object. This keeps the object using fast properties.
- forEach(removals, function (path) {
- delete children[entityId][path]
- })
-
- // Remove it from the DOM
- el.parentNode.removeChild(el)
- }
-
- /**
- * Replace an element in the DOM. Removing all components
- * within that element and re-rendering the new virtual node.
- *
- * @param {Entity} entity
- * @param {String} path
- * @param {HTMLElement} el
- * @param {Object} vnode
- *
- * @return {void}
- */
-
- function replaceElement (entityId, path, el, vnode) {
- var parent = el.parentNode
- var index = Array.prototype.indexOf.call(parent.childNodes, el)
-
- // remove the previous element and all nested components. This
- // needs to happen before we create the new element so we don't
- // get clashes on the component paths.
- removeElement(entityId, path, el)
-
- // then add the new element in there
- var newEl = toNative(entityId, path, vnode)
- var target = parent.childNodes[index]
-
- if (target) {
- parent.insertBefore(newEl, target)
- } else {
- parent.appendChild(newEl)
- }
-
- // walk up the tree and update all `entity.nativeElement` references.
- if (entityId !== 'root' && path === '0') {
- updateNativeElement(entityId, newEl)
- }
-
- return newEl
- }
-
- /**
- * Update all entities in a branch that have the same nativeElement. This
- * happens when a component has another component as it's root node.
- *
- * @param {String} entityId
- * @param {HTMLElement} newEl
- *
- * @return {void}
- */
-
- function updateNativeElement (entityId, newEl) {
- var target = entities[entityId]
- if (target.ownerId === 'root') return
- if (children[target.ownerId]['0'] === entityId) {
- entities[target.ownerId].nativeElement = newEl
- updateNativeElement(target.ownerId, newEl)
- }
- }
-
- /**
- * Set the attribute of an element, performing additional transformations
- * dependning on the attribute name
- *
- * @param {HTMLElement} el
- * @param {String} name
- * @param {String} value
- */
-
- function setAttribute (entityId, path, el, name, value) {
- if (!value && typeof value !== 'number') {
- removeAttribute(entityId, path, el, name)
- return
- }
- if (events[name]) {
- addEvent(entityId, path, events[name], value)
- return
- }
- switch (name) {
- case 'checked':
- case 'disabled':
- case 'selected':
- el[name] = true
- break
- case 'innerHTML':
- el.innerHTML = value
- break
- case 'value':
- setElementValue(el, value)
- break
- case svg.isAttribute(name):
- el.setAttributeNS(svg.namespace, name, value)
- break
- default:
- el.setAttribute(name, value)
- break
- }
- }
-
- /**
- * Remove an attribute, performing additional transformations
- * dependning on the attribute name
- *
- * @param {HTMLElement} el
- * @param {String} name
- */
-
- function removeAttribute (entityId, path, el, name) {
- if (events[name]) {
- removeEvent(entityId, path, events[name])
- return
- }
- switch (name) {
- case 'checked':
- case 'disabled':
- case 'selected':
- el[name] = false
- break
- case 'innerHTML':
- el.innerHTML = ''
- /* falls through */
- case 'value':
- setElementValue(el, null)
- break
- default:
- el.removeAttribute(name)
- break
- }
- }
-
- /**
- * Checks to see if one tree path is within
- * another tree path. Example:
- *
- * 0.1 vs 0.1.1 = true
- * 0.2 vs 0.3.5 = false
- *
- * @param {String} target
- * @param {String} path
- *
- * @return {Boolean}
- */
-
- function isWithinPath (target, path) {
- return path.indexOf(target + '.') === 0
- }
-
- /**
- * Is the DOM node an element node
- *
- * @param {HTMLElement} el
- *
- * @return {Boolean}
- */
-
- function isElement (el) {
- return !!(el && el.tagName)
- }
-
- /**
- * Remove all the child nodes from an element
- *
- * @param {HTMLElement} el
- */
-
- function removeAllChildren (el) {
- while (el.firstChild) el.removeChild(el.firstChild)
- }
-
- /**
- * Trigger a hook on a component.
- *
- * @param {String} name Name of hook.
- * @param {Entity} entity The component instance.
- * @param {Array} args To pass along to hook.
- */
-
- function trigger (name, entity, args) {
- if (typeof entity.component[name] !== 'function') return
- return entity.component[name].apply(null, args)
- }
-
- /**
- * Update an entity to match the latest rendered vode. We always
- * replace the props on the component when composing them. This
- * will trigger a re-render on all children below this point.
- *
- * @param {Entity} entity
- * @param {String} path
- * @param {Object} vnode
- *
- * @return {void}
- */
-
- function updateEntityProps (entityId, nextProps) {
- var entity = entities[entityId]
- entity.pendingProps = defaults({}, nextProps, entity.component.defaultProps || {})
- entity.dirty = true
- invalidate()
- }
-
- /**
- * Update component instance state.
- */
-
- function updateEntityState (entity, nextState) {
- entity.pendingState = assign(entity.pendingState, nextState)
- entity.dirty = true
- invalidate()
- }
-
- /**
- * Commit props and state changes to an entity.
- */
-
- function commit (entity) {
- entity.context = {
- state: entity.pendingState,
- props: entity.pendingProps,
- id: entity.id
- }
- entity.pendingState = assign({}, entity.context.state)
- entity.pendingProps = assign({}, entity.context.props)
- entity.dirty = false
- if (typeof entity.component.validate === 'function') {
- entity.component.validate(entity.context)
- }
- }
-
- /**
- * Try to avoid creating new virtual dom if possible.
- *
- * Later we may expose this so you can override, but not there yet.
- */
-
- function shouldUpdate (entity) {
- if (!entity.dirty) return false
- if (!entity.component.shouldUpdate) return true
- var nextProps = entity.pendingProps
- var nextState = entity.pendingState
- var bool = entity.component.shouldUpdate(entity.context, nextProps, nextState)
- return bool
- }
-
- /**
- * Register an entity.
- *
- * This is mostly to pre-preprocess component properties and values chains.
- *
- * The end result is for every component that gets mounted,
- * you create a set of IO nodes in the network from the `value` definitions.
- *
- * @param {Component} component
- */
-
- function register (entity) {
- registerEntity(entity)
- var component = entity.component
- if (component.registered) return
-
- // initialize sources once for a component type.
- registerSources(entity)
- component.registered = true
- }
-
- /**
- * Add entity to data-structures related to components/entities.
- *
- * @param {Entity} entity
- */
-
- function registerEntity (entity) {
- var component = entity.component
- // all entities for this component type.
- var entities = component.entities = component.entities || {}
- // add entity to component list
- entities[entity.id] = entity
- // map to component so you can remove later.
- components[entity.id] = component
- }
-
- /**
- * Initialize sources for a component by type.
- *
- * @param {Entity} entity
- */
-
- function registerSources (entity) {
- var component = components[entity.id]
- // get 'class-level' sources.
- // if we've already hooked it up, then we're good.
- var sources = component.sources
- if (sources) return
- var entities = component.entities
-
- // hook up sources.
- var map = component.sourceToPropertyName = {}
- component.sources = sources = []
- var propTypes = component.propTypes
- for (var name in propTypes) {
- var data = propTypes[name]
- if (!data) continue
- if (!data.source) continue
- sources.push(data.source)
- map[data.source] = name
- }
-
- // send value updates to all component instances.
- sources.forEach(function (source) {
- connections[source] = connections[source] || []
- connections[source].push(update)
-
- function update (data) {
- var prop = map[source]
- for (var entityId in entities) {
- var entity = entities[entityId]
- var changes = {}
- changes[prop] = data
- updateEntityProps(entityId, assign(entity.pendingProps, changes))
- }
- }
- })
- }
-
- /**
- * Set the initial source value on the entity
- *
- * @param {Entity} entity
- */
-
- function setSources (entity) {
- var component = entity.component
- var map = component.sourceToPropertyName
- var sources = component.sources
- sources.forEach(function (source) {
- var name = map[source]
- if (entity.pendingProps[name] != null) return
- entity.pendingProps[name] = app.sources[source] // get latest value plugged into global store
- })
- }
-
- /**
- * Add all of the DOM event listeners
- */
-
- function addNativeEventListeners () {
- forEach(events, function (eventType) {
- rootElement.addEventListener(eventType, handleEvent, true)
- })
- }
-
- /**
- * Add all of the DOM event listeners
- */
-
- function removeNativeEventListeners () {
- forEach(events, function (eventType) {
- rootElement.removeEventListener(eventType, handleEvent, true)
- })
- }
-
- /**
- * Handle an event that has occured within the container
- *
- * @param {Event} event
- */
-
- function handleEvent (event) {
- var target = event.target
- var eventType = event.type
-
- // Walk up the DOM tree and see if there is a handler
- // for this event type higher up.
- while (target) {
- var fn = keypath.get(handlers, [target.__entity__, target.__path__, eventType])
- if (fn) {
- event.delegateTarget = target
- if (fn(event) === false) break
- }
- target = target.parentNode
- }
- }
-
- /**
- * Bind events for an element, and all it's rendered child elements.
- *
- * @param {String} path
- * @param {String} event
- * @param {Function} fn
- */
-
- function addEvent (entityId, path, eventType, fn) {
- keypath.set(handlers, [entityId, path, eventType], function (e) {
- var entity = entities[entityId]
- if (entity) {
- return fn(e, entity.context, setState(entity))
- } else {
- return fn(e)
- }
- })
- }
-
- /**
- * Unbind events for a entityId
- *
- * @param {String} entityId
- */
-
- function removeEvent (entityId, path, eventType) {
- var args = [entityId]
- if (path) args.push(path)
- if (eventType) args.push(eventType)
- keypath.del(handlers, args)
- }
-
- /**
- * Unbind all events from an entity
- *
- * @param {Entity} entity
- */
-
- function removeAllEvents (entityId) {
- keypath.del(handlers, [entityId])
- }
-
- /**
- * Used for debugging to inspect the current state without
- * us needing to explicitly manage storing/updating references.
- *
- * @return {Object}
- */
-
- function inspect () {
- return {
- entities: entities,
- handlers: handlers,
- connections: connections,
- currentElement: currentElement,
- options: options,
- app: app,
- container: container,
- children: children
- }
- }
-
- /**
- * Return an object that lets us completely remove the automatic
- * DOM rendering and export debugging tools.
- */
-
- return {
- remove: teardown,
- inspect: inspect
- }
-}
-
-/**
- * A rendered component instance.
- *
- * This manages the lifecycle, props and state of the component.
- * It's basically just a data object for more straightfoward lookup.
- *
- * @param {Component} component
- * @param {Object} props
- */
-
-function Entity (component, props, ownerId) {
- this.id = uid()
- this.ownerId = ownerId
- this.component = component
- this.propTypes = component.propTypes || {}
- this.context = {}
- this.context.id = this.id
- this.context.props = defaults(props || {}, component.defaultProps || {})
- this.context.state = this.component.initialState ? this.component.initialState(this.context.props) : {}
- this.pendingProps = assign({}, this.context.props)
- this.pendingState = assign({}, this.context.state)
- this.dirty = false
- this.virtualElement = null
- this.nativeElement = null
- this.displayName = component.name || 'Component'
-}
-
-/**
- * Retrieve the nearest 'body' ancestor of the given element or else the root
- * element of the document in which stands the given element.
- *
- * This is necessary if you want to attach the events handler to the correct
- * element and be able to dispatch events in document fragments such as
- * Shadow DOM.
- *
- * @param {HTMLElement} el The element on which we will render an app.
- * @return {HTMLElement} The root element on which we will attach the events
- * handler.
- */
-
-function getRootElement (el) {
- while (el.parentElement) {
- if (el.tagName === 'BODY' || !el.parentElement) {
- return el
- }
- el = el.parentElement
- }
- return el
-}
-
-/**
- * Set the value property of an element and keep the text selection
- * for input fields.
- *
- * @param {HTMLElement} el
- * @param {String} value
- */
-
-function setElementValue (el, value) {
- if (el === document.activeElement && canSelectText(el)) {
- var start = el.selectionStart
- var end = el.selectionEnd
- el.value = value
- el.setSelectionRange(start, end)
- } else {
- el.value = value
- }
-}
-
-/**
- * For some reason only certain types of inputs can set the selection range.
- *
- * @param {HTMLElement} el
- *
- * @return {Boolean}
- */
-
-function canSelectText (el) {
- return el.tagName === 'INPUT' && ['text', 'search', 'password', 'tel', 'url'].indexOf(el.type) > -1
-}
-
-},{"./events":2,"./node-type":4,"./svg":7,"component-raf":13,"fast.js/forEach":17,"fast.js/object/assign":20,"fast.js/reduce":23,"get-uid":24,"is-dom":25,"object-defaults":28,"object-path":29}],6:[function(_require,module,exports){
-var defaults = _require('object-defaults')
-var nodeType = _require('./node-type')
-var type = _require('component-type')
-
-/**
- * Expose `stringify`.
- */
-
-module.exports = function (app) {
- if (!app.element) {
- throw new Error('No element mounted')
- }
-
- /**
- * Render to string.
- *
- * @param {Component} component
- * @param {Object} [props]
- * @return {String}
- */
-
- function stringify (component, optProps, children) {
- var propTypes = component.propTypes || {}
- var props = defaults(optProps || {}, component.defaultProps || {})
- var state = component.initialState ? component.initialState(props) : {}
- props.children = children
-
- for (var name in propTypes) {
- var options = propTypes[name]
- if (options.source) {
- props[name] = app.sources[options.source]
- }
- }
-
- if (component.beforeMount) component.beforeMount({ props: props, state: state })
- if (component.beforeRender) component.beforeRender({ props: props, state: state })
- var node = component.render({ props: props, state: state })
- return stringifyNode(node, '0')
- }
-
- /**
- * Render a node to a string
- *
- * @param {Node} node
- * @param {Tree} tree
- *
- * @return {String}
- */
-
- function stringifyNode (node, path) {
- switch (nodeType(node)) {
- case 'empty': return ''
- case 'text': return node
- case 'element':
- var children = node.children
- var attributes = node.attributes
- var tagName = node.type
- var innerHTML = attributes.innerHTML
- var str = '<' + tagName + attrs(attributes) + '>'
-
- if (innerHTML) {
- str += innerHTML
- } else {
- for (var i = 0, n = children.length; i < n; i++) {
- str += stringifyNode(children[i], path + '.' + i)
- }
- }
-
- str += '' + tagName + '>'
- return str
- case 'component': return stringify(node.type, node.attributes, node.children)
- }
-
- throw new Error('Invalid type')
- }
-
- return stringifyNode(app.element, '0')
-}
-
-/**
- * HTML attributes to string.
- *
- * @param {Object} attributes
- * @return {String}
- * @api private
- */
-
-function attrs (attributes) {
- var str = ''
- for (var key in attributes) {
- var value = attributes[key]
- if (key === 'innerHTML') continue
- if (isValidAttributeValue(value)) str += attr(key, attributes[key])
- }
- return str
-}
-
-/**
- * HTML attribute to string.
- *
- * @param {String} key
- * @param {String} val
- * @return {String}
- * @api private
- */
-
-function attr (key, val) {
- return ' ' + key + '="' + val + '"'
-}
-
-/**
- * Is a value able to be set a an attribute value?
- *
- * @param {Any} value
- *
- * @return {Boolean}
- */
-
-function isValidAttributeValue (value) {
- var valueType = type(value)
- switch (valueType) {
- case 'string':
- case 'number':
- return true
-
- case 'boolean':
- return value
-
- default:
- return false
- }
-}
-
-},{"./node-type":4,"component-type":14,"object-defaults":28}],7:[function(_require,module,exports){
-module.exports = {
- isElement: _require('is-svg-element').isElement,
- isAttribute: _require('is-svg-attribute'),
- namespace: 'http://www.w3.org/2000/svg'
-}
-
-},{"is-svg-attribute":26,"is-svg-element":27}],8:[function(_require,module,exports){
-(function (global){
-/*!
- * The buffer module from node.js, for the browser.
- *
- * @author Feross Aboukhadijeh
- * @license MIT
- */
-/* eslint-disable no-proto */
-
-var base64 = _require('base64-js')
-var ieee754 = _require('ieee754')
-var isArray = _require('is-array')
-
-exports.Buffer = Buffer
-exports.SlowBuffer = SlowBuffer
-exports.INSPECT_MAX_BYTES = 50
-Buffer.poolSize = 8192 // not used by this implementation
-
-var rootParent = {}
-
-/**
- * If `Buffer.TYPED_ARRAY_SUPPORT`:
- * === true Use Uint8Array implementation (fastest)
- * === false Use Object implementation (most compatible, even IE6)
- *
- * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
- * Opera 11.6+, iOS 4.2+.
- *
- * Due to various browser bugs, sometimes the Object implementation will be used even
- * when the browser supports typed arrays.
- *
- * Note:
- *
- * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
- * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
- *
- * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property
- * on objects.
- *
- * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
- *
- * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
- * incorrect length in some situations.
-
- * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
- * get the Object implementation, which is slower but behaves correctly.
- */
-Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
- ? global.TYPED_ARRAY_SUPPORT
- : typedArraySupport()
-
-function typedArraySupport () {
- function Bar () {}
- try {
- var arr = new Uint8Array(1)
- arr.foo = function () { return 42 }
- arr.constructor = Bar
- return arr.foo() === 42 && // typed array instances can be augmented
- arr.constructor === Bar && // constructor can be set
- typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
- arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
- } catch (e) {
- return false
- }
-}
-
-function kMaxLength () {
- return Buffer.TYPED_ARRAY_SUPPORT
- ? 0x7fffffff
- : 0x3fffffff
-}
-
-/**
- * Class: Buffer
- * =============
- *
- * The Buffer constructor returns instances of `Uint8Array` that are augmented
- * with function properties for all the node `Buffer` API functions. We use
- * `Uint8Array` so that square bracket notation works as expected -- it returns
- * a single octet.
- *
- * By augmenting the instances, we can avoid modifying the `Uint8Array`
- * prototype.
- */
-function Buffer (arg) {
- if (!(this instanceof Buffer)) {
- // Avoid going through an ArgumentsAdaptorTrampoline in the common case.
- if (arguments.length > 1) return new Buffer(arg, arguments[1])
- return new Buffer(arg)
- }
-
- this.length = 0
- this.parent = undefined
-
- // Common case.
- if (typeof arg === 'number') {
- return fromNumber(this, arg)
- }
-
- // Slightly less common case.
- if (typeof arg === 'string') {
- return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')
- }
-
- // Unusual.
- return fromObject(this, arg)
-}
-
-function fromNumber (that, length) {
- that = allocate(that, length < 0 ? 0 : checked(length) | 0)
- if (!Buffer.TYPED_ARRAY_SUPPORT) {
- for (var i = 0; i < length; i++) {
- that[i] = 0
- }
- }
- return that
-}
-
-function fromString (that, string, encoding) {
- if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'
-
- // Assumption: byteLength() return value is always < kMaxLength.
- var length = byteLength(string, encoding) | 0
- that = allocate(that, length)
-
- that.write(string, encoding)
- return that
-}
-
-function fromObject (that, object) {
- if (Buffer.isBuffer(object)) return fromBuffer(that, object)
-
- if (isArray(object)) return fromArray(that, object)
-
- if (object == null) {
- throw new TypeError('must start with number, buffer, array or string')
- }
-
- if (typeof ArrayBuffer !== 'undefined') {
- if (object.buffer instanceof ArrayBuffer) {
- return fromTypedArray(that, object)
- }
- if (object instanceof ArrayBuffer) {
- return fromArrayBuffer(that, object)
- }
- }
-
- if (object.length) return fromArrayLike(that, object)
-
- return fromJsonObject(that, object)
-}
-
-function fromBuffer (that, buffer) {
- var length = checked(buffer.length) | 0
- that = allocate(that, length)
- buffer.copy(that, 0, 0, length)
- return that
-}
-
-function fromArray (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
-}
-
-// Duplicate of fromArray() to keep fromArray() monomorphic.
-function fromTypedArray (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
- // Truncating the elements is probably not what people expect from typed
- // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
- // of the old Buffer constructor.
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
-}
-
-function fromArrayBuffer (that, array) {
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- // Return an augmented `Uint8Array` instance, for best performance
- array.byteLength
- that = Buffer._augment(new Uint8Array(array))
- } else {
- // Fallback: Return an object instance of the Buffer class
- that = fromTypedArray(that, new Uint8Array(array))
- }
- return that
-}
-
-function fromArrayLike (that, array) {
- var length = checked(array.length) | 0
- that = allocate(that, length)
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
-}
-
-// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
-// Returns a zero-length buffer for inputs that don't conform to the spec.
-function fromJsonObject (that, object) {
- var array
- var length = 0
-
- if (object.type === 'Buffer' && isArray(object.data)) {
- array = object.data
- length = checked(array.length) | 0
- }
- that = allocate(that, length)
-
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
-}
-
-if (Buffer.TYPED_ARRAY_SUPPORT) {
- Buffer.prototype.__proto__ = Uint8Array.prototype
- Buffer.__proto__ = Uint8Array
-}
-
-function allocate (that, length) {
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- // Return an augmented `Uint8Array` instance, for best performance
- that = Buffer._augment(new Uint8Array(length))
- that.__proto__ = Buffer.prototype
- } else {
- // Fallback: Return an object instance of the Buffer class
- that.length = length
- that._isBuffer = true
- }
-
- var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1
- if (fromPool) that.parent = rootParent
-
- return that
-}
-
-function checked (length) {
- // Note: cannot use `length < kMaxLength` here because that fails when
- // length is NaN (which is otherwise coerced to zero.)
- if (length >= kMaxLength()) {
- throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
- 'size: 0x' + kMaxLength().toString(16) + ' bytes')
- }
- return length | 0
-}
-
-function SlowBuffer (subject, encoding) {
- if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)
-
- var buf = new Buffer(subject, encoding)
- delete buf.parent
- return buf
-}
-
-Buffer.isBuffer = function isBuffer (b) {
- return !!(b != null && b._isBuffer)
-}
-
-Buffer.compare = function compare (a, b) {
- if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
- throw new TypeError('Arguments must be Buffers')
- }
-
- if (a === b) return 0
-
- var x = a.length
- var y = b.length
-
- var i = 0
- var len = Math.min(x, y)
- while (i < len) {
- if (a[i] !== b[i]) break
-
- ++i
- }
-
- if (i !== len) {
- x = a[i]
- y = b[i]
- }
-
- if (x < y) return -1
- if (y < x) return 1
- return 0
-}
-
-Buffer.isEncoding = function isEncoding (encoding) {
- switch (String(encoding).toLowerCase()) {
- case 'hex':
- case 'utf8':
- case 'utf-8':
- case 'ascii':
- case 'binary':
- case 'base64':
- case 'raw':
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return true
- default:
- return false
- }
-}
-
-Buffer.concat = function concat (list, length) {
- if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')
-
- if (list.length === 0) {
- return new Buffer(0)
- }
-
- var i
- if (length === undefined) {
- length = 0
- for (i = 0; i < list.length; i++) {
- length += list[i].length
- }
- }
-
- var buf = new Buffer(length)
- var pos = 0
- for (i = 0; i < list.length; i++) {
- var item = list[i]
- item.copy(buf, pos)
- pos += item.length
- }
- return buf
-}
-
-function byteLength (string, encoding) {
- if (typeof string !== 'string') string = '' + string
-
- var len = string.length
- if (len === 0) return 0
-
- // Use a for loop to avoid recursion
- var loweredCase = false
- for (;;) {
- switch (encoding) {
- case 'ascii':
- case 'binary':
- // Deprecated
- case 'raw':
- case 'raws':
- return len
- case 'utf8':
- case 'utf-8':
- return utf8ToBytes(string).length
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return len * 2
- case 'hex':
- return len >>> 1
- case 'base64':
- return base64ToBytes(string).length
- default:
- if (loweredCase) return utf8ToBytes(string).length // assume utf8
- encoding = ('' + encoding).toLowerCase()
- loweredCase = true
- }
- }
-}
-Buffer.byteLength = byteLength
-
-// pre-set for values that may exist in the future
-Buffer.prototype.length = undefined
-Buffer.prototype.parent = undefined
-
-function slowToString (encoding, start, end) {
- var loweredCase = false
-
- start = start | 0
- end = end === undefined || end === Infinity ? this.length : end | 0
-
- if (!encoding) encoding = 'utf8'
- if (start < 0) start = 0
- if (end > this.length) end = this.length
- if (end <= start) return ''
-
- while (true) {
- switch (encoding) {
- case 'hex':
- return hexSlice(this, start, end)
-
- case 'utf8':
- case 'utf-8':
- return utf8Slice(this, start, end)
-
- case 'ascii':
- return asciiSlice(this, start, end)
-
- case 'binary':
- return binarySlice(this, start, end)
-
- case 'base64':
- return base64Slice(this, start, end)
-
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return utf16leSlice(this, start, end)
-
- default:
- if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
- encoding = (encoding + '').toLowerCase()
- loweredCase = true
- }
- }
-}
-
-Buffer.prototype.toString = function toString () {
- var length = this.length | 0
- if (length === 0) return ''
- if (arguments.length === 0) return utf8Slice(this, 0, length)
- return slowToString.apply(this, arguments)
-}
-
-Buffer.prototype.equals = function equals (b) {
- if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
- if (this === b) return true
- return Buffer.compare(this, b) === 0
-}
-
-Buffer.prototype.inspect = function inspect () {
- var str = ''
- var max = exports.INSPECT_MAX_BYTES
- if (this.length > 0) {
- str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
- if (this.length > max) str += ' ... '
- }
- return ''
-}
-
-Buffer.prototype.compare = function compare (b) {
- if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
- if (this === b) return 0
- return Buffer.compare(this, b)
-}
-
-Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
- if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff
- else if (byteOffset < -0x80000000) byteOffset = -0x80000000
- byteOffset >>= 0
-
- if (this.length === 0) return -1
- if (byteOffset >= this.length) return -1
-
- // Negative offsets start from the end of the buffer
- if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)
-
- if (typeof val === 'string') {
- if (val.length === 0) return -1 // special case: looking for empty string always fails
- return String.prototype.indexOf.call(this, val, byteOffset)
- }
- if (Buffer.isBuffer(val)) {
- return arrayIndexOf(this, val, byteOffset)
- }
- if (typeof val === 'number') {
- if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
- return Uint8Array.prototype.indexOf.call(this, val, byteOffset)
- }
- return arrayIndexOf(this, [ val ], byteOffset)
- }
-
- function arrayIndexOf (arr, val, byteOffset) {
- var foundIndex = -1
- for (var i = 0; byteOffset + i < arr.length; i++) {
- if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {
- if (foundIndex === -1) foundIndex = i
- if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex
- } else {
- foundIndex = -1
- }
- }
- return -1
- }
-
- throw new TypeError('val must be string, number or Buffer')
-}
-
-// `get` is deprecated
-Buffer.prototype.get = function get (offset) {
- console.log('.get() is deprecated. Access using array indexes instead.')
- return this.readUInt8(offset)
-}
-
-// `set` is deprecated
-Buffer.prototype.set = function set (v, offset) {
- console.log('.set() is deprecated. Access using array indexes instead.')
- return this.writeUInt8(v, offset)
-}
-
-function hexWrite (buf, string, offset, length) {
- offset = Number(offset) || 0
- var remaining = buf.length - offset
- if (!length) {
- length = remaining
- } else {
- length = Number(length)
- if (length > remaining) {
- length = remaining
- }
- }
-
- // must be an even number of digits
- var strLen = string.length
- if (strLen % 2 !== 0) throw new Error('Invalid hex string')
-
- if (length > strLen / 2) {
- length = strLen / 2
- }
- for (var i = 0; i < length; i++) {
- var parsed = parseInt(string.substr(i * 2, 2), 16)
- if (isNaN(parsed)) throw new Error('Invalid hex string')
- buf[offset + i] = parsed
- }
- return i
-}
-
-function utf8Write (buf, string, offset, length) {
- return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
-}
-
-function asciiWrite (buf, string, offset, length) {
- return blitBuffer(asciiToBytes(string), buf, offset, length)
-}
-
-function binaryWrite (buf, string, offset, length) {
- return asciiWrite(buf, string, offset, length)
-}
-
-function base64Write (buf, string, offset, length) {
- return blitBuffer(base64ToBytes(string), buf, offset, length)
-}
-
-function ucs2Write (buf, string, offset, length) {
- return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
-}
-
-Buffer.prototype.write = function write (string, offset, length, encoding) {
- // Buffer#write(string)
- if (offset === undefined) {
- encoding = 'utf8'
- length = this.length
- offset = 0
- // Buffer#write(string, encoding)
- } else if (length === undefined && typeof offset === 'string') {
- encoding = offset
- length = this.length
- offset = 0
- // Buffer#write(string, offset[, length][, encoding])
- } else if (isFinite(offset)) {
- offset = offset | 0
- if (isFinite(length)) {
- length = length | 0
- if (encoding === undefined) encoding = 'utf8'
- } else {
- encoding = length
- length = undefined
- }
- // legacy write(string, encoding, offset, length) - remove in v0.13
- } else {
- var swap = encoding
- encoding = offset
- offset = length | 0
- length = swap
- }
-
- var remaining = this.length - offset
- if (length === undefined || length > remaining) length = remaining
-
- if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
- throw new RangeError('attempt to write outside buffer bounds')
- }
-
- if (!encoding) encoding = 'utf8'
-
- var loweredCase = false
- for (;;) {
- switch (encoding) {
- case 'hex':
- return hexWrite(this, string, offset, length)
-
- case 'utf8':
- case 'utf-8':
- return utf8Write(this, string, offset, length)
-
- case 'ascii':
- return asciiWrite(this, string, offset, length)
-
- case 'binary':
- return binaryWrite(this, string, offset, length)
-
- case 'base64':
- // Warning: maxLength not taken into account in base64Write
- return base64Write(this, string, offset, length)
-
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return ucs2Write(this, string, offset, length)
-
- default:
- if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
- encoding = ('' + encoding).toLowerCase()
- loweredCase = true
- }
- }
-}
-
-Buffer.prototype.toJSON = function toJSON () {
- return {
- type: 'Buffer',
- data: Array.prototype.slice.call(this._arr || this, 0)
- }
-}
-
-function base64Slice (buf, start, end) {
- if (start === 0 && end === buf.length) {
- return base64.fromByteArray(buf)
- } else {
- return base64.fromByteArray(buf.slice(start, end))
- }
-}
-
-function utf8Slice (buf, start, end) {
- end = Math.min(buf.length, end)
- var res = []
-
- var i = start
- while (i < end) {
- var firstByte = buf[i]
- var codePoint = null
- var bytesPerSequence = (firstByte > 0xEF) ? 4
- : (firstByte > 0xDF) ? 3
- : (firstByte > 0xBF) ? 2
- : 1
-
- if (i + bytesPerSequence <= end) {
- var secondByte, thirdByte, fourthByte, tempCodePoint
-
- switch (bytesPerSequence) {
- case 1:
- if (firstByte < 0x80) {
- codePoint = firstByte
- }
- break
- case 2:
- secondByte = buf[i + 1]
- if ((secondByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
- if (tempCodePoint > 0x7F) {
- codePoint = tempCodePoint
- }
- }
- break
- case 3:
- secondByte = buf[i + 1]
- thirdByte = buf[i + 2]
- if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
- if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
- codePoint = tempCodePoint
- }
- }
- break
- case 4:
- secondByte = buf[i + 1]
- thirdByte = buf[i + 2]
- fourthByte = buf[i + 3]
- if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
- if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
- codePoint = tempCodePoint
- }
- }
- }
- }
-
- if (codePoint === null) {
- // we did not generate a valid codePoint so insert a
- // replacement char (U+FFFD) and advance only 1 byte
- codePoint = 0xFFFD
- bytesPerSequence = 1
- } else if (codePoint > 0xFFFF) {
- // encode to utf16 (surrogate pair dance)
- codePoint -= 0x10000
- res.push(codePoint >>> 10 & 0x3FF | 0xD800)
- codePoint = 0xDC00 | codePoint & 0x3FF
- }
-
- res.push(codePoint)
- i += bytesPerSequence
- }
-
- return decodeCodePointsArray(res)
-}
-
-// Based on http://stackoverflow.com/a/22747272/680742, the browser with
-// the lowest limit is Chrome, with 0x10000 args.
-// We go 1 magnitude less, for safety
-var MAX_ARGUMENTS_LENGTH = 0x1000
-
-function decodeCodePointsArray (codePoints) {
- var len = codePoints.length
- if (len <= MAX_ARGUMENTS_LENGTH) {
- return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
- }
-
- // Decode in chunks to avoid "call stack size exceeded".
- var res = ''
- var i = 0
- while (i < len) {
- res += String.fromCharCode.apply(
- String,
- codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
- )
- }
- return res
-}
-
-function asciiSlice (buf, start, end) {
- var ret = ''
- end = Math.min(buf.length, end)
-
- for (var i = start; i < end; i++) {
- ret += String.fromCharCode(buf[i] & 0x7F)
- }
- return ret
-}
-
-function binarySlice (buf, start, end) {
- var ret = ''
- end = Math.min(buf.length, end)
-
- for (var i = start; i < end; i++) {
- ret += String.fromCharCode(buf[i])
- }
- return ret
-}
-
-function hexSlice (buf, start, end) {
- var len = buf.length
-
- if (!start || start < 0) start = 0
- if (!end || end < 0 || end > len) end = len
-
- var out = ''
- for (var i = start; i < end; i++) {
- out += toHex(buf[i])
- }
- return out
-}
-
-function utf16leSlice (buf, start, end) {
- var bytes = buf.slice(start, end)
- var res = ''
- for (var i = 0; i < bytes.length; i += 2) {
- res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
- }
- return res
-}
-
-Buffer.prototype.slice = function slice (start, end) {
- var len = this.length
- start = ~~start
- end = end === undefined ? len : ~~end
-
- if (start < 0) {
- start += len
- if (start < 0) start = 0
- } else if (start > len) {
- start = len
- }
-
- if (end < 0) {
- end += len
- if (end < 0) end = 0
- } else if (end > len) {
- end = len
- }
-
- if (end < start) end = start
-
- var newBuf
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- newBuf = Buffer._augment(this.subarray(start, end))
- } else {
- var sliceLen = end - start
- newBuf = new Buffer(sliceLen, undefined)
- for (var i = 0; i < sliceLen; i++) {
- newBuf[i] = this[i + start]
- }
- }
-
- if (newBuf.length) newBuf.parent = this.parent || this
-
- return newBuf
-}
-
-/*
- * Need to make sure that buffer isn't trying to write out of bounds.
- */
-function checkOffset (offset, ext, length) {
- if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
- if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
-}
-
-Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var val = this[offset]
- var mul = 1
- var i = 0
- while (++i < byteLength && (mul *= 0x100)) {
- val += this[offset + i] * mul
- }
-
- return val
-}
-
-Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) {
- checkOffset(offset, byteLength, this.length)
- }
-
- var val = this[offset + --byteLength]
- var mul = 1
- while (byteLength > 0 && (mul *= 0x100)) {
- val += this[offset + --byteLength] * mul
- }
-
- return val
-}
-
-Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 1, this.length)
- return this[offset]
-}
-
-Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- return this[offset] | (this[offset + 1] << 8)
-}
-
-Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- return (this[offset] << 8) | this[offset + 1]
-}
-
-Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return ((this[offset]) |
- (this[offset + 1] << 8) |
- (this[offset + 2] << 16)) +
- (this[offset + 3] * 0x1000000)
-}
-
-Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset] * 0x1000000) +
- ((this[offset + 1] << 16) |
- (this[offset + 2] << 8) |
- this[offset + 3])
-}
-
-Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var val = this[offset]
- var mul = 1
- var i = 0
- while (++i < byteLength && (mul *= 0x100)) {
- val += this[offset + i] * mul
- }
- mul *= 0x80
-
- if (val >= mul) val -= Math.pow(2, 8 * byteLength)
-
- return val
-}
-
-Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var i = byteLength
- var mul = 1
- var val = this[offset + --i]
- while (i > 0 && (mul *= 0x100)) {
- val += this[offset + --i] * mul
- }
- mul *= 0x80
-
- if (val >= mul) val -= Math.pow(2, 8 * byteLength)
-
- return val
-}
-
-Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 1, this.length)
- if (!(this[offset] & 0x80)) return (this[offset])
- return ((0xff - this[offset] + 1) * -1)
-}
-
-Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- var val = this[offset] | (this[offset + 1] << 8)
- return (val & 0x8000) ? val | 0xFFFF0000 : val
-}
-
-Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- var val = this[offset + 1] | (this[offset] << 8)
- return (val & 0x8000) ? val | 0xFFFF0000 : val
-}
-
-Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset]) |
- (this[offset + 1] << 8) |
- (this[offset + 2] << 16) |
- (this[offset + 3] << 24)
-}
-
-Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset] << 24) |
- (this[offset + 1] << 16) |
- (this[offset + 2] << 8) |
- (this[offset + 3])
-}
-
-Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
- return ieee754.read(this, offset, true, 23, 4)
-}
-
-Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
- return ieee754.read(this, offset, false, 23, 4)
-}
-
-Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 8, this.length)
- return ieee754.read(this, offset, true, 52, 8)
-}
-
-Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 8, this.length)
- return ieee754.read(this, offset, false, 52, 8)
-}
-
-function checkInt (buf, value, offset, ext, max, min) {
- if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
- if (value > max || value < min) throw new RangeError('value is out of bounds')
- if (offset + ext > buf.length) throw new RangeError('index out of range')
-}
-
-Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
-
- var mul = 1
- var i = 0
- this[offset] = value & 0xFF
- while (++i < byteLength && (mul *= 0x100)) {
- this[offset + i] = (value / mul) & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
-
- var i = byteLength - 1
- var mul = 1
- this[offset + i] = value & 0xFF
- while (--i >= 0 && (mul *= 0x100)) {
- this[offset + i] = (value / mul) & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
- if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
- this[offset] = (value & 0xff)
- return offset + 1
-}
-
-function objectWriteUInt16 (buf, value, offset, littleEndian) {
- if (value < 0) value = 0xffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
- buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
- (littleEndian ? i : 1 - i) * 8
- }
-}
-
-Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- } else {
- objectWriteUInt16(this, value, offset, true)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 8)
- this[offset + 1] = (value & 0xff)
- } else {
- objectWriteUInt16(this, value, offset, false)
- }
- return offset + 2
-}
-
-function objectWriteUInt32 (buf, value, offset, littleEndian) {
- if (value < 0) value = 0xffffffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
- buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
- }
-}
-
-Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset + 3] = (value >>> 24)
- this[offset + 2] = (value >>> 16)
- this[offset + 1] = (value >>> 8)
- this[offset] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, true)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 24)
- this[offset + 1] = (value >>> 16)
- this[offset + 2] = (value >>> 8)
- this[offset + 3] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, false)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) {
- var limit = Math.pow(2, 8 * byteLength - 1)
-
- checkInt(this, value, offset, byteLength, limit - 1, -limit)
- }
-
- var i = 0
- var mul = 1
- var sub = value < 0 ? 1 : 0
- this[offset] = value & 0xFF
- while (++i < byteLength && (mul *= 0x100)) {
- this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) {
- var limit = Math.pow(2, 8 * byteLength - 1)
-
- checkInt(this, value, offset, byteLength, limit - 1, -limit)
- }
-
- var i = byteLength - 1
- var mul = 1
- var sub = value < 0 ? 1 : 0
- this[offset + i] = value & 0xFF
- while (--i >= 0 && (mul *= 0x100)) {
- this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
- if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
- if (value < 0) value = 0xff + value + 1
- this[offset] = (value & 0xff)
- return offset + 1
-}
-
-Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- } else {
- objectWriteUInt16(this, value, offset, true)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 8)
- this[offset + 1] = (value & 0xff)
- } else {
- objectWriteUInt16(this, value, offset, false)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- this[offset + 2] = (value >>> 16)
- this[offset + 3] = (value >>> 24)
- } else {
- objectWriteUInt32(this, value, offset, true)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
- if (value < 0) value = 0xffffffff + value + 1
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 24)
- this[offset + 1] = (value >>> 16)
- this[offset + 2] = (value >>> 8)
- this[offset + 3] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, false)
- }
- return offset + 4
-}
-
-function checkIEEE754 (buf, value, offset, ext, max, min) {
- if (value > max || value < min) throw new RangeError('value is out of bounds')
- if (offset + ext > buf.length) throw new RangeError('index out of range')
- if (offset < 0) throw new RangeError('index out of range')
-}
-
-function writeFloat (buf, value, offset, littleEndian, noAssert) {
- if (!noAssert) {
- checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
- }
- ieee754.write(buf, value, offset, littleEndian, 23, 4)
- return offset + 4
-}
-
-Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
- return writeFloat(this, value, offset, true, noAssert)
-}
-
-Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
- return writeFloat(this, value, offset, false, noAssert)
-}
-
-function writeDouble (buf, value, offset, littleEndian, noAssert) {
- if (!noAssert) {
- checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
- }
- ieee754.write(buf, value, offset, littleEndian, 52, 8)
- return offset + 8
-}
-
-Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
- return writeDouble(this, value, offset, true, noAssert)
-}
-
-Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
- return writeDouble(this, value, offset, false, noAssert)
-}
-
-// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
-Buffer.prototype.copy = function copy (target, targetStart, start, end) {
- if (!start) start = 0
- if (!end && end !== 0) end = this.length
- if (targetStart >= target.length) targetStart = target.length
- if (!targetStart) targetStart = 0
- if (end > 0 && end < start) end = start
-
- // Copy 0 bytes; we're done
- if (end === start) return 0
- if (target.length === 0 || this.length === 0) return 0
-
- // Fatal error conditions
- if (targetStart < 0) {
- throw new RangeError('targetStart out of bounds')
- }
- if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
- if (end < 0) throw new RangeError('sourceEnd out of bounds')
-
- // Are we oob?
- if (end > this.length) end = this.length
- if (target.length - targetStart < end - start) {
- end = target.length - targetStart + start
- }
-
- var len = end - start
- var i
-
- if (this === target && start < targetStart && targetStart < end) {
- // descending copy from end
- for (i = len - 1; i >= 0; i--) {
- target[i + targetStart] = this[i + start]
- }
- } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
- // ascending copy from start
- for (i = 0; i < len; i++) {
- target[i + targetStart] = this[i + start]
- }
- } else {
- target._set(this.subarray(start, start + len), targetStart)
- }
-
- return len
-}
-
-// fill(value, start=0, end=buffer.length)
-Buffer.prototype.fill = function fill (value, start, end) {
- if (!value) value = 0
- if (!start) start = 0
- if (!end) end = this.length
-
- if (end < start) throw new RangeError('end < start')
-
- // Fill 0 bytes; we're done
- if (end === start) return
- if (this.length === 0) return
-
- if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')
- if (end < 0 || end > this.length) throw new RangeError('end out of bounds')
-
- var i
- if (typeof value === 'number') {
- for (i = start; i < end; i++) {
- this[i] = value
- }
- } else {
- var bytes = utf8ToBytes(value.toString())
- var len = bytes.length
- for (i = start; i < end; i++) {
- this[i] = bytes[i % len]
- }
- }
-
- return this
-}
-
-/**
- * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
- * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
- */
-Buffer.prototype.toArrayBuffer = function toArrayBuffer () {
- if (typeof Uint8Array !== 'undefined') {
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- return (new Buffer(this)).buffer
- } else {
- var buf = new Uint8Array(this.length)
- for (var i = 0, len = buf.length; i < len; i += 1) {
- buf[i] = this[i]
- }
- return buf.buffer
- }
- } else {
- throw new TypeError('Buffer.toArrayBuffer not supported in this browser')
- }
-}
-
-// HELPER FUNCTIONS
-// ================
-
-var BP = Buffer.prototype
-
-/**
- * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
- */
-Buffer._augment = function _augment (arr) {
- arr.constructor = Buffer
- arr._isBuffer = true
-
- // save reference to original Uint8Array set method before overwriting
- arr._set = arr.set
-
- // deprecated
- arr.get = BP.get
- arr.set = BP.set
-
- arr.write = BP.write
- arr.toString = BP.toString
- arr.toLocaleString = BP.toString
- arr.toJSON = BP.toJSON
- arr.equals = BP.equals
- arr.compare = BP.compare
- arr.indexOf = BP.indexOf
- arr.copy = BP.copy
- arr.slice = BP.slice
- arr.readUIntLE = BP.readUIntLE
- arr.readUIntBE = BP.readUIntBE
- arr.readUInt8 = BP.readUInt8
- arr.readUInt16LE = BP.readUInt16LE
- arr.readUInt16BE = BP.readUInt16BE
- arr.readUInt32LE = BP.readUInt32LE
- arr.readUInt32BE = BP.readUInt32BE
- arr.readIntLE = BP.readIntLE
- arr.readIntBE = BP.readIntBE
- arr.readInt8 = BP.readInt8
- arr.readInt16LE = BP.readInt16LE
- arr.readInt16BE = BP.readInt16BE
- arr.readInt32LE = BP.readInt32LE
- arr.readInt32BE = BP.readInt32BE
- arr.readFloatLE = BP.readFloatLE
- arr.readFloatBE = BP.readFloatBE
- arr.readDoubleLE = BP.readDoubleLE
- arr.readDoubleBE = BP.readDoubleBE
- arr.writeUInt8 = BP.writeUInt8
- arr.writeUIntLE = BP.writeUIntLE
- arr.writeUIntBE = BP.writeUIntBE
- arr.writeUInt16LE = BP.writeUInt16LE
- arr.writeUInt16BE = BP.writeUInt16BE
- arr.writeUInt32LE = BP.writeUInt32LE
- arr.writeUInt32BE = BP.writeUInt32BE
- arr.writeIntLE = BP.writeIntLE
- arr.writeIntBE = BP.writeIntBE
- arr.writeInt8 = BP.writeInt8
- arr.writeInt16LE = BP.writeInt16LE
- arr.writeInt16BE = BP.writeInt16BE
- arr.writeInt32LE = BP.writeInt32LE
- arr.writeInt32BE = BP.writeInt32BE
- arr.writeFloatLE = BP.writeFloatLE
- arr.writeFloatBE = BP.writeFloatBE
- arr.writeDoubleLE = BP.writeDoubleLE
- arr.writeDoubleBE = BP.writeDoubleBE
- arr.fill = BP.fill
- arr.inspect = BP.inspect
- arr.toArrayBuffer = BP.toArrayBuffer
-
- return arr
-}
-
-var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
-
-function base64clean (str) {
- // Node strips out invalid characters like \n and \t from the string, base64-js does not
- str = stringtrim(str).replace(INVALID_BASE64_RE, '')
- // Node converts strings with length < 2 to ''
- if (str.length < 2) return ''
- // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
- while (str.length % 4 !== 0) {
- str = str + '='
- }
- return str
-}
-
-function stringtrim (str) {
- if (str.trim) return str.trim()
- return str.replace(/^\s+|\s+$/g, '')
-}
-
-function toHex (n) {
- if (n < 16) return '0' + n.toString(16)
- return n.toString(16)
-}
-
-function utf8ToBytes (string, units) {
- units = units || Infinity
- var codePoint
- var length = string.length
- var leadSurrogate = null
- var bytes = []
-
- for (var i = 0; i < length; i++) {
- codePoint = string.charCodeAt(i)
-
- // is surrogate component
- if (codePoint > 0xD7FF && codePoint < 0xE000) {
- // last char was a lead
- if (!leadSurrogate) {
- // no lead yet
- if (codePoint > 0xDBFF) {
- // unexpected trail
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- continue
- } else if (i + 1 === length) {
- // unpaired lead
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- continue
- }
-
- // valid lead
- leadSurrogate = codePoint
-
- continue
- }
-
- // 2 leads in a row
- if (codePoint < 0xDC00) {
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- leadSurrogate = codePoint
- continue
- }
-
- // valid surrogate pair
- codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
- } else if (leadSurrogate) {
- // valid bmp char, but last char was a lead
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- }
-
- leadSurrogate = null
-
- // encode utf8
- if (codePoint < 0x80) {
- if ((units -= 1) < 0) break
- bytes.push(codePoint)
- } else if (codePoint < 0x800) {
- if ((units -= 2) < 0) break
- bytes.push(
- codePoint >> 0x6 | 0xC0,
- codePoint & 0x3F | 0x80
- )
- } else if (codePoint < 0x10000) {
- if ((units -= 3) < 0) break
- bytes.push(
- codePoint >> 0xC | 0xE0,
- codePoint >> 0x6 & 0x3F | 0x80,
- codePoint & 0x3F | 0x80
- )
- } else if (codePoint < 0x110000) {
- if ((units -= 4) < 0) break
- bytes.push(
- codePoint >> 0x12 | 0xF0,
- codePoint >> 0xC & 0x3F | 0x80,
- codePoint >> 0x6 & 0x3F | 0x80,
- codePoint & 0x3F | 0x80
- )
- } else {
- throw new Error('Invalid code point')
- }
- }
-
- return bytes
-}
-
-function asciiToBytes (str) {
- var byteArray = []
- for (var i = 0; i < str.length; i++) {
- // Node's code seems to be doing this and not & 0x7F..
- byteArray.push(str.charCodeAt(i) & 0xFF)
- }
- return byteArray
-}
-
-function utf16leToBytes (str, units) {
- var c, hi, lo
- var byteArray = []
- for (var i = 0; i < str.length; i++) {
- if ((units -= 2) < 0) break
-
- c = str.charCodeAt(i)
- hi = c >> 8
- lo = c % 256
- byteArray.push(lo)
- byteArray.push(hi)
- }
-
- return byteArray
-}
-
-function base64ToBytes (str) {
- return base64.toByteArray(base64clean(str))
-}
-
-function blitBuffer (src, dst, offset, length) {
- for (var i = 0; i < length; i++) {
- if ((i + offset >= dst.length) || (i >= src.length)) break
- dst[i + offset] = src[i]
- }
- return i
-}
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"base64-js":9,"ieee754":10,"is-array":11}],9:[function(_require,module,exports){
-var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-
-;(function (exports) {
- 'use strict';
-
- var Arr = (typeof Uint8Array !== 'undefined')
- ? Uint8Array
- : Array
-
- var PLUS = '+'.charCodeAt(0)
- var SLASH = '/'.charCodeAt(0)
- var NUMBER = '0'.charCodeAt(0)
- var LOWER = 'a'.charCodeAt(0)
- var UPPER = 'A'.charCodeAt(0)
- var PLUS_URL_SAFE = '-'.charCodeAt(0)
- var SLASH_URL_SAFE = '_'.charCodeAt(0)
-
- function decode (elt) {
- var code = elt.charCodeAt(0)
- if (code === PLUS ||
- code === PLUS_URL_SAFE)
- return 62 // '+'
- if (code === SLASH ||
- code === SLASH_URL_SAFE)
- return 63 // '/'
- if (code < NUMBER)
- return -1 //no match
- if (code < NUMBER + 10)
- return code - NUMBER + 26 + 26
- if (code < UPPER + 26)
- return code - UPPER
- if (code < LOWER + 26)
- return code - LOWER + 26
- }
-
- function b64ToByteArray (b64) {
- var i, j, l, tmp, placeHolders, arr
-
- if (b64.length % 4 > 0) {
- throw new Error('Invalid string. Length must be a multiple of 4')
- }
-
- // the number of equal signs (place holders)
- // if there are two placeholders, than the two characters before it
- // represent one byte
- // if there is only one, then the three characters before it represent 2 bytes
- // this is just a cheap hack to not do indexOf twice
- var len = b64.length
- placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
-
- // base64 is 4/3 + up to two characters of the original data
- arr = new Arr(b64.length * 3 / 4 - placeHolders)
-
- // if there are placeholders, only get up to the last complete 4 chars
- l = placeHolders > 0 ? b64.length - 4 : b64.length
-
- var L = 0
-
- function push (v) {
- arr[L++] = v
- }
-
- for (i = 0, j = 0; i < l; i += 4, j += 3) {
- tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
- push((tmp & 0xFF0000) >> 16)
- push((tmp & 0xFF00) >> 8)
- push(tmp & 0xFF)
- }
-
- if (placeHolders === 2) {
- tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
- push(tmp & 0xFF)
- } else if (placeHolders === 1) {
- tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
- push((tmp >> 8) & 0xFF)
- push(tmp & 0xFF)
- }
-
- return arr
- }
-
- function uint8ToBase64 (uint8) {
- var i,
- extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
- output = "",
- temp, length
-
- function encode (num) {
- return lookup.charAt(num)
- }
-
- function tripletToBase64 (num) {
- return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
- }
-
- // go through the array every three bytes, we'll deal with trailing stuff later
- for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
- temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
- output += tripletToBase64(temp)
- }
-
- // pad the end with zeros, but make sure to not forget the extra bytes
- switch (extraBytes) {
- case 1:
- temp = uint8[uint8.length - 1]
- output += encode(temp >> 2)
- output += encode((temp << 4) & 0x3F)
- output += '=='
- break
- case 2:
- temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
- output += encode(temp >> 10)
- output += encode((temp >> 4) & 0x3F)
- output += encode((temp << 2) & 0x3F)
- output += '='
- break
- }
-
- return output
- }
-
- exports.toByteArray = b64ToByteArray
- exports.fromByteArray = uint8ToBase64
-}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
-
-},{}],10:[function(_require,module,exports){
-exports.read = function (buffer, offset, isLE, mLen, nBytes) {
- var e, m
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var nBits = -7
- var i = isLE ? (nBytes - 1) : 0
- var d = isLE ? -1 : 1
- var s = buffer[offset + i]
-
- i += d
-
- e = s & ((1 << (-nBits)) - 1)
- s >>= (-nBits)
- nBits += eLen
- for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- m = e & ((1 << (-nBits)) - 1)
- e >>= (-nBits)
- nBits += mLen
- for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- if (e === 0) {
- e = 1 - eBias
- } else if (e === eMax) {
- return m ? NaN : ((s ? -1 : 1) * Infinity)
- } else {
- m = m + Math.pow(2, mLen)
- e = e - eBias
- }
- return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
-}
-
-exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
- var e, m, c
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
- var i = isLE ? 0 : (nBytes - 1)
- var d = isLE ? 1 : -1
- var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
-
- value = Math.abs(value)
-
- if (isNaN(value) || value === Infinity) {
- m = isNaN(value) ? 1 : 0
- e = eMax
- } else {
- e = Math.floor(Math.log(value) / Math.LN2)
- if (value * (c = Math.pow(2, -e)) < 1) {
- e--
- c *= 2
- }
- if (e + eBias >= 1) {
- value += rt / c
- } else {
- value += rt * Math.pow(2, 1 - eBias)
- }
- if (value * c >= 2) {
- e++
- c /= 2
- }
-
- if (e + eBias >= eMax) {
- m = 0
- e = eMax
- } else if (e + eBias >= 1) {
- m = (value * c - 1) * Math.pow(2, mLen)
- e = e + eBias
- } else {
- m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
- e = 0
- }
- }
-
- for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
-
- e = (e << mLen) | m
- eLen += mLen
- for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
-
- buffer[offset + i - d] |= s * 128
-}
-
-},{}],11:[function(_require,module,exports){
-
-/**
- * isArray
- */
-
-var isArray = Array.isArray;
-
-/**
- * toString
- */
-
-var str = Object.prototype.toString;
-
-/**
- * Whether or not the given `val`
- * is an array.
- *
- * example:
- *
- * isArray([]);
- * // > true
- * isArray(arguments);
- * // > false
- * isArray('');
- * // > false
- *
- * @param {mixed} val
- * @return {bool}
- */
-
-module.exports = isArray || function (val) {
- return !! val && '[object Array]' == str.call(val);
-};
-
-},{}],12:[function(_require,module,exports){
-
-/**
- * Expose `Emitter`.
- */
-
-module.exports = Emitter;
-
-/**
- * Initialize a new `Emitter`.
- *
- * @api public
- */
-
-function Emitter(obj) {
- if (obj) return mixin(obj);
-};
-
-/**
- * Mixin the emitter properties.
- *
- * @param {Object} obj
- * @return {Object}
- * @api private
- */
-
-function mixin(obj) {
- for (var key in Emitter.prototype) {
- obj[key] = Emitter.prototype[key];
- }
- return obj;
-}
-
-/**
- * Listen on the given `event` with `fn`.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.on =
-Emitter.prototype.addEventListener = function(event, fn){
- this._callbacks = this._callbacks || {};
- (this._callbacks['$' + event] = this._callbacks['$' + event] || [])
- .push(fn);
- return this;
-};
-
-/**
- * Adds an `event` listener that will be invoked a single
- * time then automatically removed.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.once = function(event, fn){
- function on() {
- this.off(event, on);
- fn.apply(this, arguments);
- }
-
- on.fn = fn;
- this.on(event, on);
- return this;
-};
-
-/**
- * Remove the given callback for `event` or all
- * registered callbacks.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.off =
-Emitter.prototype.removeListener =
-Emitter.prototype.removeAllListeners =
-Emitter.prototype.removeEventListener = function(event, fn){
- this._callbacks = this._callbacks || {};
-
- // all
- if (0 == arguments.length) {
- this._callbacks = {};
- return this;
- }
-
- // specific event
- var callbacks = this._callbacks['$' + event];
- if (!callbacks) return this;
-
- // remove all handlers
- if (1 == arguments.length) {
- delete this._callbacks['$' + event];
- return this;
- }
-
- // remove specific handler
- var cb;
- for (var i = 0; i < callbacks.length; i++) {
- cb = callbacks[i];
- if (cb === fn || cb.fn === fn) {
- callbacks.splice(i, 1);
- break;
- }
- }
- return this;
-};
-
-/**
- * Emit `event` with the given args.
- *
- * @param {String} event
- * @param {Mixed} ...
- * @return {Emitter}
- */
-
-Emitter.prototype.emit = function(event){
- this._callbacks = this._callbacks || {};
- var args = [].slice.call(arguments, 1)
- , callbacks = this._callbacks['$' + event];
-
- if (callbacks) {
- callbacks = callbacks.slice(0);
- for (var i = 0, len = callbacks.length; i < len; ++i) {
- callbacks[i].apply(this, args);
- }
- }
-
- return this;
-};
-
-/**
- * Return array of callbacks for `event`.
- *
- * @param {String} event
- * @return {Array}
- * @api public
- */
-
-Emitter.prototype.listeners = function(event){
- this._callbacks = this._callbacks || {};
- return this._callbacks['$' + event] || [];
-};
-
-/**
- * Check if this emitter has `event` handlers.
- *
- * @param {String} event
- * @return {Boolean}
- * @api public
- */
-
-Emitter.prototype.hasListeners = function(event){
- return !! this.listeners(event).length;
-};
-
-},{}],13:[function(_require,module,exports){
-/**
- * Expose `requestAnimationFrame()`.
- */
-
-exports = module.exports = window.requestAnimationFrame
- || window.webkitRequestAnimationFrame
- || window.mozRequestAnimationFrame
- || fallback;
-
-/**
- * Fallback implementation.
- */
-
-var prev = new Date().getTime();
-function fallback(fn) {
- var curr = new Date().getTime();
- var ms = Math.max(0, 16 - (curr - prev));
- var req = setTimeout(fn, ms);
- prev = curr;
- return req;
-}
-
-/**
- * Cancel.
- */
-
-var cancel = window.cancelAnimationFrame
- || window.webkitCancelAnimationFrame
- || window.mozCancelAnimationFrame
- || window.clearTimeout;
-
-exports.cancel = function(id){
- cancel.call(window, id);
-};
-
-},{}],14:[function(_require,module,exports){
-(function (Buffer){
-/**
- * toString ref.
- */
-
-var toString = Object.prototype.toString;
-
-/**
- * Return the type of `val`.
- *
- * @param {Mixed} val
- * @return {String}
- * @api public
- */
-
-module.exports = function(val){
- switch (toString.call(val)) {
- case '[object Date]': return 'date';
- case '[object RegExp]': return 'regexp';
- case '[object Arguments]': return 'arguments';
- case '[object Array]': return 'array';
- case '[object Error]': return 'error';
- }
-
- if (val === null) return 'null';
- if (val === undefined) return 'undefined';
- if (val !== val) return 'nan';
- if (val && val.nodeType === 1) return 'element';
-
- if (typeof Buffer != 'undefined' && Buffer.isBuffer(val)) return 'buffer';
-
- val = val.valueOf
- ? val.valueOf()
- : Object.prototype.valueOf.apply(val)
-
- return typeof val;
-};
-
-}).call(this,_require("buffer").Buffer)
-},{"buffer":8}],15:[function(_require,module,exports){
-'use strict';
-
-var bindInternal3 = _require('../function/bindInternal3');
-
-/**
- * # For Each
- *
- * A fast `.forEach()` implementation.
- *
- * @param {Array} subject The array (or array-like) to iterate over.
- * @param {Function} fn The visitor function.
- * @param {Object} thisContext The context for the visitor.
- */
-module.exports = function fastForEach (subject, fn, thisContext) {
- var length = subject.length,
- iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
- i;
- for (i = 0; i < length; i++) {
- iterator(subject[i], i, subject);
- }
-};
-
-},{"../function/bindInternal3":18}],16:[function(_require,module,exports){
-'use strict';
-
-var bindInternal4 = _require('../function/bindInternal4');
-
-/**
- * # Reduce
- *
- * A fast `.reduce()` implementation.
- *
- * @param {Array} subject The array (or array-like) to reduce.
- * @param {Function} fn The reducer function.
- * @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
- * @param {Object} thisContext The context for the reducer.
- * @return {mixed} The final result.
- */
-module.exports = function fastReduce (subject, fn, initialValue, thisContext) {
- var length = subject.length,
- iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
- i, result;
-
- if (initialValue === undefined) {
- i = 1;
- result = subject[0];
- }
- else {
- i = 0;
- result = initialValue;
- }
-
- for (; i < length; i++) {
- result = iterator(result, subject[i], i, subject);
- }
-
- return result;
-};
-
-},{"../function/bindInternal4":19}],17:[function(_require,module,exports){
-'use strict';
-
-var forEachArray = _require('./array/forEach'),
- forEachObject = _require('./object/forEach');
-
-/**
- * # ForEach
- *
- * A fast `.forEach()` implementation.
- *
- * @param {Array|Object} subject The array or object to iterate over.
- * @param {Function} fn The visitor function.
- * @param {Object} thisContext The context for the visitor.
- */
-module.exports = function fastForEach (subject, fn, thisContext) {
- if (subject instanceof Array) {
- return forEachArray(subject, fn, thisContext);
- }
- else {
- return forEachObject(subject, fn, thisContext);
- }
-};
-},{"./array/forEach":15,"./object/forEach":21}],18:[function(_require,module,exports){
-'use strict';
-
-/**
- * Internal helper to bind a function known to have 3 arguments
- * to a given context.
- */
-module.exports = function bindInternal3 (func, thisContext) {
- return function (a, b, c) {
- return func.call(thisContext, a, b, c);
- };
-};
-
-},{}],19:[function(_require,module,exports){
-'use strict';
-
-/**
- * Internal helper to bind a function known to have 4 arguments
- * to a given context.
- */
-module.exports = function bindInternal4 (func, thisContext) {
- return function (a, b, c, d) {
- return func.call(thisContext, a, b, c, d);
- };
-};
-
-},{}],20:[function(_require,module,exports){
-'use strict';
-
-/**
- * Analogue of Object.assign().
- * Copies properties from one or more source objects to
- * a target object. Existing keys on the target object will be overwritten.
- *
- * > Note: This differs from spec in some important ways:
- * > 1. Will throw if passed non-objects, including `undefined` or `null` values.
- * > 2. Does not support the curious Exception handling behavior, exceptions are thrown immediately.
- * > For more details, see:
- * > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
- *
- *
- *
- * @param {Object} target The target object to copy properties to.
- * @param {Object} source, ... The source(s) to copy properties from.
- * @return {Object} The updated target object.
- */
-module.exports = function fastAssign (target) {
- var totalArgs = arguments.length,
- source, i, totalKeys, keys, key, j;
-
- for (i = 1; i < totalArgs; i++) {
- source = arguments[i];
- keys = Object.keys(source);
- totalKeys = keys.length;
- for (j = 0; j < totalKeys; j++) {
- key = keys[j];
- target[key] = source[key];
- }
- }
- return target;
-};
-
-},{}],21:[function(_require,module,exports){
-'use strict';
-
-var bindInternal3 = _require('../function/bindInternal3');
-
-/**
- * # For Each
- *
- * A fast object `.forEach()` implementation.
- *
- * @param {Object} subject The object to iterate over.
- * @param {Function} fn The visitor function.
- * @param {Object} thisContext The context for the visitor.
- */
-module.exports = function fastForEachObject (subject, fn, thisContext) {
- var keys = Object.keys(subject),
- length = keys.length,
- iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
- key, i;
- for (i = 0; i < length; i++) {
- key = keys[i];
- iterator(subject[key], key, subject);
- }
-};
-
-},{"../function/bindInternal3":18}],22:[function(_require,module,exports){
-'use strict';
-
-var bindInternal4 = _require('../function/bindInternal4');
-
-/**
- * # Reduce
- *
- * A fast object `.reduce()` implementation.
- *
- * @param {Object} subject The object to reduce over.
- * @param {Function} fn The reducer function.
- * @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
- * @param {Object} thisContext The context for the reducer.
- * @return {mixed} The final result.
- */
-module.exports = function fastReduceObject (subject, fn, initialValue, thisContext) {
- var keys = Object.keys(subject),
- length = keys.length,
- iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
- i, key, result;
-
- if (initialValue === undefined) {
- i = 1;
- result = subject[keys[0]];
- }
- else {
- i = 0;
- result = initialValue;
- }
-
- for (; i < length; i++) {
- key = keys[i];
- result = iterator(result, subject[key], key, subject);
- }
-
- return result;
-};
-
-},{"../function/bindInternal4":19}],23:[function(_require,module,exports){
-'use strict';
-
-var reduceArray = _require('./array/reduce'),
- reduceObject = _require('./object/reduce');
-
-/**
- * # Reduce
- *
- * A fast `.reduce()` implementation.
- *
- * @param {Array|Object} subject The array or object to reduce over.
- * @param {Function} fn The reducer function.
- * @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
- * @param {Object} thisContext The context for the reducer.
- * @return {Array|Object} The array or object containing the results.
- */
-module.exports = function fastReduce (subject, fn, initialValue, thisContext) {
- if (subject instanceof Array) {
- return reduceArray(subject, fn, initialValue, thisContext);
- }
- else {
- return reduceObject(subject, fn, initialValue, thisContext);
- }
-};
-},{"./array/reduce":16,"./object/reduce":22}],24:[function(_require,module,exports){
-/** generate unique id for selector */
-var counter = Date.now() % 1e9;
-
-module.exports = function getUid(){
- return (Math.random() * 1e9 >>> 0) + (counter++);
-};
-},{}],25:[function(_require,module,exports){
-/*global window*/
-
-/**
- * Check if object is dom node.
- *
- * @param {Object} val
- * @return {Boolean}
- * @api public
- */
-
-module.exports = function isNode(val){
- if (!val || typeof val !== 'object') return false;
- if (window && 'object' == typeof window.Node) return val instanceof window.Node;
- return 'number' == typeof val.nodeType && 'string' == typeof val.nodeName;
-}
-
-},{}],26:[function(_require,module,exports){
-/**
- * Supported SVG attributes
- */
-
-exports.attributes = {
- 'cx': true,
- 'cy': true,
- 'd': true,
- 'dx': true,
- 'dy': true,
- 'fill': true,
- 'fillOpacity': true,
- 'fontFamily': true,
- 'fontSize': true,
- 'fx': true,
- 'fy': true,
- 'gradientTransform': true,
- 'gradientUnits': true,
- 'markerEnd': true,
- 'markerMid': true,
- 'markerStart': true,
- 'offset': true,
- 'opacity': true,
- 'patternContentUnits': true,
- 'patternUnits': true,
- 'points': true,
- 'preserveAspectRatio': true,
- 'r': true,
- 'rx': true,
- 'ry': true,
- 'spreadMethod': true,
- 'stopColor': true,
- 'stopOpacity': true,
- 'stroke': true,
- 'strokeDasharray': true,
- 'strokeLinecap': true,
- 'strokeOpacity': true,
- 'strokeWidth': true,
- 'textAnchor': true,
- 'transform': true,
- 'version': true,
- 'viewBox': true,
- 'x1': true,
- 'x2': true,
- 'x': true,
- 'y1': true,
- 'y2': true,
- 'y': true
-}
-
-/**
- * Are element's attributes SVG?
- *
- * @param {String} attr
- */
-
-module.exports = function (attr) {
- return attr in exports.attributes
-}
-
-},{}],27:[function(_require,module,exports){
-/**
- * Supported SVG elements
- *
- * @type {Array}
- */
-
-exports.elements = {
- 'animate': true,
- 'circle': true,
- 'defs': true,
- 'ellipse': true,
- 'g': true,
- 'line': true,
- 'linearGradient': true,
- 'mask': true,
- 'path': true,
- 'pattern': true,
- 'polygon': true,
- 'polyline': true,
- 'radialGradient': true,
- 'rect': true,
- 'stop': true,
- 'svg': true,
- 'text': true,
- 'tspan': true
-}
-
-/**
- * Is element's namespace SVG?
- *
- * @param {String} name
- */
-
-exports.isElement = function (name) {
- return name in exports.elements
-}
-
-},{}],28:[function(_require,module,exports){
-'use strict'
-
-module.exports = function(target) {
- target = target || {}
-
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i]
- if (!source) continue
-
- Object.getOwnPropertyNames(source).forEach(function(key) {
- if (undefined === target[key])
- target[key] = source[key]
- })
- }
-
- return target
-}
-
-},{}],29:[function(_require,module,exports){
-(function (root, factory){
- 'use strict';
-
- /*istanbul ignore next:cant test*/
- if (typeof module === 'object' && typeof module.exports === 'object') {
- module.exports = factory();
- } else if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define([], factory);
- } else {
- // Browser globals
- root.objectPath = factory();
- }
-})(this, function(){
- 'use strict';
-
- var
- toStr = Object.prototype.toString,
- _hasOwnProperty = Object.prototype.hasOwnProperty;
-
- function isEmpty(value){
- if (!value) {
- return true;
- }
- if (isArray(value) && value.length === 0) {
- return true;
- } else if (!isString(value)) {
- for (var i in value) {
- if (_hasOwnProperty.call(value, i)) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- function toString(type){
- return toStr.call(type);
- }
-
- function isNumber(value){
- return typeof value === 'number' || toString(value) === "[object Number]";
- }
-
- function isString(obj){
- return typeof obj === 'string' || toString(obj) === "[object String]";
- }
-
- function isObject(obj){
- return typeof obj === 'object' && toString(obj) === "[object Object]";
- }
-
- function isArray(obj){
- return typeof obj === 'object' && typeof obj.length === 'number' && toString(obj) === '[object Array]';
- }
-
- function isBoolean(obj){
- return typeof obj === 'boolean' || toString(obj) === '[object Boolean]';
- }
-
- function getKey(key){
- var intKey = parseInt(key);
- if (intKey.toString() === key) {
- return intKey;
- }
- return key;
- }
-
- function set(obj, path, value, doNotReplace){
- if (isNumber(path)) {
- path = [path];
- }
- if (isEmpty(path)) {
- return obj;
- }
- if (isString(path)) {
- return set(obj, path.split('.').map(getKey), value, doNotReplace);
- }
- var currentPath = path[0];
-
- if (path.length === 1) {
- var oldVal = obj[currentPath];
- if (oldVal === void 0 || !doNotReplace) {
- obj[currentPath] = value;
- }
- return oldVal;
- }
-
- if (obj[currentPath] === void 0) {
- //check if we assume an array
- if(isNumber(path[1])) {
- obj[currentPath] = [];
- } else {
- obj[currentPath] = {};
- }
- }
-
- return set(obj[currentPath], path.slice(1), value, doNotReplace);
- }
-
- function del(obj, path) {
- if (isNumber(path)) {
- path = [path];
- }
-
- if (isEmpty(obj)) {
- return void 0;
- }
-
- if (isEmpty(path)) {
- return obj;
- }
- if(isString(path)) {
- return del(obj, path.split('.'));
- }
-
- var currentPath = getKey(path[0]);
- var oldVal = obj[currentPath];
-
- if(path.length === 1) {
- if (oldVal !== void 0) {
- if (isArray(obj)) {
- obj.splice(currentPath, 1);
- } else {
- delete obj[currentPath];
- }
- }
- } else {
- if (obj[currentPath] !== void 0) {
- return del(obj[currentPath], path.slice(1));
- }
- }
-
- return obj;
- }
-
- var objectPath = function(obj) {
- return Object.keys(objectPath).reduce(function(proxy, prop) {
- if (typeof objectPath[prop] === 'function') {
- proxy[prop] = objectPath[prop].bind(objectPath, obj);
- }
-
- return proxy;
- }, {});
- };
-
- objectPath.has = function (obj, path) {
- if (isEmpty(obj)) {
- return false;
- }
-
- if (isNumber(path)) {
- path = [path];
- } else if (isString(path)) {
- path = path.split('.');
- }
-
- if (isEmpty(path) || path.length === 0) {
- return false;
- }
-
- for (var i = 0; i < path.length; i++) {
- var j = path[i];
- if ((isObject(obj) || isArray(obj)) && _hasOwnProperty.call(obj, j)) {
- obj = obj[j];
- } else {
- return false;
- }
- }
-
- return true;
- };
-
- objectPath.ensureExists = function (obj, path, value){
- return set(obj, path, value, true);
- };
-
- objectPath.set = function (obj, path, value, doNotReplace){
- return set(obj, path, value, doNotReplace);
- };
-
- objectPath.insert = function (obj, path, value, at){
- var arr = objectPath.get(obj, path);
- at = ~~at;
- if (!isArray(arr)) {
- arr = [];
- objectPath.set(obj, path, arr);
- }
- arr.splice(at, 0, value);
- };
-
- objectPath.empty = function(obj, path) {
- if (isEmpty(path)) {
- return obj;
- }
- if (isEmpty(obj)) {
- return void 0;
- }
-
- var value, i;
- if (!(value = objectPath.get(obj, path))) {
- return obj;
- }
-
- if (isString(value)) {
- return objectPath.set(obj, path, '');
- } else if (isBoolean(value)) {
- return objectPath.set(obj, path, false);
- } else if (isNumber(value)) {
- return objectPath.set(obj, path, 0);
- } else if (isArray(value)) {
- value.length = 0;
- } else if (isObject(value)) {
- for (i in value) {
- if (_hasOwnProperty.call(value, i)) {
- delete value[i];
- }
- }
- } else {
- return objectPath.set(obj, path, null);
- }
- };
-
- objectPath.push = function (obj, path /*, values */){
- var arr = objectPath.get(obj, path);
- if (!isArray(arr)) {
- arr = [];
- objectPath.set(obj, path, arr);
- }
-
- arr.push.apply(arr, Array.prototype.slice.call(arguments, 2));
- };
-
- objectPath.coalesce = function (obj, paths, defaultValue) {
- var value;
-
- for (var i = 0, len = paths.length; i < len; i++) {
- if ((value = objectPath.get(obj, paths[i])) !== void 0) {
- return value;
- }
- }
-
- return defaultValue;
- };
-
- objectPath.get = function (obj, path, defaultValue){
- if (isNumber(path)) {
- path = [path];
- }
- if (isEmpty(path)) {
- return obj;
- }
- if (isEmpty(obj)) {
- return defaultValue;
- }
- if (isString(path)) {
- return objectPath.get(obj, path.split('.'), defaultValue);
- }
-
- var currentPath = getKey(path[0]);
-
- if (path.length === 1) {
- if (obj[currentPath] === void 0) {
- return defaultValue;
- }
- return obj[currentPath];
- }
-
- return objectPath.get(obj[currentPath], path.slice(1), defaultValue);
- };
-
- objectPath.del = function(obj, path) {
- return del(obj, path);
- };
-
- return objectPath;
-});
-
-},{}]},{},[3])(3)
-});
\ No newline at end of file
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 0000000..e27fdd3
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,6 @@
+machine:
+ node:
+ version: 5
+test:
+ override:
+ - make ci
diff --git a/component.json b/component.json
deleted file mode 100644
index 5539e08..0000000
--- a/component.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "deku",
- "main": "build/deku.js"
-}
diff --git a/dist/deku.js b/dist/deku.js
new file mode 100644
index 0000000..e740f04
--- /dev/null
+++ b/dist/deku.js
@@ -0,0 +1,1410 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.deku = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o nEndIdx && pStartIdx > pEndIdx) {
+ return;
+ }
+
+ var pEndItem = prev[pEndIdx];
+ var nEndItem = next[nEndIdx];
+ var movedFromFront = 0;
+
+ // Reversed
+ while (pStartIdx <= pEndIdx && nStartIdx <= nEndIdx && equal(pStartItem, nEndItem)) {
+ effect(MOVE, pStartItem, nEndItem, pEndIdx - movedFromFront + 1);
+ pStartItem = prev[++pStartIdx];
+ nEndItem = next[--nEndIdx];
+ ++movedFromFront;
+ }
+
+ // Reversed the other way (in case of e.g. reverse and append)
+ while (pEndIdx >= pStartIdx && nStartIdx <= nEndIdx && equal(nStartItem, pEndItem)) {
+ effect(MOVE, pEndItem, nStartItem, nStartIdx);
+ pEndItem = prev[--pEndIdx];
+ nStartItem = next[++nStartIdx];
+ --movedFromFront;
+ }
+
+ // List tail is the same
+ while (pEndIdx >= pStartIdx && nEndIdx >= nStartIdx && equal(pEndItem, nEndItem)) {
+ effect(UPDATE, pEndItem, nEndItem, nEndIdx);
+ pEndItem = prev[--pEndIdx];
+ nEndItem = next[--nEndIdx];
+ }
+
+ if (pStartIdx > pEndIdx) {
+ while (nStartIdx <= nEndIdx) {
+ effect(CREATE, null, nStartItem, nStartIdx);
+ nStartItem = next[++nStartIdx];
+ }
+
+ return;
+ }
+
+ if (nStartIdx > nEndIdx) {
+ while (pStartIdx <= pEndIdx) {
+ effect(REMOVE, pStartItem);
+ pStartItem = prev[++pStartIdx];
+ }
+
+ return;
+ }
+
+ var created = 0;
+ var pivotDest = null;
+ var pivotIdx = pStartIdx - movedFromFront;
+ var keepBase = pStartIdx;
+ var keep = (0, _bitVector.createBv)(pEndIdx - pStartIdx);
+
+ var prevMap = keyMap(prev, pStartIdx, pEndIdx + 1, key);
+
+ for (; nStartIdx <= nEndIdx; nStartItem = next[++nStartIdx]) {
+ var oldIdx = prevMap[key(nStartItem)];
+
+ if (isUndefined(oldIdx)) {
+ effect(CREATE, null, nStartItem, pivotIdx++);
+ ++created;
+ } else if (pStartIdx !== oldIdx) {
+ (0, _bitVector.setBit)(keep, oldIdx - keepBase);
+ effect(MOVE, prev[oldIdx], nStartItem, pivotIdx++);
+ } else {
+ pivotDest = nStartIdx;
+ }
+ }
+
+ if (pivotDest !== null) {
+ (0, _bitVector.setBit)(keep, 0);
+ effect(MOVE, prev[pStartIdx], next[pivotDest], pivotDest);
+ }
+
+ // If there are no creations, then you have to
+ // remove exactly max(prevLen - nextLen, 0) elements in this
+ // diff. You have to remove one more for each element
+ // that was created. This means once we have
+ // removed that many, we can stop.
+ var necessaryRemovals = prev.length - next.length + created;
+ for (var removals = 0; removals < necessaryRemovals; pStartItem = prev[++pStartIdx]) {
+ if (!(0, _bitVector.getBit)(keep, pStartIdx - keepBase)) {
+ effect(REMOVE, pStartItem);
+ ++removals;
+ }
+ }
+
+ function equal(a, b) {
+ return key(a) === key(b);
+ }
+}
+
+function isUndefined(val) {
+ return typeof val === 'undefined';
+}
+
+function keyMap(items, start, end, key) {
+ var map = {};
+
+ for (var i = start; i < end; ++i) {
+ map[key(items[i])] = i;
+ }
+
+ return map;
+}
+
+/**
+ * Exports
+ */
+
+exports.default = dift;
+exports.CREATE = CREATE;
+exports.UPDATE = UPDATE;
+exports.MOVE = MOVE;
+exports.REMOVE = REMOVE;
+},{"bit-vector":2}],2:[function(require,module,exports){
+/**
+ * Use typed arrays if we can
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+var FastArray = typeof Uint32Array === 'undefined' ? Array : Uint32Array;
+
+/**
+ * Bit vector
+ */
+
+function createBv(sizeInBits) {
+ return new FastArray(Math.ceil(sizeInBits / 32));
+}
+
+function setBit(v, idx) {
+ var r = idx % 32;
+ var pos = (idx - r) / 32;
+
+ v[pos] |= 1 << r;
+}
+
+function clearBit(v, idx) {
+ var r = idx % 32;
+ var pos = (idx - r) / 32;
+
+ v[pos] &= ~(1 << r);
+}
+
+function getBit(v, idx) {
+ var r = idx % 32;
+ var pos = (idx - r) / 32;
+
+ return !!(v[pos] & 1 << r);
+}
+
+/**
+ * Exports
+ */
+
+exports['default'] = {
+ createBv: createBv,
+ setBit: setBit,
+ clearBit: clearBit,
+ getBit: getBit
+};
+module.exports = exports['default'];
+},{}],3:[function(require,module,exports){
+/**
+ * Supported SVG attributes
+ */
+
+exports.attributes = {
+ 'cx': true,
+ 'cy': true,
+ 'd': true,
+ 'dx': true,
+ 'dy': true,
+ 'fill': true,
+ 'fillOpacity': true,
+ 'fontFamily': true,
+ 'fontSize': true,
+ 'fx': true,
+ 'fy': true,
+ 'gradientTransform': true,
+ 'gradientUnits': true,
+ 'markerEnd': true,
+ 'markerMid': true,
+ 'markerStart': true,
+ 'offset': true,
+ 'opacity': true,
+ 'patternContentUnits': true,
+ 'patternUnits': true,
+ 'points': true,
+ 'preserveAspectRatio': true,
+ 'r': true,
+ 'rx': true,
+ 'ry': true,
+ 'spreadMethod': true,
+ 'stopColor': true,
+ 'stopOpacity': true,
+ 'stroke': true,
+ 'strokeDasharray': true,
+ 'strokeLinecap': true,
+ 'strokeOpacity': true,
+ 'strokeWidth': true,
+ 'textAnchor': true,
+ 'transform': true,
+ 'version': true,
+ 'viewBox': true,
+ 'x1': true,
+ 'x2': true,
+ 'x': true,
+ 'y1': true,
+ 'y2': true,
+ 'y': true
+}
+
+/**
+ * Are element's attributes SVG?
+ *
+ * @param {String} attr
+ */
+
+module.exports = function (attr) {
+ return attr in exports.attributes
+}
+
+},{}],4:[function(require,module,exports){
+/**
+ * Supported SVG elements
+ *
+ * @type {Array}
+ */
+
+exports.elements = {
+ 'animate': true,
+ 'circle': true,
+ 'defs': true,
+ 'ellipse': true,
+ 'g': true,
+ 'line': true,
+ 'linearGradient': true,
+ 'mask': true,
+ 'path': true,
+ 'pattern': true,
+ 'polygon': true,
+ 'polyline': true,
+ 'radialGradient': true,
+ 'rect': true,
+ 'stop': true,
+ 'svg': true,
+ 'text': true,
+ 'tspan': true
+}
+
+/**
+ * Is element's namespace SVG?
+ *
+ * @param {String} name
+ */
+
+exports.isElement = function (name) {
+ return name in exports.elements
+}
+
+},{}],5:[function(require,module,exports){
+var naturalSelection = require('natural-selection');
+
+module.exports = function(element, value){
+ var canSet = naturalSelection(element) && element === document.activeElement;
+
+ if (canSet) {
+ var start = element.selectionStart,
+ end = element.selectionEnd;
+
+ element.value = value;
+ element.setSelectionRange(start, end);
+ } else {
+ element.value = value;
+ }
+};
+
+},{"natural-selection":6}],6:[function(require,module,exports){
+var supportedTypes = ['text', 'search', 'tel', 'url', 'password'];
+
+module.exports = function(element){
+ return !!(element.setSelectionRange && ~supportedTypes.indexOf(element.type));
+};
+
+},{}],7:[function(require,module,exports){
+var _curry2 = require('./internal/_curry2');
+
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts exactly `n`
+ * parameters. Unlike `nAry`, which passes only `n` arguments to the wrapped function,
+ * functions produced by `arity` will pass all provided arguments to the wrapped function.
+ *
+ * @func
+ * @memberOf R
+ * @sig (Number, (* -> *)) -> (* -> *)
+ * @category Function
+ * @param {Number} n The desired arity of the returned function.
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is
+ * guaranteed to be of arity `n`.
+ * @deprecated since v0.15.0
+ * @example
+ *
+ * var takesTwoArgs = function(a, b) {
+ * return [a, b];
+ * };
+ * takesTwoArgs.length; //=> 2
+ * takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ * var takesOneArg = R.arity(1, takesTwoArgs);
+ * takesOneArg.length; //=> 1
+ * // All arguments are passed through to the wrapped function
+ * takesOneArg(1, 2); //=> [1, 2]
+ */
+module.exports = _curry2(function(n, fn) {
+ // jshint unused:vars
+ switch (n) {
+ case 0: return function() {return fn.apply(this, arguments);};
+ case 1: return function(a0) {return fn.apply(this, arguments);};
+ case 2: return function(a0, a1) {return fn.apply(this, arguments);};
+ case 3: return function(a0, a1, a2) {return fn.apply(this, arguments);};
+ case 4: return function(a0, a1, a2, a3) {return fn.apply(this, arguments);};
+ case 5: return function(a0, a1, a2, a3, a4) {return fn.apply(this, arguments);};
+ case 6: return function(a0, a1, a2, a3, a4, a5) {return fn.apply(this, arguments);};
+ case 7: return function(a0, a1, a2, a3, a4, a5, a6) {return fn.apply(this, arguments);};
+ case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) {return fn.apply(this, arguments);};
+ case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) {return fn.apply(this, arguments);};
+ case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {return fn.apply(this, arguments);};
+ default: throw new Error('First argument to arity must be a non-negative integer no greater than ten');
+ }
+});
+
+},{"./internal/_curry2":10}],8:[function(require,module,exports){
+var _curry2 = require('./internal/_curry2');
+var _curryN = require('./internal/_curryN');
+var arity = require('./arity');
+
+
+/**
+ * Returns a curried equivalent of the provided function, with the
+ * specified arity. The curried function has two unusual capabilities.
+ * First, its arguments needn't be provided one at a time. If `g` is
+ * `R.curryN(3, f)`, the following are equivalent:
+ *
+ * - `g(1)(2)(3)`
+ * - `g(1)(2, 3)`
+ * - `g(1, 2)(3)`
+ * - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value `R.__` may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is `R.__`,
+ * the following are equivalent:
+ *
+ * - `g(1, 2, 3)`
+ * - `g(_, 2, 3)(1)`
+ * - `g(_, _, 3)(1)(2)`
+ * - `g(_, _, 3)(1, 2)`
+ * - `g(_, 2)(1)(3)`
+ * - `g(_, 2)(1, 3)`
+ * - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curry
+ * @example
+ *
+ * var addFourNumbers = function() {
+ * return R.sum([].slice.call(arguments, 0, 4));
+ * };
+ *
+ * var curriedAddFourNumbers = R.curryN(4, addFourNumbers);
+ * var f = curriedAddFourNumbers(1, 2);
+ * var g = f(3);
+ * g(4); //=> 10
+ */
+module.exports = _curry2(function curryN(length, fn) {
+ return arity(length, _curryN(length, [], fn));
+});
+
+},{"./arity":7,"./internal/_curry2":10,"./internal/_curryN":11}],9:[function(require,module,exports){
+/**
+ * Optimized internal two-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+module.exports = function _curry1(fn) {
+ return function f1(a) {
+ if (arguments.length === 0) {
+ return f1;
+ } else if (a != null && a['@@functional/placeholder'] === true) {
+ return f1;
+ } else {
+ return fn(a);
+ }
+ };
+};
+
+},{}],10:[function(require,module,exports){
+var _curry1 = require('./_curry1');
+
+
+/**
+ * Optimized internal two-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+module.exports = function _curry2(fn) {
+ return function f2(a, b) {
+ var n = arguments.length;
+ if (n === 0) {
+ return f2;
+ } else if (n === 1 && a != null && a['@@functional/placeholder'] === true) {
+ return f2;
+ } else if (n === 1) {
+ return _curry1(function(b) { return fn(a, b); });
+ } else if (n === 2 && a != null && a['@@functional/placeholder'] === true &&
+ b != null && b['@@functional/placeholder'] === true) {
+ return f2;
+ } else if (n === 2 && a != null && a['@@functional/placeholder'] === true) {
+ return _curry1(function(a) { return fn(a, b); });
+ } else if (n === 2 && b != null && b['@@functional/placeholder'] === true) {
+ return _curry1(function(b) { return fn(a, b); });
+ } else {
+ return fn(a, b);
+ }
+ };
+};
+
+},{"./_curry1":9}],11:[function(require,module,exports){
+var arity = require('../arity');
+
+
+/**
+ * Internal curryN function.
+ *
+ * @private
+ * @category Function
+ * @param {Number} length The arity of the curried function.
+ * @return {array} An array of arguments received thus far.
+ * @param {Function} fn The function to curry.
+ */
+module.exports = function _curryN(length, received, fn) {
+ return function() {
+ var combined = [];
+ var argsIdx = 0;
+ var left = length;
+ var combinedIdx = 0;
+ while (combinedIdx < received.length || argsIdx < arguments.length) {
+ var result;
+ if (combinedIdx < received.length &&
+ (received[combinedIdx] == null ||
+ received[combinedIdx]['@@functional/placeholder'] !== true ||
+ argsIdx >= arguments.length)) {
+ result = received[combinedIdx];
+ } else {
+ result = arguments[argsIdx];
+ argsIdx += 1;
+ }
+ combined[combinedIdx] = result;
+ if (result == null || result['@@functional/placeholder'] !== true) {
+ left -= 1;
+ }
+ combinedIdx += 1;
+ }
+ return left <= 0 ? fn.apply(this, combined) : arity(left, _curryN(length, combined, fn));
+ };
+};
+
+},{"../arity":7}],12:[function(require,module,exports){
+var curryN = require('ramda/src/curryN');
+
+function isString(s) { return typeof s === 'string'; }
+function isNumber(n) { return typeof n === 'number'; }
+function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+}
+function isFunction(f) { return typeof f === 'function'; }
+var isArray = Array.isArray || function(a) { return 'length' in a; };
+
+var mapConstrToFn = curryN(2, function(group, constr) {
+ return constr === String ? isString
+ : constr === Number ? isNumber
+ : constr === Object ? isObject
+ : constr === Array ? isArray
+ : constr === Function ? isFunction
+ : constr === undefined ? group
+ : constr;
+});
+
+function Constructor(group, name, validators) {
+ validators = validators.map(mapConstrToFn(group));
+ var constructor = curryN(validators.length, function() {
+ var val = [], v, validator;
+ for (var i = 0; i < arguments.length; ++i) {
+ v = arguments[i];
+ validator = validators[i];
+ if ((typeof validator === 'function' && validator(v)) ||
+ (v !== undefined && v !== null && v.of === validator)) {
+ val[i] = arguments[i];
+ } else {
+ throw new TypeError('wrong value ' + v + ' passed to location ' + i + ' in ' + name);
+ }
+ }
+ val.of = group;
+ val.name = name;
+ return val;
+ });
+ return constructor;
+}
+
+function rawCase(type, cases, action, arg) {
+ if (type !== action.of) throw new TypeError('wrong type passed to case');
+ var name = action.name in cases ? action.name
+ : '_' in cases ? '_'
+ : undefined;
+ if (name === undefined) {
+ throw new Error('unhandled value passed to case');
+ } else {
+ return cases[name].apply(undefined, arg !== undefined ? action.concat([arg]) : action);
+ }
+}
+
+var typeCase = curryN(3, rawCase);
+var caseOn = curryN(4, rawCase);
+
+function Type(desc) {
+ var obj = {};
+ for (var key in desc) {
+ obj[key] = Constructor(obj, key, desc[key]);
+ }
+ obj.case = typeCase(obj);
+ obj.caseOn = caseOn(obj);
+ return obj;
+}
+
+module.exports = Type;
+
+},{"ramda/src/curryN":8}],13:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.createDOMRenderer = createDOMRenderer;
+
+var _createElement = require('./createElement');
+
+var _createElement2 = _interopRequireDefault(_createElement);
+
+var _diff = require('./diff');
+
+var _patch = require('./patch');
+
+var _patch2 = _interopRequireDefault(_patch);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Create a DOM renderer using a container element. Everything will be rendered
+ * inside of that container. Returns a function that accepts new state that can
+ * replace what is currently rendered.
+ */
+
+function createDOMRenderer(container) {
+ var oldVnode = null;
+ var node = null;
+
+ var update = function update(newVnode) {
+ var changes = (0, _diff.diffNode)(oldVnode, newVnode);
+ node = changes.reduce(_patch2.default, node);
+ oldVnode = newVnode;
+ return node;
+ };
+
+ var create = function create(vnode) {
+ node = (0, _createElement2.default)(vnode);
+ if (container) container.appendChild(node);
+ oldVnode = vnode;
+ return node;
+ };
+
+ return function (vnode) {
+ return node !== null ? update(vnode) : create(vnode);
+ };
+}
+
+},{"./createElement":14,"./diff":15,"./patch":19}],14:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = createElement;
+
+var _setAttribute = require('./setAttribute');
+
+var _utils = require('./utils');
+
+var _svg = require('./svg');
+
+var _svg2 = _interopRequireDefault(_svg);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var cache = {};
+
+/**
+ * Create a real DOM element from a virtual element, recursively looping down.
+ * When it finds custom elements it will render them, cache them, and keep going,
+ * so they are treated like any other native element.
+ */
+
+function createElement(vnode) {
+ if ((0, _utils.isText)(vnode)) {
+ return document.createTextNode(vnode.nodeValue || '');
+ }
+
+ var cached = cache[vnode.type];
+
+ if (typeof cached === 'undefined') {
+ cached = cache[vnode.type] = _svg2.default.isElement(vnode.type) ? document.createElementNS(_svg2.default.namespace, vnode.type) : document.createElement(vnode.type);
+ }
+
+ var DOMElement = cached.cloneNode(false);
+
+ for (var name in vnode.attributes) {
+ (0, _setAttribute.setAttribute)(DOMElement, name, vnode.attributes[name]);
+ }
+
+ vnode.children.forEach(function (node, index) {
+ var child = createElement(node);
+ DOMElement.appendChild(child);
+ });
+
+ return DOMElement;
+}
+
+},{"./setAttribute":21,"./svg":22,"./utils":23}],15:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Actions = undefined;
+exports.diffAttributes = diffAttributes;
+exports.diffChildren = diffChildren;
+exports.diffNode = diffNode;
+
+var _utils = require('./utils');
+
+var _dift = require('dift');
+
+var diffActions = _interopRequireWildcard(_dift);
+
+var _unionType = require('union-type');
+
+var _unionType2 = _interopRequireDefault(_unionType);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var Any = function Any() {
+ return true;
+};
+
+/**
+ * Patch actions
+ */
+
+var Actions = exports.Actions = (0, _unionType2.default)({
+ setAttribute: [String, Any, Any],
+ removeAttribute: [String, Any],
+ insertChild: [Any, Number],
+ replaceChild: [Any, Any, Number],
+ removeChild: [Any, Number],
+ updateChild: [Number, Array],
+ insertBefore: [Number],
+ replaceNode: [Any, Any],
+ removeNode: [Any],
+ sameNode: []
+});
+
+/**
+ * Diff two attribute objects and return an array of actions that represent
+ * changes to transform the old object into the new one.
+ */
+
+function diffAttributes(previous, next) {
+ var setAttribute = Actions.setAttribute;
+ var removeAttribute = Actions.removeAttribute;
+
+ var changes = [];
+ var pAttrs = previous.attributes;
+ var nAttrs = next.attributes;
+
+ for (var name in nAttrs) {
+ if (nAttrs[name] !== pAttrs[name]) {
+ changes.push(setAttribute(name, nAttrs[name], pAttrs[name]));
+ }
+ }
+
+ for (var name in pAttrs) {
+ if (!(name in nAttrs)) {
+ changes.push(removeAttribute(name, pAttrs[name]));
+ }
+ }
+
+ return changes;
+}
+
+/**
+ * Compare two arrays of virtual nodes and return an array of actions
+ * to transform the left into the right. A starting path is supplied that use
+ * recursively to build up unique paths for each node.
+ */
+
+function diffChildren(previous, next) {
+ var insertChild = Actions.insertChild;
+ var updateChild = Actions.updateChild;
+ var removeChild = Actions.removeChild;
+ var insertBefore = Actions.insertBefore;
+ var CREATE = diffActions.CREATE;
+ var UPDATE = diffActions.UPDATE;
+ var MOVE = diffActions.MOVE;
+ var REMOVE = diffActions.REMOVE;
+
+ var previousChildren = (0, _utils.groupByKey)(previous.children);
+ var nextChildren = (0, _utils.groupByKey)(next.children);
+ var key = function key(a) {
+ return a.key;
+ };
+ var changes = [];
+
+ function effect(type, prev, next, idx) {
+ switch (type) {
+ case CREATE:
+ {
+ changes.push(insertChild(next.item, next.index));
+ break;
+ }
+ case UPDATE:
+ {
+ var actions = diffNode(prev.item, next.item);
+ if (actions.length > 0) {
+ changes.push(updateChild(idx, actions));
+ }
+ break;
+ }
+ case MOVE:
+ {
+ var actions = diffNode(prev.item, next.item);
+ changes.push(insertBefore(next.index));
+ if (actions.length > 0) {
+ changes.push(updateChild(next.index, actions));
+ }
+ break;
+ }
+ case REMOVE:
+ {
+ changes.push(removeChild(prev.item, prev.index));
+ break;
+ }
+ }
+ }
+
+ (0, diffActions.default)(previousChildren, nextChildren, effect, key);
+
+ return changes;
+}
+
+/**
+ * Compare two virtual nodes and return an array of changes to turn the left
+ * into the right.
+ */
+
+function diffNode(prev, next) {
+ var changes = [];
+ var replaceNode = Actions.replaceNode;
+ var setAttribute = Actions.setAttribute;
+ var sameNode = Actions.sameNode;
+ var removeNode = Actions.removeNode;
+
+ // No left node to compare it to
+ // TODO: This should just return a createNode action
+
+ if (prev === null || prev === undefined) {
+ throw new Error('Left node must not be null or undefined');
+ }
+
+ // Bail out and skip updating this whole sub-tree
+ if (prev === next) {
+ changes.push(sameNode());
+ return changes;
+ }
+
+ // Remove
+ if (prev != null && next == null) {
+ changes.push(removeNode(prev));
+ return changes;
+ }
+
+ // Replace
+ if (prev.type !== next.type) {
+ changes.push(replaceNode(prev, next));
+ return changes;
+ }
+
+ // Text
+ if ((0, _utils.isText)(next)) {
+ if (prev.nodeValue !== next.nodeValue) {
+ changes.push(setAttribute('nodeValue', next.nodeValue, prev.nodeValue));
+ }
+ return changes;
+ }
+
+ changes = changes.concat(diffAttributes(prev, next)).concat(diffChildren(prev, next));
+
+ return changes;
+}
+
+},{"./utils":23,"dift":1,"union-type":12}],16:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = element;
+exports.createTextElement = createTextElement;
+exports.createThunkElement = createThunkElement;
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
+
+/**
+ * This function lets us create virtual nodes using a simple
+ * syntax. It is compatible with JSX transforms so you can use
+ * JSX to write nodes that will compile to this function.
+ *
+ * let node = element('div', { id: 'foo' }, [
+ * element('a', { href: 'http://google.com' },
+ * element('span', {}, 'Google'),
+ * element('b', {}, 'Link')
+ * )
+ * ])
+ */
+
+function element(type, attributes) {
+ for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
+ children[_key - 2] = arguments[_key];
+ }
+
+ if (!type) throw new TypeError('element() needs a type.');
+
+ attributes = attributes || {};
+ children = (children || []).reduce(reduceChildren, []);
+
+ var key = typeof attributes.key === 'string' || typeof attributes.key === 'number' ? attributes.key : undefined;
+
+ if ((typeof type === 'undefined' ? 'undefined' : _typeof(type)) === 'object') {
+ return createThunkElement(type, key, attributes, children);
+ }
+
+ return {
+ attributes: attributes,
+ children: children,
+ type: type,
+ key: key
+ };
+}
+
+function reduceChildren(children, vnode) {
+ if (typeof vnode === 'string') {
+ children.push(createTextElement(vnode));
+ } else if (Array.isArray(vnode)) {
+ children = [].concat(_toConsumableArray(children), _toConsumableArray(vnode));
+ } else if (typeof vnode !== 'undefined') {
+ children.push(vnode);
+ }
+ return children;
+}
+
+function createTextElement(text) {
+ return {
+ type: '#text',
+ nodeValue: text
+ };
+}
+
+function createThunkElement(component, key, attributes, children) {
+ return {
+ type: '#thunk',
+ attributes: attributes,
+ component: component,
+ children: children,
+ key: key
+ };
+}
+
+},{}],17:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+/**
+ * Special attributes that map to DOM events.
+ */
+
+exports.default = {
+ onAbort: 'abort',
+ onAnimationStart: 'animationstart',
+ onAnimationIteration: 'animationiteration',
+ onAnimationEnd: 'animationend',
+ onBlur: 'blur',
+ onCanPlay: 'canplay',
+ onCanPlayThrough: 'canplaythrough',
+ onChange: 'change',
+ onClick: 'click',
+ onContextMenu: 'contextmenu',
+ onCopy: 'copy',
+ onCut: 'cut',
+ onDoubleClick: 'dblclick',
+ onDrag: 'drag',
+ onDragEnd: 'dragend',
+ onDragEnter: 'dragenter',
+ onDragExit: 'dragexit',
+ onDragLeave: 'dragleave',
+ onDragOver: 'dragover',
+ onDragStart: 'dragstart',
+ onDrop: 'drop',
+ onDurationChange: 'durationchange',
+ onEmptied: 'emptied',
+ onEncrypted: 'encrypted',
+ onEnded: 'ended',
+ onError: 'error',
+ onFocus: 'focus',
+ onInput: 'input',
+ onInvalid: 'invalid',
+ onKeyDown: 'keydown',
+ onKeyPress: 'keypress',
+ onKeyUp: 'keyup',
+ onLoad: 'load',
+ onLoadedData: 'loadeddata',
+ onLoadedMetadata: 'loadedmetadata',
+ onLoadStart: 'loadstart',
+ onPause: 'pause',
+ onPlay: 'play',
+ onPlaying: 'playing',
+ onProgress: 'progress',
+ onMouseDown: 'mousedown',
+ onMouseEnter: 'mouseenter',
+ onMouseLeave: 'mouseleave',
+ onMouseMove: 'mousemove',
+ onMouseOut: 'mouseout',
+ onMouseOver: 'mouseover',
+ onMouseUp: 'mouseup',
+ onPaste: 'paste',
+ onRateChange: 'ratechange',
+ onReset: 'reset',
+ onScroll: 'scroll',
+ onSeeked: 'seeked',
+ onSeeking: 'seeking',
+ onSubmit: 'submit',
+ onStalled: 'stalled',
+ onSuspend: 'suspend',
+ onTimeUpdate: 'timeupdate',
+ onTransitionEnd: 'transitionend',
+ onTouchCancel: 'touchcancel',
+ onTouchEnd: 'touchend',
+ onTouchMove: 'touchmove',
+ onTouchStart: 'touchstart',
+ onVolumeChange: 'volumechange',
+ onWaiting: 'waiting',
+ onWheel: 'wheel'
+};
+
+},{}],18:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _renderString = require('./renderString');
+
+var _renderString2 = _interopRequireDefault(_renderString);
+
+var _createDOMRenderer = require('./createDOMRenderer');
+
+var _createDOMRenderer2 = _interopRequireDefault(_createDOMRenderer);
+
+var _element = require('./element');
+
+var _element2 = _interopRequireDefault(_element);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = {
+ createDOMRenderer: _createDOMRenderer2.default,
+ renderString: _renderString2.default,
+ element: _element2.default
+};
+
+},{"./createDOMRenderer":13,"./element":16,"./renderString":20}],19:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = patch;
+
+var _setAttribute2 = require('./setAttribute');
+
+var _utils = require('./utils');
+
+var _createElement = require('./createElement');
+
+var _createElement2 = _interopRequireDefault(_createElement);
+
+var _diff = require('./diff');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Modify a DOM element given an array of actions. A context can be set
+ * that will be used to render any custom elements.
+ */
+
+function patch(DOMElement, action) {
+ _diff.Actions.case({
+ setAttribute: function setAttribute(name, value, previousValue) {
+ (0, _setAttribute2.setAttribute)(DOMElement, name, value, previousValue);
+ },
+ removeAttribute: function removeAttribute(name, previousValue) {
+ (0, _setAttribute2.removeAttribute)(DOMElement, name, previousValue);
+ },
+ insertChild: function insertChild(vnode, index) {
+ (0, _utils.insertAtIndex)(DOMElement, index, (0, _createElement2.default)(vnode));
+ },
+ removeChild: function removeChild(vnode, index) {
+ (0, _utils.removeAtIndex)(DOMElement, index);
+ },
+ insertBefore: function insertBefore(index) {
+ (0, _utils.insertAtIndex)(DOMElement.parentNode, index, DOMElement);
+ },
+ updateChild: function updateChild(index, actions) {
+ var child = DOMElement.childNodes[index];
+ actions.forEach(function (action) {
+ return patch(child, action);
+ });
+ return DOMElement;
+ },
+ replaceNode: function replaceNode(prev, next) {
+ DOMElement.parentNode.replaceChild((0, _createElement2.default)(next), DOMElement);
+ },
+ removeNode: function removeNode(prev) {
+ DOMElement.parentNode.removeChild(DOMElement);
+ DOMElement = null;
+ }
+ }, action);
+ return DOMElement;
+}
+
+},{"./createElement":14,"./diff":15,"./setAttribute":21,"./utils":23}],20:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = renderString;
+
+var _utils = require('./utils');
+
+/**
+ * Turn an object of key/value pairs into a HTML attribute string. This
+ * function is responsible for what attributes are allowed to be rendered and
+ * should handle any other special cases specific to deku.
+ */
+
+function attributesToString(attributes) {
+ var str = '';
+ for (var name in attributes) {
+ var value = attributes[name];
+ if (name === 'innerHTML') continue;
+ if ((0, _utils.isValidAttribute)(value)) str += ' ' + name + '="' + attributes[name] + '"';
+ }
+ return str;
+}
+
+/**
+ * Render a virtual element to a string. You can pass in an option state context
+ * object that will be given to all components.
+ */
+
+function renderString(element, context) {
+ var path = arguments.length <= 2 || arguments[2] === undefined ? '0' : arguments[2];
+
+ if ((0, _utils.isText)(element)) {
+ return element.nodeValue;
+ }
+
+ var attributes = element.attributes;
+ var type = element.type;
+ var children = element.children;
+
+ var innerHTML = attributes.innerHTML;
+ var str = '<' + type + attributesToString(attributes) + '>';
+
+ if (innerHTML) {
+ str += innerHTML;
+ } else {
+ str += children.map(function (child, i) {
+ return renderString(child, context, path + '.' + child.key || i);
+ }).join('');
+ }
+
+ str += '' + type + '>';
+ return str;
+}
+
+},{"./utils":23}],21:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.removeAttribute = removeAttribute;
+exports.setAttribute = setAttribute;
+
+var _utils = require('./utils');
+
+var _setify = require('setify');
+
+var _setify2 = _interopRequireDefault(_setify);
+
+var _events = require('./events');
+
+var _events2 = _interopRequireDefault(_events);
+
+var _svg = require('./svg');
+
+var _svg2 = _interopRequireDefault(_svg);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function removeAttribute(DOMElement, name, previousValue) {
+ switch (name) {
+ case _events2.default[name]:
+ if (typeof previousValue === 'function') {
+ DOMElement.removeEventListener(_events2.default[name], previousValue);
+ }
+ break;
+ case 'checked':
+ case 'disabled':
+ case 'selected':
+ DOMElement[name] = false;
+ break;
+ case 'innerHTML':
+ case 'nodeValue':
+ DOMElement.innerHTML = '';
+ break;
+ case 'value':
+ (0, _setify2.default)(DOMElement, null);
+ break;
+ default:
+ DOMElement.removeAttribute(name);
+ break;
+ }
+}
+
+function setAttribute(DOMElement, name, value, previousValue) {
+ if (value === previousValue) {
+ return;
+ }
+ if (typeof value === 'function') {
+ value = value(DOMElement, name);
+ }
+ if (!(0, _utils.isValidAttribute)(value)) {
+ removeAttribute(DOMElement, name, previousValue);
+ return;
+ }
+ switch (name) {
+ case _events2.default[name]:
+ if (typeof previousValue === 'function') {
+ DOMElement.removeEventListener(_events2.default[name], previousValue);
+ }
+ DOMElement.addEventListener(_events2.default[name], value);
+ break;
+ case 'checked':
+ case 'disabled':
+ case 'selected':
+ case 'innerHTML':
+ case 'nodeValue':
+ DOMElement[name] = value;
+ break;
+ case 'value':
+ (0, _setify2.default)(DOMElement, value);
+ break;
+ default:
+ if (_svg2.default.isAttribute(name)) {
+ DOMElement.setAttributeNS(_svg2.default.namespace, name, value);
+ } else {
+ DOMElement.setAttribute(name, value);
+ }
+ break;
+ }
+}
+
+},{"./events":17,"./svg":22,"./utils":23,"setify":5}],22:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _isSvgElement = require('is-svg-element');
+
+var _isSvgAttribute = require('is-svg-attribute');
+
+var _isSvgAttribute2 = _interopRequireDefault(_isSvgAttribute);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var namespace = 'http://www.w3.org/2000/svg';
+
+exports.default = {
+ isElement: _isSvgElement.isElement,
+ isAttribute: _isSvgAttribute2.default,
+ namespace: namespace
+};
+
+},{"is-svg-attribute":3,"is-svg-element":4}],23:[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.isValidAttribute = isValidAttribute;
+/**
+ * Check if an attribute shoudl be rendered into the DOM.
+ */
+
+function isValidAttribute(value) {
+ if (typeof value === 'boolean') return value;
+ if (typeof value === 'function') return false;
+ if (value === '') return true;
+ if (value === undefined) return false;
+ if (value === null) return false;
+ if (value === false) return false;
+ return true;
+}
+
+/**
+ * Group an array of virtual elements by their key, using index as a fallback.
+ */
+
+var groupByKey = exports.groupByKey = function groupByKey(children) {
+ return children.reduce(function (acc, child, i) {
+ if (child != null && child !== false) {
+ acc.push({
+ key: String(child.key || i),
+ item: child,
+ index: i
+ });
+ }
+ return acc;
+ }, []);
+};
+
+/**
+ * Is a vnode a thunk?
+ */
+
+var isThunk = exports.isThunk = function isThunk(node) {
+ return node.type === '#thunk';
+};
+
+/**
+ * Is a vnode a text node?
+ */
+
+var isText = exports.isText = function isText(node) {
+ return node.type === '#text';
+};
+
+/**
+ * Determine if two virtual nodes are the same type
+ */
+
+var isSameThunk = exports.isSameThunk = function isSameThunk(left, right) {
+ return isThunk(left) && isThunk(right) && left.render === right.render;
+};
+
+/**
+ * Create a node path, eg. (23,5,2,4) => '23.5.2.4'
+ */
+
+var createPath = exports.createPath = function createPath() {
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ return args.join('.');
+};
+
+/**
+ * Find a child node at a given path. Takes any tree that uses a
+ * 'children' key. This will work for both virtual nodes and real
+ * DOM trees.
+ */
+
+var findNodeAtPath = exports.findNodeAtPath = function findNodeAtPath(path, tree) {
+ var parts = path.split('.');
+ var node = undefined;
+ while (parts.length) {
+ var index = parts.shift();
+ node = tree.children[index];
+ }
+ return node;
+};
+
+/**
+ * Slightly nicer insertBefore
+ */
+
+var insertAtIndex = exports.insertAtIndex = function insertAtIndex(parent, index, el) {
+ var target = parent.childNodes[index];
+ if (target) {
+ parent.insertBefore(el, target);
+ } else {
+ parent.appendChild(el);
+ }
+};
+
+/**
+ * Remove an element at an index
+ */
+
+var removeAtIndex = exports.removeAtIndex = function removeAtIndex(DOMElement, index) {
+ DOMElement.removeChild(DOMElement.childNodes[index]);
+};
+
+},{}]},{},[18])(18)
+});
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..27e131c
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,19 @@
+# Summary
+
+* [Readme](/README.md)
+* [Motivation](/docs/motivation.md)
+* [Contributing](/docs/contributing.md)
+* [Basics](/docs/basics/index.md)
+ * [Elements](/docs/basics/elements.md)
+ * [JSX](/docs/basics/JSX.md)
+ * [Events](/docs/basics/events.md)
+ * [Components](/docs/basics/components.md)
+* [Advanced](/docs/advanced/index.md)
+ * [Lifecycle Hooks](/docs/advanced/lifecycle.md)
+ * [Keys](/docs/advanced/keys.md)
+ * [Context](/docs/advanced/context.md)
+ * [Dispatcher](/docs/advanced/dispatcher.md)
+* [API Reference](/docs/api/index.md)
+ * [dom](/docs/api/dom.md)
+ * [string](/docs/api/string.md)
+ * [element](/docs/api/element.md)
diff --git a/docs/advanced/context.md b/docs/advanced/context.md
new file mode 100644
index 0000000..2c993da
--- /dev/null
+++ b/docs/advanced/context.md
@@ -0,0 +1,97 @@
+# Context
+
+Context is an object you can set when you call render. It will be accessible from every component in the tree. Unlike React you can't modify the context within the tree.
+
+You can use `context` to:
+
+* Access your Redux state throughout the tree.
+* Passing in `window` properties, like the size of the browser window.
+* Viewing device information like the user agent, or the orientation.
+* Setting global theme variables.
+* Store local state for components using their `path` as the key.
+
+There are some things to remember when using `context`:
+
+* Context should be **immutable**. Never mutate the object directly. The renderer can perform additional optimizations if you use a different object each time. If you're using Redux, your state should be immutable anyway. You can also use a library to help with immutable structures like [Immutable.js](https://github.com/facebook/immutable-js) or [Mori](https://github.com/swannodette/mori).
+* Context can't be modified by components. There's no `getChildContext`.
+
+## Example
+
+We can access the `context` on the model:
+
+```js
+function render ({ context }) {
+ return
Hi
+}
+
+export default {
+ render
+}
+```
+
+Your context object might look something like this:
+
+```js
+let context = {
+ theme: {
+ background: 'red'
+ },
+ device: {
+ width: 1000,
+ height: 1000,
+ orientation: 'landscape'
+ },
+ browser: {
+ type: 'IE',
+ version: 10
+ },
+ collections: {
+ todos: [],
+ projects: []
+ },
+ user: {
+ name: 'Anthony Short',
+ username: 'anthoney'
+ }
+}
+```
+
+Which you can set when you call [`render`](../api/dom):
+
+```js
+render(, context)
+```
+
+## How do I change context and re-render?
+
+Context can change in a few ways. You should listen for changes at the top level of your application rather than within components where possible. To change any type of context value from within components, you should trigger actions using `dispatch`.
+
+* You can listen to your Redux store using `subscribe`
+* You can listen for `window` events like `resize`
+* Trigger actions using the `dispatcher`
+
+The easiest way to use context is to use the Redux state, a it's almost guaranteed to be immutable and you can easily keep `window` and device information in your Redux store.
+
+```js
+render(, store.getState())
+```
+
+You would modify context by dispatching actions and reducing them with Redux:
+
+```js
+function render ({ dispatch }) {
+ return
+}
+
+function resize (dispatch, width, height) {
+ return () => dispatch({
+ type: 'RESIZE',
+ width,
+ height
+ })
+}
+
+export default {
+ render
+}
+```
diff --git a/docs/advanced/dispatcher.md b/docs/advanced/dispatcher.md
new file mode 100644
index 0000000..d04a8f5
--- /dev/null
+++ b/docs/advanced/dispatcher.md
@@ -0,0 +1,41 @@
+# Dispatcher
+
+The `dispatcher` is a function you can pass to `createRenderer` that will handle actions that are triggered within the UI. You will typically use a library like Redux to handle reducing actions into state and side-effects.
+
+* All actions a user or program trigger should be dispatched
+* Side-effects, like DOM manipulation, should also be dispatched as actions and handled by this function
+* Access the dispatch function within components as `model.dispatch`
+
+## Example
+
+Here's a custom `dispatch` function being passed into the `createRenderer` function.
+
+```js
+// Custom dispatch method
+let render = createRenderer(document.body, action => {
+ // action.type = 'ADD_TODO'
+})
+
+// Using Redux
+let render = createRenderer(document.body, store.dispatch)
+```
+
+You will be able to access `dispatch` from any component as `model.dispatch`:
+
+```js
+function render ({ dispatch }) {
+ return
+}
+
+function addTodo (dispatch) {
+ return event => {
+ dispatch({
+ type: 'ADD_TODO'
+ })
+ }
+}
+
+export default {
+ render
+}
+```
diff --git a/docs/advanced/index.md b/docs/advanced/index.md
new file mode 100644
index 0000000..fe85bb9
--- /dev/null
+++ b/docs/advanced/index.md
@@ -0,0 +1,8 @@
+# Advanced
+
+Learn how to integrate Deku into your application and improve performance.
+
+* [Lifecycle Hooks](./hooks.md)
+* [Keys](./keys.md)
+* [Context](./context.md)
+* [Dispatcher](./dispatcher.md)
diff --git a/docs/advanced/keys.md b/docs/advanced/keys.md
new file mode 100644
index 0000000..368d1a3
--- /dev/null
+++ b/docs/advanced/keys.md
@@ -0,0 +1,101 @@
+# Keys
+
+Elements can have a special attribute named `key`. This lets the renderer know how to identify an element amongst sibling elements so it can determine if an element has just been moved, instead of removing and replacing DOM nodes unnecessarily.
+
+* `key` is a special attribute that won't be passed in as a prop or rendered in the DOM.
+* They increase the rendering performance of large lists.
+* They only need to be unique to sibling elements.
+* They can be used to maintain state of form elements, like `input` and `select`.
+* Not every sibling needs a key. You can add a `key` to the elements you want to be moved around.
+
+## Example
+
+In this example, we use the key attribute to make sure the input element is moved instead of replaced whenever the hint is added and removed:
+
+```js
+
+
+ {showHint ? Enter your full name : null}
+
+
+```
+
+In the next example, we use keys to improve the rendering performance of a list. You can use the `id`, `name`, or other unique field for the list item.
+
+```js
+let people = [
+ { id: 1, name: 'Tom' },
+ { id: 2, name: 'Dick' },
+ { id: 3, name: 'Harry' }
+]
+
+let el =
+
+ {people.map(person =>
{person.name}
)}
+
+```
+
+## Why do we need keys?
+
+To see why we need to do this we need to explain how the renderer compares lists of elements. Imagine on the first render these elements are return:
+
+```html
+
+ One
+
Two
+ Three
+
+```
+
+Then on the next render this element is returned:
+
+```html
+
+ One
+ Three
+
Two
+
+```
+
+The third element has moved up. This is obvious to humans. But when the renderer is performing the diff it is just comparing the left and right sides one after the other:
+
+```
+One -> One // No change. Leave it.
+
Two
-> Three // Different element. Replace!
+Three ->
Two
// Different element. Replace!
+```
+
+Most of the time this won't affect you but there are a couple of cases where this becomes a problem:
+
+* When you have a large list of elements (thousands) that have moved around. The renderer will be removing and creating large sets of DOM elements.
+* When elements with hidden state, like `input` fields, are moved around. Their state will be lost because they've been destroyed and recreated.
+
+To get around this we can just add a `key` attribute:
+
+```js
+
+ One
+
Two
+ Three
+
+```
+
+Now during the diff the renderer will know that elements have just moved:
+
+```
+One -> One // No change. Leave it.
+
Two
->
Two
// Move to position 2!
+Three -> Three // Move to position 1!
+```
+
+**These keys only need to be unique to siblings.** They don't need to be globally unique like the `id` attribute.
+
+You can also add keys only to the elements you want moved around if that's easier.
+
+```js
+
+ One
+
Two
+ Three
+
+```
diff --git a/docs/advanced/lifecycle.md b/docs/advanced/lifecycle.md
new file mode 100644
index 0000000..851a77d
--- /dev/null
+++ b/docs/advanced/lifecycle.md
@@ -0,0 +1,48 @@
+# Lifecycle hooks
+
+These are functions you can add to your component to hook into different parts of the rendering process. You can use these to manipulate the DOM in some way or trigger an action to change state.
+
+| Name | Triggered | Arguments |
+|-------------|--------------------------------------------------------------------------|-------------|
+| `onCreate` | When the component is initially created | `model` |
+| `onUpdate` | After the component is re-rendered and the DOM is patched | `model` |
+| `onRemove` | When the DOM element has been removed from the DOM | `model` |
+
+## Example
+
+```js
+function render (model) {
+ return
{model.props.text}
+}
+
+function onCreate (model) {
+ console.log('A MyComponent entity was created!')
+}
+
+export default {
+ render,
+ onCreate
+}
+```
+
+## How do I access the DOM element?
+
+In React, you can access the DOM element directly in the lifecycle hooks. In Deku, we only pass you the data model. If you need to access the DOM element this is a side-effect. You should dispatch an action and let another part of your application handle the side-effect. This allows you to keep your component completely DOM-free, which makes it easier to test and allows you to reuse side-effects.
+
+```js
+function render ({ path }) {
+ return
+}
+
+function onCreate ({ dispatch, path }) {
+ dispatch({
+ type: 'FOCUS',
+ selector: `#${path}`
+ })
+}
+
+export default {
+ render,
+ onCreate
+}
+```
diff --git a/docs/advanced/model.md b/docs/advanced/model.md
new file mode 100644
index 0000000..8f34216
--- /dev/null
+++ b/docs/advanced/model.md
@@ -0,0 +1,79 @@
+# Model
+
+The model is passed into the Component function and is essentially the state that you can use to create virtual nodes. The model is immutable so to make any changes to values you need modify the state somewhere else and call `render` again from the top level.
+
+```js
+function App (model) {
+ return
Hello World
+}
+```
+
+## Properties
+
+### `model.attributes`
+
+The values passed into your component as virtual element attributes. For example, passing these attributes into the component:
+
+```js
+
+```
+
+will yield this as `model.attributes`:
+
+```json
+{
+ "count": 5,
+ "type": "tasks"
+}
+```
+
+### `model.children`
+
+The child nodes that are passed to the component.
+
+```js
+
+
+ Hello World
+
+```
+
+The `children` property will always be an array:
+
+```jsx
+[
+ ,
+ Hello World
+]
+```
+
+You can use this to render the passed in nodes somewhere within the rendered DOM.
+
+```js
+function App (model) {
+ return
{model.children}
+}
+```
+
+### `model.path`
+
+The unique path to the component within the entire component tree.
+
+```js
+function App (model) {
+ return Save
+}
+
+function updateState (path) {
+ return function (e) {
+ dispatch('updateState', {
+ path: path,
+ value: e.target.value
+ })
+ }
+}
+```
+
+Paths in a tree are strings, like `0.1.5.2`. Each number represents the index of the node in the parent node, so you can use this to find a node within a tree.
+
+If a node within that path has a `key` attribute, we use that instead so that the path is stable even if any elements move around. For example, `0.1.foo.2`. This allows you to maintain some state for a component even if it moves.
diff --git a/docs/api/dom.md b/docs/api/dom.md
new file mode 100644
index 0000000..c3007f1
--- /dev/null
+++ b/docs/api/dom.md
@@ -0,0 +1,53 @@
+# `dom`
+
+The `dom` object provides functions for rendering elements to the DOM.
+
+```js
+import {dom} from 'deku'
+```
+
+### Properties
+
+* [`createRenderer`](#-createrenderer-el-dispatcher)
+
+## `createRenderer(el, [dispatcher])`
+
+Returns a `render` function that you can use to render elements within `DOMElement`.
+
+### Arguments
+
+1. `el` _(HTMLElement)_: A container element that will have virtual elements rendered inside of it. The element will never be touched.
+2. `dispatcher` _(Function)_: A function that can receive actions from the interface. This function will be passed into every component. It usually takes an [action](http://redux.js.org/docs/basics/Actions.html) that can be handled by a [store](http://redux.js.org/docs/basics/Store.html)
+
+### Returns
+
+`render` _(Function)_: A function that will update the current virtual element. It accepts a new `vnode` and a `context` object that will be passed to every component. You can use the context object to send shared state to every component. The `context` object should be immutable if possible as internally the renderer can provide extra optimizations.
+
+### Example
+
+```js
+import {dom, element} from 'deku'
+import {createStore} from 'redux'
+import reducer from './reducer'
+import App from './app'
+let {createRenderer} = dom
+
+// Create a redux store to handle actions
+let store = createStore(reducer)
+
+// Create a renderer
+let render = createRenderer(document.body, store.dispatch)
+
+// This renders the content into document.body
+render()
+
+// Update the UI
+render()
+```
+
+### Notes
+
+The container DOM element should:
+
+* **Not be the document.body**. You'll probably run into problems with other libraries. They'll often add elements to the `document.body` which can confuse the diff algorithm.
+* **Be empty**. All elements inside of the container will be removed when a virtual element is rendered into it. The renderer needs to have complete control of all of the elements within the container.
diff --git a/docs/api/element.md b/docs/api/element.md
new file mode 100644
index 0000000..2d85601
--- /dev/null
+++ b/docs/api/element.md
@@ -0,0 +1,31 @@
+# `element(type, attributes, children)`
+
+Returns a `render` function that you can use to render elements within `DOMElement`. The function signature is compatible with JSX.
+
+### Arguments
+
+1. `type` _(String|Object)_: Each node in a tree has a type. This is only used when rendering the tree.
+2. `attributes` _(Object)_ (Optional): The attributes of this node, similar to HTML attributes.
+3. `children` _(Array)_ (Optional): An array of children. Each child should also be an `element`. Strings are also accepted for text nodes.
+
+### Returns
+
+`vnode` _(Object)_: An object representing a node within a tree.
+
+### Example
+
+```js
+import {element} from 'deku'
+
+// Native elements
+element('div', { class: "greeting" }, [
+ element('span', {}, ['Hello'])
+])
+
+// Components
+let App = {
+ render: ({ props }) =>
Hello {props.name}!
+}
+
+element(App, { name: "Tom" })
+```
diff --git a/docs/api/index.md b/docs/api/index.md
new file mode 100644
index 0000000..7f0e0d3
--- /dev/null
+++ b/docs/api/index.md
@@ -0,0 +1,5 @@
+# API Reference
+
+* [dom](dom.md)
+* [string](string.md)
+* [element](element.md)
diff --git a/docs/api/string.md b/docs/api/string.md
new file mode 100644
index 0000000..7778700
--- /dev/null
+++ b/docs/api/string.md
@@ -0,0 +1,43 @@
+# `string`
+
+The `string` object provides functions for rendering virtual elements to a string.
+
+```js
+import {string} from 'deku'
+```
+
+### Properties
+
+* [`render`](#-render-vnode-context)
+
+## `render(vnode, [context])`
+
+This function renders a virtual element to a string. It will render components and call all hooks as normal. This can be used on the server to pre-render an app as HTML, and then replaced on the client.
+
+The `context` object will be passed into each component function.
+
+### Arguments
+
+1. `vnode` _(VirtualElement)_: A virtual element to render as a string.
+2. `context` _(Object)_: You can use the context object to send shared state to every component. The `context` object should be immutable if possible as internally the renderer can provide extra optimizations.
+
+### Returns
+
+`html` _(String)_: A string of HTML that can be rendered on the server.
+
+### Example
+
+```js
+import {string, element} from 'deku'
+import Sidebar from './sidebar'
+import Header from './header'
+import App from './app'
+
+let html = string.render(
+
+
+
+
+
+)
+```
diff --git a/docs/basics/JSX.md b/docs/basics/JSX.md
new file mode 100644
index 0000000..62fec18
--- /dev/null
+++ b/docs/basics/JSX.md
@@ -0,0 +1,44 @@
+# JSX
+
+The `element` function used to create virtual elements is compatible with [JSX](http://jsx.github.io) through [Babel](https://babeljs.io). When using Babel you just need to set the `jsxPragma`. This allows you to automatically transform HTML in your code into `element` calls.
+
+## Setting the pragma
+
+Here's an example `.babelrc` that sets the pragma:
+
+```
+{
+ "presets": ["es2015"],
+ "plugins": [
+ ["transform-react-jsx", {"pragma": "element"}]
+ ]
+}
+```
+
+## How does it work?
+
+JSX is just syntax sugar for creating object trees. You can use Deku perfectly fine without JSX, but if you're already using Babel you can use JSX without any extra work.
+
+Instead of writing each `element` call:
+
+```js
+function render (model) {
+ return (
+ element('button', { class: 'Button' }, [
+ element('span', { class: 'Button-text' }, ['Click Me!'])
+ ])
+ )
+}
+```
+
+You can write HTML:
+
+```js
+function render (model) {
+ return (
+
+ )
+}
+```
diff --git a/docs/basics/components.md b/docs/basics/components.md
new file mode 100644
index 0000000..512d44e
--- /dev/null
+++ b/docs/basics/components.md
@@ -0,0 +1,140 @@
+# Components
+
+Components are a way to define logical, re-usable pieces of your interface - tabs, buttons, forms. In Deku, components are just a special type of virtual element that is not rendered until it's needed. Internally, components are known as "thunks". This means that only the minimal number of virtual elements need to be re-created and patched on each render.
+
+In addition to providing a performance boost, you are able to hook into "lifecycle events" when a component is created, updated, or removed.
+
+Components are:
+
+* Plain objects with at least `render` function;
+* Able to provide a performance boost by caching the result of each render;
+* Uniquely identifiable using the `path` value, allowing you to store local state;
+* Able to trigger actions when they are created, updated, or removed;
+* Used like custom elements within your app
+
+Unlike React, components in Deku are completely stateless, there's no `setState` function or `this` used.
+
+## Example
+
+Here's a simple `` component:
+
+```js
+function render ({ props, children, context }) {
+ return (
+
+ {children}
+
+ }
+}
+
+function onCreate ({ props, dispatch }) {
+ dispatch({
+ type: 'APP_STARTED'
+ })
+}
+
+function onRemove ({ props, dispatch }) {
+ dispatch({
+ type: 'APP_STOPPED'
+ })
+}
+
+export default {
+ render,
+ onCreate,
+ onRemove
+}
+```
+
+To use this component within other components, you simply import and compose it:
+
+```js
+import App from './app'
+
+function render (model) {
+ return
+}
+
+export {
+ render
+}
+```
+
+And you can do the same at top-level using `render`, while also setting the `context`:
+
+```js
+render(, {
+ theme: {
+ color: 'red'
+ }
+})
+```
+
+## Model
+
+The model is passed into the Component function and is contains the state that you can use to create virtual nodes. The model is immutable
+
+```js
+function render ({ props }) {
+ return
Hello World
+}
+```
+
+### Properties
+
+#### `props`
+
+The values passed into your component as virtual element attributes. For example, passing these attributes into the component:
+
+```js
+
+```
+
+will yield this as `model.props`:
+
+```json
+{
+ "count": 5,
+ "type": "tasks"
+}
+```
+
+#### `children`
+
+The child nodes that are passed to the component.
+
+```js
+
+
+ Hello World
+
+```
+
+The `children` property will always be an array:
+
+```js
+[
+ ,
+ Hello World
+]
+```
+
+You can use this to render the passed in nodes somewhere within the rendered DOM.
+
+```js
+function render ({ children }) {
+ return
{children}
+}
+```
+
+#### `path`
+
+The unique path to the component within the entire component tree.
+
+```js
+function render ({ path }) {
+ return Save
+}
+```
+
+Paths in a tree are strings, like `0.1.5.2`. Each number represents the index of the node in the parent node, so you can use this to find a node within a tree. If a node within that path has a `key` attribute, we use that instead of the index so that the path is stable even if any elements move around.
diff --git a/docs/basics/elements.md b/docs/basics/elements.md
new file mode 100644
index 0000000..c369125
--- /dev/null
+++ b/docs/basics/elements.md
@@ -0,0 +1,59 @@
+# Virtual elements
+
+Virtual elements are objects that represent nodes in a tree, like the DOM. We call these 'virtual elements' because they create a fake DOM tree, a tree that looks like the real DOM but doesn't come with all the baggage of rendering real nodes.
+
+Virtual elements are objects:
+
+```js
+{
+ type: 'button',
+ attributes: { class: 'Button' },
+ children: ['Click me!']
+}
+```
+
+They have:
+
+* a `type` that can be any primitive value (e.g. string, object, or function);
+* `attributes` that describe it's features;
+* and `children`, which is just an array of more nodes.
+
+This is how you would write it in HTML:
+
+```html
+
+```
+
+But these objects aren't easy to read or write so we can use the `element` function provided by Deku to make this a little nicer:
+
+```js
+element('button', { class: "Button" }, ['Click Me!'])
+```
+
+This function signature is the same that is expected by [JSX](https://github.com/dekujs/deku/blob/master/docs/guides/jsx.md), so if you're using Babel you can use JSX. This will just compile back down to our simple `element` function above and end up becoming a plain object, just like what we started with:
+
+```js
+{
+ type: 'button',
+ attributes: { class: 'Button' },
+ children: ['Click me!']
+}
+```
+
+Deku just requires objects that look like that, which means you can use any library you want to create those nodes. If you wanted to add some custom functionality, you can wrap the element function with your own. For example, this would allow you to write the `class` attribute as an array or object:
+
+```js
+import {element} from 'deku'
+import classnames from 'classnames'
+
+export function magic (type, attributes, children) {
+ let vnode = element(type, attributes, children)
+
+ let classes = vnode.attributes.class
+ if (classes) {
+ vnode.attributes.class = classnames(classes)
+ }
+
+ return vnode
+}
+```
diff --git a/docs/basics/events.md b/docs/basics/events.md
new file mode 100644
index 0000000..42894e7
--- /dev/null
+++ b/docs/basics/events.md
@@ -0,0 +1,61 @@
+# Event handlers
+
+You can add event handlers using attributes. There are a number of attributes that Deku will recognize for you. These are treated as special attributes:
+
+```js
+let save = dispatch => event => {
+ dispatch({
+ type: 'SAVED'
+ })
+}
+
+let render = model => {
+ return
+}
+
+export default {
+ render
+}
+```
+
+These handlers will be added and removed for you. With each render, if the handler doesn't match the new handler, they are swapped.
+
+## How do I delegate events?
+
+The renderer doesn't automatically delegate events. To delegate events you can just add a handler on the parent element:
+
+```js
+let render = model => {
+ return (
+
+
1
+
2
+
3
+
+ )
+}
+
+let onClick = event => {
+ if (event.target.tagName === 'LI') {
+ console.log('clicked')
+ }
+}
+```
+
+You can probably find some libraries on npm to make this easier too.
+
+## How do I access my the model in an event handler?
+
+If you want to send extra information to the handler you can curry or partially apply the handler function. We don't provide any special parameters to the event handlers, so it's as if you called `el.addEventListener` directly.
+
+```js
+let render = model => {
+ return
Hello World
+}
+
+let onClick = model => event => {
+ console.log(model, e)
+}
+```
+
+Because the handler is changing the function on every render, it will add the new event listener each time like you'd expect.
diff --git a/docs/basics/getting-started.md b/docs/basics/getting-started.md
new file mode 100644
index 0000000..77862b1
--- /dev/null
+++ b/docs/basics/getting-started.md
@@ -0,0 +1,78 @@
+# Getting started
+
+Deku is a library that allows you to create and compose components that render virtual elements. Here's a basic example that we'll step through:
+
+```js
+import {dom, element} from 'deku'
+let {createRenderer} = dom
+let render = createRenderer(document.body)
+
+let MyButton = {
+ render: ({ children }) {
+ return
+ }
+}
+
+render(
+
+ Hello World!
+
+)
+```
+
+First, we're importing a library to create virtual elements.
+
+```js
+import h from 'virtual-element'
+```
+
+Unlike React and other libraries, the virtual elements used in Deku are plain objects with no knowledge of what's rendering them. We'll cover this in more detail in the next section.
+
+```js
+import {render} from 'deku'
+```
+
+Then we're importing the renderer.
+
+Deku exports two functions: `render` and `renderString`. These are essentially two included renderers for virtual elements for rendering to the DOM.
+
+The render function takes a DOM element to use as a container, a virtual element, and an optional context argument:
+
+```js
+render(DOMElement el, VirtualElement vnode, Object context)
+```
+
+This function is curried, allowing you to set the paramters and create new functions:
+
+```js
+let renderToContainer = render(containerEl)
+renderToContainer(
Hello!
)
+```
+
+In the example we also created a component. Components in Deku are functions:
+
+```js
+function MyButton (model, context) {
+ return
+}
+```
+
+They can also have other functions added to them called [lifecycle hooks](#lifecycle-hooks):
+
+```js
+MyButton.onCreate = function () {
+ console.log('created a new MyButton somewhere')
+}
+```
+
+If you're using ES6 modules, we can also just directly export functions:
+
+```js
+export default function MyButton (model) {
+ return
+}
+
+export function onCreate () {
+ console.log('created a new MyButton somewhere')
+}
+```
diff --git a/docs/basics/index.md b/docs/basics/index.md
new file mode 100644
index 0000000..441c5fb
--- /dev/null
+++ b/docs/basics/index.md
@@ -0,0 +1,9 @@
+# Basics
+
+Learn how to get started using Deku.
+
+* [Getting Started](./getting-started.md)
+* [Virtual Elements](./elements.md)
+* [JSX](./jsx.md)
+* [Events](./events.md)
+* [Components](./components.md)
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 0000000..b82eaf4
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,21 @@
+# Contributing
+
+Anyone is free to contribute to the project. Here are some general guidelines for contributing:
+
+#### Feature requests
+
+If you have a feature you'd like added, open up an issue first to discuss it with everyone. If the idea is accepted, it would be great if you would take the time to try and implement the feature and submit a pull request.
+
+You should also add documentation for any new feature you'd added. PRs with passing tests are much, much more likely to get merged in.
+
+#### Testing
+
+The tests are run using [hihat](https://github.com/Jam3/hihat). This runs the tape tests in an Electron window with just the console. To run the tests, run `make test`.
+
+#### Releasing
+
+Releases are created using [release-it](https://github.com/webpro/release-it). You'll need to install the `release-it` CLI tool. e.g. `release-it 2.1.3`
+
+### CI
+
+Whenever you push a branch to dekujs/deku the tests are run in CircleCI. The unit tests are then run on many browsers at once using SauceLabs.
diff --git a/docs/deku.d.ts b/docs/deku.d.ts
deleted file mode 100644
index dc884b2..0000000
--- a/docs/deku.d.ts
+++ /dev/null
@@ -1,363 +0,0 @@
-
-// CORE API
-// --------------------------------------------------------------------
-
-declare module "deku" {
-
- /**
- * Take an Application and paint it into the DOM at a given root node.
- */
- function render(tree: Application, root: Node): void;
-
- /**
- * Produce the image of an Application as an HTML string.
- * Used server-side pre-rendering.
- */
- function renderString(tree: Application): string;
-
- /**
- * Produces an Application tree from a VirtualNode tree.
- *
- * An Application appends environment and plugin information to
- * the virtual node, preparing it for rendering.
- */
- function tree
(virtualNode: VirtualNode
): Application;
-
- /**
- * Raw VirtualNode contruction API.
- *
- * Builds either "raw" DOM-like elements or "component-like" elements.
- */
- function element(tag: string): VirtualNode<{}, {}>;
- function element(tag: string, props: PropLike): VirtualNode<{}, {}>;
- function element(tag: string, props: PropLike, children: Child[]): VirtualNode<{}, {}>;
- function element
(spec: Spec
, props: P): VirtualNode
;
- function element
(spec: Spec
, props: P, children: Child[]): VirtualNode
;
-
- /**
- * Prop types are constrained and informed by three interfaces: HasChildren,
- * Evented, and Keyed.
- *
- * In practice, what this implies is two-fold. First, prop types will have "children"
- * appended in all circumstances once the component is mounted to the DOM. Custom Prop
- * types should therefore properly inherit this slot. Second, props may include both
- * event listener declarations and keys used for controlling tree diffing.
- */
- interface PropLike extends HasChildren, Evented, Keyed {}
-
- /**
- * VirtualNodes are abstract types that form a "skeletonized" DOM tree that
- * is much faster to construct, compare, and analyze.
- */
- class VirtualNode
{
- data: string;
- }
- type Child = VirtualNode | string;
-
- /**
- * An Application is a virtual tree extended with environment and plugin
- * information. In this form it is ready to mount to the browser DOM.
- */
- interface Application {
-
- /**
- * Set environment data.
- * Values set in the environment are available in components by
- * registering a 'source' in their proptype declaration.
- */
- set(name: string, value: any): void;
-
- /**
- * Set rendering options. Options include:
- *
- * - validateProps: boolean
- * Is propType validation enabled? There is a runtime penalty, so
- * it may be useful to disable in production.
- */
- option(name: string, value: any): void;
-
- /** Change the virtual element currently mounted */
- mount
(vnode: VirtualNode
): void;
-
- /** Use a plugin */
- use(fn: (app: Application) => any): void;
- }
-
-
-
- // COMPONENT API
- //
- // Components are modularized behavior which manages creation,
- // parameterization, and local state within a virtual subtree of the
- // DOM.
- // --------------------------------------------------------------------
-
- /**
- * A "live" component providing access to the current properties and state
- * at a current time of a component managing a virtual tree which is now
- * mounted.
- *
- * Users do not construct Components directly but instead create component
- * Specs which
- */
- interface Component
{
- props: P;
- state: S;
- id: string;
- }
-
- /**
- * Keys within a component's Property set may be configured and
- * deliminated by property specifications.
- */
- interface PropSpec {
- type?: string;
- expects?: Array;
- optional?: boolean;
-
- /**
- * A source string links the value of a property to a value which
- * must be present in the Application environment.
- */
- source?: string;
- }
-
- /**
- * A descriptor of Component creation, behavior, and lifecycle.
- *
- * Deku's primary interface is operated via specification of components.
- * Components are collections of behavior and state parameterized by immutable,
- * static properties. A value of type Spec
specifies a component of
- * type Component
with properties in type P and local state in type S.
- */
- interface Spec
{
-
- /** Define a name for the component that can be used in debugging */
- name?: string;
-
- /** Validate the props sent to your component */
- propTypes?: { [prop: string]: PropSpec };
-
- /**
- * Render a component. We need to pass in setState so that callbacks on
- * sub-components. This may change in the future.
- *
- * Client: Yes
- * Server: Yes
- */
- render: (component: Component
, setState: (newState: S) => void) => VirtualNode
;
-
- /**
- * Get the initial state for the component. We don't pass props in here like
- * React does because the state should just be computed in the render function.
- */
- initialState?: () => S;
-
- /** Default props can be defined that will be used across all instances. */
- defaultProps?: P;
-
- /** This is called on both the server and the client. */
- beforeMount?: (component: Component
) => any;
-
- /**
- * This is called after the component is rendered the first time and is only
- * ever called once.
- *
- * Use cases:
- * - Analytics tracking
- * - Loading initial data
- * - Setting the state that should change immediately eg. open/close
- * - Adding DOM event listeners on the window/document
- * - Moving the element in the DOM. eg. to the root for dialogs
- * - Focusing the element
- *
- * Client: Yes
- * Server: No
- */
- afterMount?: (component: Component
, el: Node, setState: (newState: S) => void) => any;
-
- /**
- * This is called once just before the element is removed. It should be used
- * to clean up after the component.
- *
- * Use cases:
- * - Unbind window/document event handlers
- * - Edit the DOM in anyway to clean up after the component
- * - Unbind any event emitters
- * - Disconnect streams
- *
- * Client: Yes
- * Server: No
- */
- beforeUnmount?: (component: Component
, el: Node) => any;
-
- /**
- * This is called on each update and can be used to skip renders to improve
- * performance of the component.
- */
- shouldUpdate?: (component: Component
, nextProps: P, nextState: S) => boolean;
-
- /**
- * Called before each render on both the client and server.
- *
- * Example use cases:
- * - Updating stream/emitter based on next props
- *
- * Client: Yes
- * Server: Yes
- */
- beforeRender?: (component: Component
) => any;
-
- /**
- * Called after every render, including the first one. This is better
- * than the afterUpdate as it's called on the first render so if forces
- * us to think in single renders instead of worrying about the lifecycle.
- * It can't update state here because then you'd be changing state based on
- * the DOM.
- *
- * Example use cases:
- * - Update the DOM based on the latest state eg. animations, event handlers
- *
- * Client: Yes
- * Server: No
- */
- afterRender?: (component: Component
, el: Node) => any;
-
- /**
- * This isn't called on the first render only on updates.
- *
- * Example use cases:
- * - Updating stream/emitter based on next props
- *
- * Client: Yes
- * Server: No
- */
- beforeUpdate?: (component: Component
, nextProps: P, nextState: S) => any;
-
- /**
- * Not called on the first render but on any update.
- *
- * Example use cases:
- * - Changing the state based on the previous state transition
- * - Calling callbacks when a state change happens
- *
- * Client: Yes
- * Server: No
- */
- afterUpdate?: (component: Component
, prevProps: P, prevState: S, setState: (newState: S) => void) => void;
- }
-
-
-
- // ANCILARY PROPERTY INTERFACES
- // --------------------------------------------------------------------
-
- /**
- * Prop types are assigned a slot to hold the children assigned to a component
- * after it has been built into the virtual tree; therefore, all Prop types
- * should recognize that they may also include a children slot.
- */
- interface HasChildren {
- children?: Array>;
- }
-
- /**
- * A component with Keyed properties can be more efficiently diffed under
- * the assumption that keys preserve identity between diffs.
- *
- * To be more particular, when diffing old and new virtual elements that
- * and children of the new element with keys that match the keys of the old
- * element are actually *the same* nodes which have perhaps merely moved.
- * Without this identity preservation over keys it would be necessary to
- * completely remove and replace all children more frequently.
- */
- interface Keyed {
- key?: string;
- }
-
- /**
- * An Evented property may contain keys corresponding to DOM events. The
- * EventListeners stored at these keys will be registered against the DOM
- * element corresponding to the virtual element with the given property.
- *
- * In Deku the events submitted are regular browser events---there is no
- * synthetic event system for canonicalization of browser event semantics.
- */
-
- interface EventListenerOf {
- (event: T): any;
- }
-
- // For listing and event details, see
- //
- interface Evented {
-
- // Element interaction events
- onFocus?: EventListenerOf;
- onBlur?: EventListenerOf;
- onChange?: EventListenerOf;
- onInput?: EventListenerOf;
-
- // Clipboard events
- //
- // Ought to be
- onCopy?: EventListenerOf;
- onCut?: EventListenerOf;
- onPaste?: EventListenerOf;
-
- // Drag events
- onDrag?: EventListenerOf;
- onDragEnd?: EventListenerOf;
- onDragEnter?: EventListenerOf;
- onDragExit?: EventListenerOf;
- onDragLeave?: EventListenerOf;
- onDragOver?: EventListenerOf
- onDragStart?: EventListenerOf;
- onDrop?: EventListenerOf;
-
- // UI events
- onScroll?: EventListenerOf;
-
- // Keyboard events
- onKeyDown?: EventListenerOf;
- onKeyUp?: EventListenerOf;
-
- // Mouse events
- onClick?: EventListenerOf;
- onDoubleClick?: EventListenerOf;
- onContextMenu?: EventListenerOf;
- onMouseDown?: EventListenerOf;
- onMouseMove?: EventListenerOf;
- onMouseOut?: EventListenerOf;
- onMouseOver?: EventListenerOf;
- onMouseUp?: EventListenerOf;
-
- // Form events
- onSubmit?: EventListenerOf;
-
- // Touch events
- //
- // Ought to be s
- onTouchCancel?: EventListenerOf;
- onTouchEnd?: EventListenerOf;
- onTouchMove?: EventListenerOf;
- onTouchStart?: EventListenerOf;
- }
-
-}
-
diff --git a/docs/examples/counter/index.css b/docs/examples/counter/index.css
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/examples/counter/index.js b/docs/examples/counter/index.js
deleted file mode 100644
index c394e51..0000000
--- a/docs/examples/counter/index.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import element from 'dekujs/virtual-element'
-import { render, tree } from 'dekujs/deku'
-
-const intervals = {};
-
-let Counter = {
- initialState () {
- return {
- secondsElapsed: 0
- }
- },
-
- render (component) {
- let { props, state } = component
- let { secondsElapsed } = state;
- return element('span', [ 'Seconds Elapsed: ' + secondsElapsed ]);
- },
-
- afterUpdate (component) {
- let { props, state } = component;
- if (state.secondsElapsed && state.secondsElapsed % 10 === 0) props.onAnEmittedEventFromCounter();
- },
-
- afterMount (component, el, setState) {
- let counter = 0;
- intervals[component.id] = setInterval(() => {
- setState({ secondsElapsed: counter++ })
- }, 1000);
- },
-
- beforeUnmount (component) {
- clearInterval(intervals[component.id]);
- delete intervals[component.id];
- }
-}
-
-function doSomething() {
- console.log('I did something.');
-}
-
-let counter = tree(
- element(Counter, { onAnEmittedEventFromCounter: doSomething })
-);
-
-render(counter, document.body);
diff --git a/docs/examples/counter/react.js b/docs/examples/counter/react.js
deleted file mode 100644
index 9d39603..0000000
--- a/docs/examples/counter/react.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from "react";
-
-class Counter extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- secondsElapsed: 0
- };
- }
-
- render () {
- let { secondsElapsed } = this.state;
- return (
- Seconds Elapsed: { secondsElapsed }
- );
- }
-
- componentWillUpdate() {
- let { secondsElapsed } = this.state;
- let { onAnEmittedEventFromCounter } = this.props;
- if (secondsElapsed && secondsElapsed % 10 === 0) onAnEmittedEventFromCounter();
- }
-
- componentDidMount () {
- let self = this;
- var counter = 0;
- this.interval = setInterval(() => {
- self.setState({ secondsElapsed: counter++ })
- }, 1000);
- }
-
- componentWillUnmount () {
- clearInterval(this.interval);
- }
-}
-
-function doSomething() {
- console.log('I did something.');
-}
-
-React.render(, document.body);
diff --git a/docs/examples/events/index.css b/docs/examples/events/index.css
deleted file mode 100644
index eed8d89..0000000
--- a/docs/examples/events/index.css
+++ /dev/null
@@ -1,4 +0,0 @@
-
-.active {
- background-color: yellow;
-}
diff --git a/docs/examples/events/index.js b/docs/examples/events/index.js
deleted file mode 100644
index 6342beb..0000000
--- a/docs/examples/events/index.js
+++ /dev/null
@@ -1,384 +0,0 @@
-/** @jsx element */
-
-import element from 'dekujs/magic-virtual-element'
-import { render, tree } from 'dekujs/deku'
-
-let timers = {};
-
-var MouseOver = {
- render (component, setState) {
- let {props, state} = component
- function hover() {
- setState({ hover: true })
- }
- function blur() {
- setState({ hover: false })
- }
- var classes = {
- 'box': true,
- 'active': state.hover === true
- }
- return (
-
- )
-}
-
-export default {propTypes,render}
diff --git a/docs/examples/todo/index.css b/docs/examples/todo/index.css
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/examples/todo/index.js b/docs/examples/todo/index.js
deleted file mode 100644
index 14c4ec5..0000000
--- a/docs/examples/todo/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/** @jsx element */
-
-import App from './app'
-import element from 'dekujs/virtual-element'
-import { render, tree } from 'dekujs/deku'
-
-// Initial todos
-var todos = [
- { text: 'Hello!' },
- { text: 'Buy milk' }
-]
-
-// Create the app
-var app = tree()
-
-// Set values on the tree that can be accessed by
-// any component by using propTypes and setting the 'source'
-// option to be 'removeTodo'
-app.set('removeTodo', function(todo){
- var newTodos = todos.filter(function(target){
- return target !== todo
- })
- app.mount(
-
- )
-})
-
-// Render into the DOM
-render(app, document.body)
diff --git a/docs/examples/todo/list.js b/docs/examples/todo/list.js
deleted file mode 100644
index ea64ba0..0000000
--- a/docs/examples/todo/list.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/** @jsx element */
-
-import element from 'dekujs/virtual-element'
-import Todo from './todo'
-
-// These are shared across all instances on the page
-let defaultProps = {
- items: []
-}
-
-// Optionally set prop types that will validate
-// whenever props are changed
-let propTypes = {
- items: {
- type: 'array'
- }
-}
-
-// Render the list
-function render (component) {
- let {props,state} = component
-
- let items = props.items.map(function (item) {
- return
- })
-
- return (
-
- )
-}
-
-export default {propTypes,render}
diff --git a/docs/guides/components.md b/docs/guides/components.md
deleted file mode 100644
index faa0aef..0000000
--- a/docs/guides/components.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# Components
-
-Components are re-usable pieces of your UI. You can think of components as custom elements you can use and compose, just like the native `