diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index b02ca099..6fb98646 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -17,15 +17,12 @@
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
-- [ ] Documentation change
-## Checklist:
+## Checklist
- [ ] My code follows the code style of this project.
-- [ ] My change requires a change to the documentation.
-- [ ] I have updated the documentation accordingly.
-- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
-- [ ] I have updated `docs/changelog.md`
+- [ ] My change requires a documentation update, and I've opened a pull request to update them already: https://github.com/MithrilJS/docs/pulls/NNNN
+- [ ] I have read https://mithril.js.org/contributing.html.
diff --git a/.github/workflows/issue-create.yml b/.github/workflows/issue-create.yml
index 8735af93..852f2a17 100644
--- a/.github/workflows/issue-create.yml
+++ b/.github/workflows/issue-create.yml
@@ -2,20 +2,11 @@ name: Ping triage on issue create
on:
issues:
types: [opened]
+ pull_request_target:
+ types: [opened]
permissions:
issues: write
repository-projects: write
jobs:
- add_triage:
- runs-on: ubuntu-latest
- steps:
- - run: gh issue edit "$ISSUE_URL" --add-project 'Triage/bugs'
- env:
- ISSUE_URL: ${{ github.event.issue.url }}
- GITHUB_TOKEN: ${{ github.token }}
-
- notify:
- uses: ./.github/workflows/_post-comment.yml
- with:
- url: ${{ github.event.issue.url }}
- message: '@MithrilJS/triage Please take a look.'
+ notify_triage:
+ uses: MithrilJS/infra/.github/workflows/notify-triage.yml@main
diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml
index 9b95880c..c69dd678 100644
--- a/.github/workflows/push-master.yml
+++ b/.github/workflows/push-master.yml
@@ -1,6 +1,6 @@
name: Warn on pushing to `master`
on:
- pull_request:
+ pull_request_target:
types: [opened]
branches: [master]
permissions:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 69bc69bb..4c491625 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,7 +1,7 @@
name: test
on:
- pull_request:
+ pull_request_target:
branches: [ next ]
workflow_dispatch:
workflow_call:
@@ -14,12 +14,6 @@ permissions:
# easier than parsing everything out.
jobs:
- lint-docs:
- uses: ./.github/workflows/_npm-task.yml
- with:
- task: lint:docs
- continue-on-error: true
-
lint-js:
uses: ./.github/workflows/_npm-task.yml
with:
diff --git a/docs/16.png b/docs/16.png
deleted file mode 100644
index f1794514..00000000
Binary files a/docs/16.png and /dev/null differ
diff --git a/docs/32.png b/docs/32.png
deleted file mode 100644
index a9c091ec..00000000
Binary files a/docs/32.png and /dev/null differ
diff --git a/docs/48.png b/docs/48.png
deleted file mode 100644
index 8da689d8..00000000
Binary files a/docs/48.png and /dev/null differ
diff --git a/docs/CNAME b/docs/CNAME
deleted file mode 100644
index 5c153480..00000000
--- a/docs/CNAME
+++ /dev/null
@@ -1 +0,0 @@
-mithril.js.org
diff --git a/docs/animation.md b/docs/animation.md
deleted file mode 100644
index c29884df..00000000
--- a/docs/animation.md
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-# Animations
-
-- [Technology choices](#technology-choices)
-- [Animation on element creation](#animation-on-element-creation)
-- [Animation on element removal](#animation-on-element-removal)
-- [Performance](#performance)
-
----
-
-### Technology choices
-
-Animations are often used to make applications come alive. Nowadays, browsers have good support for CSS animations, and there are [various](https://greensock.com/gsap) [libraries](https://github.com/julianshapiro/velocity) that provide fast JavaScript-based animations. There's also an upcoming [Web API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API) and a [polyfill](https://github.com/web-animations/web-animations-js) if you like living on the bleeding edge.
-
-Mithril.js does not provide any animation APIs per se, since these other options are more than sufficient to achieve rich, complex animations. Mithril.js does, however, offer hooks to make life easier in some specific cases where it's traditionally difficult to make animations work.
-
----
-
-### Animation on element creation
-
-Animating an element via CSS when the element is created couldn't be simpler. Just add an animation to a CSS class normally:
-
-```css
-.fancy {animation:fade-in 0.5s;}
-@keyframes fade-in {
- from {opacity:0;}
- to {opacity:1;}
-}
-```
-
-```javascript
-var FancyComponent = {
- view: function() {
- return m(".fancy", "Hello world")
- }
-}
-
-m.mount(document.body, FancyComponent)
-```
-
----
-
-### Animation on element removal
-
-The problem with animating before removing an element is that we must wait until the animation is complete before we can actually remove the element. Fortunately, Mithril.js offers the [`onbeforeremove`](lifecycle-methods.md#onbeforeremove) hook that allows us to defer the removal of an element.
-
-Let's create an `exit` animation that fades `opacity` from 1 to 0.
-
-```css
-.exit {animation:fade-out 0.5s;}
-@keyframes fade-out {
- from {opacity:1;}
- to {opacity:0;}
-}
-```
-
-Now let's create a contrived component that shows and hides the `FancyComponent` we created in the previous section:
-
-```javascript
-var on = true
-
-var Toggler = {
- view: function() {
- return [
- m("button", {onclick: function() {on = !on}}, "Toggle"),
- on ? m(FancyComponent) : null,
- ]
- }
-}
-```
-
-Next, let's modify `FancyComponent` so that it fades out when removed:
-
-```javascript
-var FancyComponent = {
- onbeforeremove: function(vnode) {
- vnode.dom.classList.add("exit")
- return new Promise(function(resolve) {
- vnode.dom.addEventListener("animationend", resolve)
- })
- },
- view: function() {
- return m(".fancy", "Hello world")
- }
-}
-```
-
-`vnode.dom` points to the root DOM element of the component (`
`). We use the classList API here to add an `exit` class to `
`.
-
-Then we return a Promise that resolves when the `animationend` event fires. When we return a promise from `onbeforeremove`, Mithril.js waits until the promise is resolved and only then it removes the element. In this case, it waits for the exit animation to finish.
-
-We can verify that both the enter and exit animations work by mounting the `Toggler` component:
-
-```javascript
-m.mount(document.body, Toggler)
-```
-
-Note that the `onbeforeremove` hook only fires on the element that loses its `parentNode` when an element gets detached from the DOM. This behavior is by design and exists to prevent a potential jarring user experience where every conceivable exit animation on the page would run on a route change. If your exit animation is not running, make sure to attach the `onbeforeremove` handler as high up the tree as it makes sense to ensure that your animation code is called.
-
----
-
-### Performance
-
-When creating animations, it's recommended that you only use the `opacity` and `transform` CSS rules, since these can be hardware-accelerated by modern browsers and yield better performance than animating `top`, `left`, `width`, and `height`.
-
-It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. If you want to animate a `box-shadow`, consider [putting the `box-shadow` rule on a pseudo element, and animate that element's opacity instead](https://tobiasahlin.com/blog/how-to-animate-box-shadow/). Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute positioned element over a fixed element).
diff --git a/docs/api.md b/docs/api.md
deleted file mode 100644
index 6141fb58..00000000
--- a/docs/api.md
+++ /dev/null
@@ -1,140 +0,0 @@
-
-
-# API
-
-### Cheatsheet
-
-Here are examples for the most commonly used methods. If a method is not listed below, it's meant for advanced usage.
-
-#### m(selector, attrs, children) - [docs](hyperscript.md)
-
-```javascript
-m("div.class#id", {title: "title"}, ["children"])
-```
-
----
-
-#### m.mount(element, component) - [docs](mount.md)
-
-```javascript
-var state = {
- count: 0,
- inc: function() {state.count++}
-}
-
-var Counter = {
- view: function() {
- return m("div", {onclick: state.inc}, state.count)
- }
-}
-
-m.mount(document.body, Counter)
-```
-
----
-
-#### m.route(root, defaultRoute, routes) - [docs](route.md)
-
-```javascript
-var Home = {
- view: function() {
- return "Welcome"
- }
-}
-
-m.route(document.body, "/home", {
- "/home": Home, // defines `https://example.com/#!/home`
-})
-```
-
-#### m.route.set(path) - [docs](route.md#mrouteset)
-
-```javascript
-m.route.set("/home")
-```
-
-#### m.route.get() - [docs](route.md#mrouteget)
-
-```javascript
-var currentRoute = m.route.get()
-```
-
-#### m.route.prefix = prefix - [docs](route.md#mrouteprefix)
-
-Invoke this before `m.route()` to change the routing prefix.
-
-```javascript
-m.route.prefix = "#!"
-```
-
-#### m(m.route.Link, ...) - [docs](route.md#mroutelink)
-
-```javascript
-m(m.route.Link, {href: "/Home"}, "Go to home page")
-```
-
----
-
-#### m.request(options) - [docs](request.md)
-
-```javascript
-m.request({
- method: "PUT",
- url: "/api/v1/users/:id",
- params: {id: 1, name: "test"}
-})
-.then(function(result) {
- console.log(result)
-})
-```
-
----
-
-#### m.parseQueryString(querystring) - [docs](parseQueryString.md)
-
-```javascript
-var object = m.parseQueryString("a=1&b=2")
-// {a: "1", b: "2"}
-```
-
----
-
-#### m.buildQueryString(object) - [docs](buildQueryString.md)
-
-```javascript
-var querystring = m.buildQueryString({a: "1", b: "2"})
-// "a=1&b=2"
-```
-
----
-
-#### m.trust(htmlString) - [docs](trust.md)
-
-```javascript
-m.render(document.body, m.trust("
Hello
"))
-```
-
----
-
-#### m.redraw() - [docs](redraw.md)
-
-```javascript
-var count = 0
-function inc() {
- setInterval(function() {
- count++
- m.redraw()
- }, 1000)
-}
-
-var Counter = {
- oninit: inc,
- view: function() {
- return m("div", count)
- }
-}
-
-m.mount(document.body, Counter)
-```
diff --git a/docs/autoredraw.md b/docs/autoredraw.md
deleted file mode 100644
index b5b50890..00000000
--- a/docs/autoredraw.md
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-# The auto-redraw system
-
-Mithril.js implements a virtual DOM diffing system for fast rendering, and in addition, it offers various mechanisms to gain granular control over the rendering of an application.
-
-When used idiomatically, Mithril.js employs an auto-redraw system that synchronizes the DOM whenever changes are made in the data layer. The auto-redraw system becomes enabled when you call `m.mount` or `m.route` (but it stays disabled if your app is bootstrapped solely via `m.render` calls).
-
-The auto-redraw system simply consists of triggering a re-render function behind the scenes after certain functions complete.
-
-### After event handlers
-
-Mithril.js automatically redraws after DOM event handlers that are defined in a Mithril.js view:
-
-```javascript
-var MyComponent = {
- view: function() {
- return m("div", {onclick: doSomething})
- }
-}
-
-function doSomething() {
- // a redraw happens synchronously after this function runs
-}
-
-m.mount(document.body, MyComponent)
-```
-
-You can disable an auto-redraw for specific events by setting `e.redraw` to `false`.
-
-```javascript
-var MyComponent = {
- view: function() {
- return m("div", {onclick: doSomething})
- }
-}
-
-function doSomething(e) {
- e.redraw = false
- // no longer triggers a redraw when the div is clicked
-}
-
-m.mount(document.body, MyComponent)
-```
-
-
-### After m.request
-
-Mithril.js automatically redraws after [`m.request`](request.md) completes:
-
-```javascript
-m.request("/api/v1/users").then(function() {
- // a redraw happens after this function runs
-})
-```
-
-You can disable an auto-redraw for a specific request by setting the `background` option to true:
-
-```javascript
-m.request("/api/v1/users", {background: true}).then(function() {
- // does not trigger a redraw
-})
-```
-
-
-### After route changes
-
-Mithril.js automatically redraws after [`m.route.set()`](route.md#mrouteset) calls and after route changes via links using [`m.route.Link`](route.md#mroutelink).
-
-```javascript
-var RoutedComponent = {
- view: function() {
- return [
- // a redraw happens asynchronously after the route changes
- m(m.route.Link, {href: "/"}),
- m("div", {
- onclick: function() {
- m.route.set("/")
- }
- }),
- ]
- }
-}
-
-m.route(document.body, "/", {
- "/": RoutedComponent,
-})
-```
-
----
-
-### When Mithril.js does not redraw
-
-Mithril.js does not redraw after `setTimeout`, `setInterval`, `requestAnimationFrame`, raw `Promise` resolutions and 3rd party library event handlers (e.g. Socket.io callbacks). In those cases, you must manually call [`m.redraw()`](redraw.md).
-
-Mithril.js also does not redraw after lifecycle methods. Parts of the UI may be redrawn after an `oninit` handler, but other parts of the UI may already have been redrawn when a given `oninit` handler fires. Handlers like `oncreate` and `onupdate` fire after the UI has been redrawn.
-
-If you need to explicitly trigger a redraw within a lifecycle method, you should call `m.redraw()`, which will trigger an asynchronous redraw.
-
-```javascript
-function StableComponent() {
- var height = 0
-
- return {
- oncreate: function(vnode) {
- height = vnode.dom.offsetHeight
- m.redraw()
- },
- view: function() {
- return m("div", "This component is " + height + "px tall")
- }
- }
-}
-```
-
-Mithril.js does not auto-redraw vnode trees that are rendered via `m.render`. This means redraws do not occur after event changes and `m.request` calls for templates that were rendered via `m.render`. Thus, if your architecture requires manual control over when rendering occurs (as can sometimes be the case when using libraries like Redux), you should use `m.render` instead of `m.mount`.
-
-Remember that `m.render` expects a vnode tree, and `m.mount` expects a component:
-
-```javascript
-// wrap the component in a m() call for m.render
-m.render(document.body, m(MyComponent))
-
-// don't wrap the component for m.mount
-m.mount(document.body, MyComponent)
-```
-
-Mithril.js may also avoid auto-redrawing if the frequency of requested redraws is higher than one animation frame (typically around 16ms). This means, for example, that when using fast-firing events like `onresize` or `onscroll`, Mithril.js will automatically throttle the number of redraws to avoid lag.
diff --git a/docs/buildPathname.md b/docs/buildPathname.md
deleted file mode 100644
index df1220e8..00000000
--- a/docs/buildPathname.md
+++ /dev/null
@@ -1,45 +0,0 @@
-
-# buildPathname(object)
-
-- [Description](#description)
-- [Signature](#signature)
-- [How it works](#how-it-works)
-
----
-
-### Description
-
-Turns a [path template](paths.md) and a parameters object into a string of form `/path/user?a=1&b=2`
-
-```javascript
-var pathname = m.buildPathname("/path/:id", {id: "user", a: "1", b: "2"})
-// "/path/user?a=1&b=2"
-```
-
----
-
-### Signature
-
-`pathname = m.buildPathname(object)`
-
-Argument | Type | Required | Description
------------- | ------------------------------------------ | -------- | ---
-`path` | `String` | Yes | A URL path
-`query ` | `Object` | Yes | A key-value map to be converted into a string
-**returns** | `String` | | A string representing the URL with the query string
-
-[How to read signatures](signatures.md)
-
----
-
-### How it works
-
-The `m.buildPathname` creates a [path name](paths.md) from a path template and a parameters object. It's useful for building URLs, and it's what [`m.route`](route.md) and [`m.request`](request.md) use internally to interpolate paths. It uses [`m.buildQueryString`](buildQueryString.md) to generate the query parameters to append to the path name.
-
-```javascript
-var pathname = m.buildPathname("/path/:id", {id: "user", a: 1, b: 2})
-
-// pathname is "/path/user?a=1&b=2"
-```
diff --git a/docs/buildQueryString.md b/docs/buildQueryString.md
deleted file mode 100644
index 1bbb8f5f..00000000
--- a/docs/buildQueryString.md
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-# buildQueryString(object)
-
-- [Description](#description)
-- [Signature](#signature)
-- [How it works](#how-it-works)
-
----
-
-### Description
-
-Turns an object into a string of form `a=1&b=2`
-
-```javascript
-var querystring = m.buildQueryString({a: "1", b: "2"})
-// "a=1&b=2"
-```
-
----
-
-### Signature
-
-`querystring = m.buildQueryString(object)`
-
-Argument | Type | Required | Description
------------- | ------------------------------------------ | -------- | ---
-`query` | `Object` | Yes | A key-value map to be converted into a string
-**returns** | `String` | | A string representing the input object
-
-[How to read signatures](signatures.md)
-
----
-
-### How it works
-
-The `m.buildQueryString` creates a querystring from an object. It's useful for manipulating URLs
-
-```javascript
-var querystring = m.buildQueryString({a: 1, b: 2})
-
-// querystring is "a=1&b=2"
-```
-
-#### Deep data structures
-
-Deep data structures are serialized in a way that is understood by popular web application servers such as PHP, Rails and ExpressJS
-
-```javascript
-var querystring = m.buildQueryString({a: ["hello", "world"]})
-
-// querystring is "a[0]=hello&a[1]=world"
-```
-
diff --git a/docs/censor.md b/docs/censor.md
deleted file mode 100644
index 96dde569..00000000
--- a/docs/censor.md
+++ /dev/null
@@ -1,151 +0,0 @@
-
-
-# censor(object, extra)
-
-- [Description](#description)
-- [Signature](#signature)
-- [How it works](#signature)
-
----
-
-### Description
-
-Returns a shallow-cloned object with lifecycle attributes and any given custom attributes omitted.
-
-```javascript
-var attrs = {one: "two", enabled: false, oninit: function() {}}
-var censored = m.censor(attrs, ["enabled"])
-// {one: "two"}
-```
-
----
-
-### Signature
-
-`censored = m.censor(object, extra)`
-
-Argument | Type | Required | Description
------------- | ------------------------------------------ | -------- | ---
-`object` | `Object` | Yes | A key-value map to be converted into a string
-`extra` | `Array` | No | Additional properties to omit.
-**returns** | `Object` | | The original object if no properties to omit existed on it, a shallow-cloned object with the removed properties otherwise.
-
-[How to read signatures](signatures.md)
-
----
-
-### How it works
-
-Ordinarily, you don't need this method, and you'll just want to specify the attributes you want. But sometimes, it's more convenient to send all attributes you don't know to another element. This is often perfectly reasonable, but it can lead you into a major trap with lifecycle methods getting called twice.
-
-```javascript
-function SomePage() {
- return {
- view: function() {
- return m(SomeFancyView, {
- oncreate: function() {
- sendViewHit(m.route.get(), "some fancy view")
- },
- })
- },
- }
-}
-
-function SomeFancyView() {
- return {
- view: function(vnode) {
- return m("div", vnode.attrs, [ // !!!
- // ...
- ])
- },
- }
-}
-```
-
-This looks benign, but this creates a problem: you're sending two hits each time this view is navigated. This is where `m.censor` come in: it lets you strip that `oncreate` from the attributes so it only gets called once and so the caller can remain sane and rest assured they aren't dealing with super weird bugs because of it.
-
-```javascript
-// Fixed
-function SomeFancyView() {
- return {
- view: function(vnode) {
- return m("div", m.censor(vnode.attrs), [
- // ...
- ])
- },
- }
-}
-```
-
-You can also run into similar issues with keys:
-
-```javascript
-function SomePage() {
- return {
- view: function() {
- return m(Layout, {
- pageTitle: "Some Page",
- key: someKey,
- }, [
- // ...
- ])
- },
- }
-}
-
-function Layout() {
- return {
- view: function(vnode) {
- return [
- m("header", [
- m("h1", "My beautiful web app"),
- m("nav"),
- ]),
- m(".body", vnode.attrs, [ // !!!
- m("h2", vnode.attrs.pageTitle),
- vnode.children,
- ])
- ]
- },
- }
-}
-```
-
-This would end up [throwing an error](keys.md#key-restrictions) because here's what Mithril.js sees when creating the `Layout` vnode:
-
-```javascript
-return [
- m("header", [
- m("h1", "My beautiful web app"),
- m("nav"),
- ]),
- m(".body", {pageTitle: "Some Page", key: someKey}, [
- m("h2", "Some Page"),
- [/* ... */],
- ])
-]
-```
-
-You wouldn't likely catch that at first glance, especially in much more real-world scenarios where there might be indirection and/or other issues. To correct this, you similarly have to censor out the `key:` attribute. You can also censor out the custom `pageTitle` attribute, too, since it doesn't provide any real value being in the DOM.
-
-```javascript
-// Fixed
-function Layout() {
- return {
- view: function(vnode) {
- return [
- m("header", [
- m("h1", "My beautiful web app"),
- m("nav"),
- ]),
- m(".body", m.censor(vnode.attrs, ["pageTitle"]), [
- m("h2", vnode.attrs.pageTitle),
- vnode.children,
- ])
- ]
- },
- }
-}
-```
diff --git a/docs/components.md b/docs/components.md
deleted file mode 100644
index 7ef3733f..00000000
--- a/docs/components.md
+++ /dev/null
@@ -1,673 +0,0 @@
-
-
-# Components
-
-- [Structure](#structure)
-- [Lifecycle methods](#lifecycle-methods)
-- [Passing data to components](#passing-data-to-components)
-- [State](#state)
- - [Closure component state](#closure-component-state)
- - [POJO component state](#pojo-component-state)
-- [Classes](#classes)
- - [Class component state](#class-component-state)
-- [Special attributes](#special-attributes)
-- [Avoid anti-patterns](#avoid-anti-patterns)
-
-### Structure
-
-Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
-
-Any JavaScript object that has a `view` method is a Mithril.js component. Components can be consumed via the [`m()`](hyperscript.md) utility:
-
-```javascript
-// define your component
-var Example = {
- view: function(vnode) {
- return m("div", "Hello")
- }
-}
-
-// consume your component
-m(Example)
-
-// equivalent HTML
-//
Hello
-```
-
----
-
-### Lifecycle methods
-
-Components can have the same [lifecycle methods](lifecycle-methods.md) as virtual DOM nodes. Note that `vnode` is passed as an argument to each lifecycle method, as well as to `view` (with the _previous_ vnode passed additionally to `onbeforeupdate`):
-
-```javascript
-var ComponentWithHooks = {
- oninit: function(vnode) {
- console.log("initialized")
- },
- oncreate: function(vnode) {
- console.log("DOM created")
- },
- onbeforeupdate: function(newVnode, oldVnode) {
- return true
- },
- onupdate: function(vnode) {
- console.log("DOM updated")
- },
- onbeforeremove: function(vnode) {
- console.log("exit animation can start")
- return new Promise(function(resolve) {
- // call after animation completes
- resolve()
- })
- },
- onremove: function(vnode) {
- console.log("removing DOM element")
- },
- view: function(vnode) {
- return "hello"
- }
-}
-```
-
-Like other types of virtual DOM nodes, components may have additional lifecycle methods defined when consumed as vnode types.
-
-```javascript
-function initialize(vnode) {
- console.log("initialized as vnode")
-}
-
-m(ComponentWithHooks, {oninit: initialize})
-```
-
-Lifecycle methods in vnodes do not override component methods, nor vice versa. Component lifecycle methods are always run after the vnode's corresponding method.
-
-Take care not to use lifecycle method names for your own callback function names in vnodes.
-
-To learn more about lifecycle methods, [see the lifecycle methods page](lifecycle-methods.md).
-
----
-
-### Passing data to components
-
-Data can be passed to component instances by passing an `attrs` object as the second parameter in the hyperscript function:
-
-```javascript
-m(Example, {name: "Floyd"})
-```
-
-This data can be accessed in the component's view or lifecycle methods via the `vnode.attrs`:
-
-```javascript
-var Example = {
- view: function (vnode) {
- return m("div", "Hello, " + vnode.attrs.name)
- }
-}
-```
-
-NOTE: Lifecycle methods can also be defined in the `attrs` object, so you should avoid using their names for your own callbacks as they would also be invoked by Mithril.js itself. Use them in `attrs` only when you specifically wish to use them as lifecycle methods.
-
----
-
-### State
-
-Like all virtual DOM nodes, component vnodes can have state. Component state is useful for supporting object-oriented architectures, for encapsulation and for separation of concerns.
-
-Note that unlike many other frameworks, mutating component state does *not* trigger [redraws](autoredraw.md) or DOM updates. Instead, redraws are performed when event handlers fire, when HTTP requests made by [m.request](request.md) complete or when the browser navigates to different routes. Mithril.js' component state mechanisms simply exist as a convenience for applications.
-
-If a state change occurs that is not as a result of any of the above conditions (e.g. after a `setTimeout`), then you can use `m.redraw()` to trigger a redraw manually.
-
-#### Closure component state
-
-In the above examples, each component is defined as a POJO (Plain Old JavaScript Object), which is used by Mithril.js internally as the prototype for that component's instances. It's possible to use component state with a POJO (as we'll discuss below), but it's not the cleanest or simplest approach. For that we'll use a **_closure component_**, which is simply a wrapper function which _returns_ a POJO component instance, which in turn carries its own, closed-over scope.
-
-With a closure component, state can simply be maintained by variables that are declared within the outer function:
-
-```javascript
-function ComponentWithState(initialVnode) {
- // Component state variable, unique to each instance
- var count = 0
-
- // POJO component instance: any object with a
- // view function which returns a vnode
- return {
- oninit: function(vnode){
- console.log("init a closure component")
- },
- view: function(vnode) {
- return m("div",
- m("p", "Count: " + count),
- m("button", {
- onclick: function() {
- count += 1
- }
- }, "Increment count")
- )
- }
- }
-}
-```
-
-Any functions declared within the closure also have access to its state variables.
-
-```javascript
-function ComponentWithState(initialVnode) {
- var count = 0
-
- function increment() {
- count += 1
- }
-
- function decrement() {
- count -= 1
- }
-
- return {
- view: function(vnode) {
- return m("div",
- m("p", "Count: " + count),
- m("button", {
- onclick: increment
- }, "Increment"),
- m("button", {
- onclick: decrement
- }, "Decrement")
- )
- }
- }
-}
-```
-
-Closure components are consumed in the same way as POJOs, e.g. `m(ComponentWithState, { passedData: ... })`.
-
-A big advantage of closure components is that we don't need to worry about binding `this` when attaching event handler callbacks. In fact `this` is never used at all and we never have to think about `this` context ambiguities.
-
-
----
-
-#### POJO component state
-
-It is generally recommended that you use closures for managing component state. If, however, you have reason to manage state in a POJO, the state of a component can be accessed in three ways: as a blueprint at initialization, via `vnode.state` and via the `this` keyword in component methods.
-
-#### At initialization
-
-For POJO components, the component object is the prototype of each component instance, so any property defined on the component object will be accessible as a property of `vnode.state`. This allows simple "blueprint" state initialization.
-
-In the example below, `data` becomes a property of the `ComponentWithInitialState` component's `vnode.state` object.
-
-```javascript
-var ComponentWithInitialState = {
- data: "Initial content",
- view: function(vnode) {
- return m("div", vnode.state.data)
- }
-}
-
-m(ComponentWithInitialState)
-
-// Equivalent HTML
-//
Initial content
-```
-
-#### Via vnode.state
-
-As you can see, state can also be accessed via the `vnode.state` property, which is available to all lifecycle methods as well as the `view` method of a component.
-
-```javascript
-var ComponentWithDynamicState = {
- oninit: function(vnode) {
- vnode.state.data = vnode.attrs.text
- },
- view: function(vnode) {
- return m("div", vnode.state.data)
- }
-}
-
-m(ComponentWithDynamicState, {text: "Hello"})
-
-// Equivalent HTML
-//
Hello
-```
-
-#### Via the this keyword
-
-State can also be accessed via the `this` keyword, which is available to all lifecycle methods as well as the `view` method of a component.
-
-```javascript
-var ComponentUsingThis = {
- oninit: function(vnode) {
- this.data = vnode.attrs.text
- },
- view: function(vnode) {
- return m("div", this.data)
- }
-}
-
-m(ComponentUsingThis, {text: "Hello"})
-
-// Equivalent HTML
-//
Hello
-```
-
-Be aware that when using ES5 functions, the value of `this` in nested anonymous functions is not the component instance. There are two recommended ways to get around this JavaScript limitation, use arrow functions, or if those are not supported, use `vnode.state`.
-
----
-
-### Classes
-
-If it suits your needs (like in object-oriented projects), components can also be written using classes:
-
-```javascript
-class ClassComponent {
- constructor(vnode) {
- this.kind = "class component"
- }
- view() {
- return m("div", `Hello from a ${this.kind}`)
- }
- oncreate() {
- console.log(`A ${this.kind} was created`)
- }
-}
-```
-
-Class components must define a `view()` method, detected via `.prototype.view`, to get the tree to render.
-
-They can be consumed in the same way regular components can.
-
-```javascript
-// EXAMPLE: via m.render
-m.render(document.body, m(ClassComponent))
-
-// EXAMPLE: via m.mount
-m.mount(document.body, ClassComponent)
-
-// EXAMPLE: via m.route
-m.route(document.body, "/", {
- "/": ClassComponent
-})
-
-// EXAMPLE: component composition
-class AnotherClassComponent {
- view() {
- return m("main", [
- m(ClassComponent)
- ])
- }
-}
-```
-
-#### Class component state
-
-With classes, state can be managed by class instance properties and methods, and accessed via `this`:
-
-```javascript
-class ComponentWithState {
- constructor(vnode) {
- this.count = 0
- }
- increment() {
- this.count += 1
- }
- decrement() {
- this.count -= 1
- }
- view() {
- return m("div",
- m("p", "Count: " + count),
- m("button", {
- onclick: () => {this.increment()}
- }, "Increment"),
- m("button", {
- onclick: () => {this.decrement()}
- }, "Decrement")
- )
- }
-}
-```
-
-Note that we must use arrow functions for the event handler callbacks so the `this` context can be referenced correctly.
-
----
-
-### Mixing component kinds
-
-Components can be freely mixed. A class component can have closure or POJO components as children, etc...
-
----
-
-### Special attributes
-
-Mithril.js places special semantics on several property keys, so you should normally avoid using them in normal component attributes.
-
-- [Lifecycle methods](lifecycle-methods.md): `oninit`, `oncreate`, `onbeforeupdate`, `onupdate`, `onbeforeremove`, and `onremove`
-- `key`, which is used to track identity in keyed fragments
-- `tag`, which is used to tell vnodes apart from normal attributes objects and other things that are non-vnode objects.
-
----
-
-### Avoid anti-patterns
-
-Although Mithril.js is flexible, some code patterns are discouraged:
-
-#### Avoid fat components
-
-Generally speaking, a "fat" component is a component that has custom instance methods. In other words, you should avoid attaching functions to `vnode.state` or `this`. It's exceedingly rare to have logic that logically fits in a component instance method and that can't be reused by other components. It's relatively common that said logic might be needed by a different component down the road.
-
-It's easier to refactor code if that logic is placed in the data layer than if it's tied to a component state.
-
-Consider this fat component:
-
-```javascript
-// views/Login.js
-// AVOID
-var Login = {
- username: "",
- password: "",
- setUsername: function(value) {
- this.username = value
- },
- setPassword: function(value) {
- this.password = value
- },
- canSubmit: function() {
- return this.username !== "" && this.password !== ""
- },
- login: function() {/*...*/},
- view: function() {
- return m(".login", [
- m("input[type=text]", {
- oninput: function (e) { this.setUsername(e.target.value) },
- value: this.username,
- }),
- m("input[type=password]", {
- oninput: function (e) { this.setPassword(e.target.value) },
- value: this.password,
- }),
- m("button", {disabled: !this.canSubmit(), onclick: this.login}, "Login"),
- ])
- }
-}
-```
-
-Normally, in the context of a larger application, a login component like the one above exists alongside components for user registration and password recovery. Imagine that we want to be able to prepopulate the email field when navigating from the login screen to the registration or password recovery screens (or vice versa), so that the user doesn't need to re-type their email if they happened to fill the wrong page (or maybe you want to bump the user to the registration form if a username is not found).
-
-Right away, we see that sharing the `username` and `password` fields from this component to another is difficult. This is because the fat component encapsulates its state, which by definition makes this state difficult to access from outside.
-
-It makes more sense to refactor this component and pull the state code out of the component and into the application's data layer. This can be as simple as creating a new module:
-
-```javascript
-// models/Auth.js
-// PREFER
-var Auth = {
- username: "",
- password: "",
- setUsername: function(value) {
- Auth.username = value
- },
- setPassword: function(value) {
- Auth.password = value
- },
- canSubmit: function() {
- return Auth.username !== "" && Auth.password !== ""
- },
- login: function() {/*...*/},
-}
-
-module.exports = Auth
-```
-
-Then, we can clean up the component:
-
-```javascript
-// views/Login.js
-// PREFER
-var Auth = require("../models/Auth")
-
-var Login = {
- view: function() {
- return m(".login", [
- m("input[type=text]", {
- oninput: function (e) { Auth.setUsername(e.target.value) },
- value: Auth.username
- }),
- m("input[type=password]", {
- oninput: function (e) { Auth.setPassword(e.target.value) },
- value: Auth.password
- }),
- m("button", {
- disabled: !Auth.canSubmit(),
- onclick: Auth.login
- }, "Login")
- ])
- }
-}
-```
-
-This way, the `Auth` module is now the source of truth for auth-related state, and a `Register` component can easily access this data, and even reuse methods like `canSubmit`, if needed. In addition, if validation code is required (for example, for the email field), you only need to modify `setEmail`, and that change will do email validation for any component that modifies an email field.
-
-As a bonus, notice that we no longer need to use `.bind` to keep a reference to the state for the component's event handlers.
-
-#### Don't forward `vnode.attrs` itself to other vnodes
-
-Sometimes, you might want to keep an interface flexible and your implementation simpler by forwarding attributes to a particular child component or element, in this case [Bootstrap's modal](https://getbootstrap.com/docs/4.1/components/modal/). It might be tempting to forward a vnode's attributes like this:
-
-```javascript
-// AVOID
-var Modal = {
- // ...
- view: function(vnode) {
- return m(".modal[tabindex=-1][role=dialog]", vnode.attrs, [
- // forwarding `vnode.attrs` here ^
- // ...
- ])
- }
-}
-```
-
-If you do it like above, you could run into issues when using it:
-
-```javascript
-var MyModal = {
- view: function() {
- return m(Modal, {
- // This toggles it twice, so it doesn't show
- onupdate: function(vnode) {
- if (toggle) $(vnode.dom).modal("toggle")
- }
- }, [
- // ...
- ])
- }
-}
-```
-
-Instead, you should forward *single* attributes into vnodes:
-
-```javascript
-// PREFER
-var Modal = {
- // ...
- view: function(vnode) {
- return m(".modal[tabindex=-1][role=dialog]", vnode.attrs.attrs, [
- // forwarding `attrs:` here ^
- // ...
- ])
- }
-}
-
-// Example
-var MyModal = {
- view: function() {
- return m(Modal, {
- attrs: {
- // This toggles it once
- onupdate: function(vnode) {
- if (toggle) $(vnode.dom).modal("toggle")
- }
- },
- // ...
- })
- }
-}
-```
-
-#### Don't manipulate `children`
-
-If a component is opinionated in how it applies attributes or children, you should switch to using custom attributes.
-
-Often it's desirable to define multiple sets of children, for example, if a component has a configurable title and body.
-
-Avoid destructuring the `children` property for this purpose.
-
-```javascript
-// AVOID
-var Header = {
- view: function(vnode) {
- return m(".section", [
- m(".header", vnode.children[0]),
- m(".tagline", vnode.children[1]),
- ])
- }
-}
-
-m(Header, [
- m("h1", "My title"),
- m("h2", "Lorem ipsum"),
-])
-
-// awkward consumption use case
-m(Header, [
- [
- m("h1", "My title"),
- m("small", "A small note"),
- ],
- m("h2", "Lorem ipsum"),
-])
-```
-
-The component above breaks the assumption that children will be output in the same contiguous format as they are received. It's difficult to understand the component without reading its implementation. Instead, use attributes as named parameters and reserve `children` for uniform child content:
-
-```javascript
-// PREFER
-var BetterHeader = {
- view: function(vnode) {
- return m(".section", [
- m(".header", vnode.attrs.title),
- m(".tagline", vnode.attrs.tagline),
- ])
- }
-}
-
-m(BetterHeader, {
- title: m("h1", "My title"),
- tagline: m("h2", "Lorem ipsum"),
-})
-
-// clearer consumption use case
-m(BetterHeader, {
- title: [
- m("h1", "My title"),
- m("small", "A small note"),
- ],
- tagline: m("h2", "Lorem ipsum"),
-})
-```
-
-#### Define components statically, call them dynamically
-
-##### Avoid creating component definitions inside views
-
-If you create a component from within a `view` method (either directly inline or by calling a function that does so), each redraw will have a different clone of the component. When diffing component vnodes, if the component referenced by the new vnode is not strictly equal to the one referenced by the old component, the two are assumed to be different components even if they ultimately run equivalent code. This means components created dynamically via a factory will always be re-created from scratch.
-
-For that reason you should avoid recreating components. Instead, consume components idiomatically.
-
-```javascript
-// AVOID
-var ComponentFactory = function(greeting) {
- // creates a new component on every call
- return {
- view: function() {
- return m("div", greeting)
- }
- }
-}
-m.render(document.body, m(ComponentFactory("hello")))
-// calling a second time recreates div from scratch rather than doing nothing
-m.render(document.body, m(ComponentFactory("hello")))
-
-// PREFER
-var Component = {
- view: function(vnode) {
- return m("div", vnode.attrs.greeting)
- }
-}
-m.render(document.body, m(Component, {greeting: "hello"}))
-// calling a second time does not modify DOM
-m.render(document.body, m(Component, {greeting: "hello"}))
-```
-
-##### Avoid creating component instances outside views
-
-Conversely, for similar reasons, if a component instance is created outside of a view, future redraws will perform an equality check on the node and skip it. Therefore component instances should always be created inside views:
-
-```javascript
-// AVOID
-var Counter = {
- count: 0,
- view: function(vnode) {
- return m("div",
- m("p", "Count: " + vnode.state.count ),
-
- m("button", {
- onclick: function() {
- vnode.state.count++
- }
- }, "Increase count")
- )
- }
-}
-
-var counter = m(Counter)
-
-m.mount(document.body, {
- view: function(vnode) {
- return [
- m("h1", "My app"),
- counter
- ]
- }
-})
-```
-
-In the example above, clicking the counter component button will increase its state count, but its view will not be triggered because the vnode representing the component shares the same reference, and therefore the render process doesn't diff them. You should always call components in the view to ensure a new vnode is created:
-
-```javascript
-// PREFER
-var Counter = {
- count: 0,
- view: function(vnode) {
- return m("div",
- m("p", "Count: " + vnode.state.count ),
-
- m("button", {
- onclick: function() {
- vnode.state.count++
- }
- }, "Increase count")
- )
- }
-}
-
-m.mount(document.body, {
- view: function(vnode) {
- return [
- m("h1", "My app"),
- m(Counter)
- ]
- }
-})
-```
diff --git a/docs/es6.md b/docs/es6.md
deleted file mode 100644
index b673f7d1..00000000
--- a/docs/es6.md
+++ /dev/null
@@ -1,189 +0,0 @@
-
-# ES6+ on legacy browsers
-
-- [Setup](#setup)
-- [Using Babel with Webpack](#using-babel-with-webpack)
-
----
-
-Mithril.js is written in ES5, but it's fully compatible with ES6 and later as well. All modern browsers do support it natively, up to and even including native module syntax. (They don't support Node's magic module resolution, so you can't use `import * as _ from "lodash-es"` or similar. They just support relative and URL paths.) And so you can feel free to use [arrow functions for your closure components and classes for your class components](components.md).
-
-But, if like many of us, you still need to support older browsers like Internet Explorer, you'll need to transpile that down to ES5, and this is what this page is all about, using [Babel](https://babeljs.io) to make modern ES6+ code work on older browsers.
-
----
-
-### Setup
-
-First, if you haven't already, make sure you have [Node](https://nodejs.org/en/) installed. It comes with [npm](https://www.npmjs.com/) pre-bundled, something we'll need soon.
-
-Once you've got that downloaded, open a terminal and run these commands:
-
-```bash
-# Replace this with the actual path to your project. Quote it if it has spaces,
-# and single-quote it if you're on Linux/Mac and it contains a `$$` anywhere.
-cd "/path/to/your/project"
-
-# If you have a `package.json` there already, skip this command.
-npm init
-```
-
-Now, you can go one of a couple different routes:
-
-- [Use Babel standalone, with no bundler at all](#using-babel-standalone)
-- [Use Babel and bundle with Webpack](#using-babel-with-webpack)
-
-#### Using Babel standalone
-
-First, we need to install a couple dependencies we need.
-
-- `@babel/cli` installs the core Babel logic as well as the `babel` command.
-- `@babel/preset-env` helps Babel know what to transpile and how to transpile them.
-
-```bash
-npm install @babel/cli @babel/preset-env --save-dev
-```
-
-Now, create a `.babelrc` file and set up with `@babel/preset-env`.
-
-```json
-{
- "presets": ["@babel/preset-env"],
- "sourceMaps": true
-}
-```
-
-And finally, if you have *very* specific requirements on what you need to support, you may want to [configure Browserslist](https://github.com/browserslist/browserslist) so Babel (and other libraries) know what features to target.
-
-*By default, if you don't configure anything, Browserslist uses a fairly sensible query: `> 0.5%, last 2 versions, Firefox ESR, not dead`. Unless you have very specific circumstances that require you to change this, like if you need to support IE 8 with a lot of polyfills, don't bother with this step.*
-
-Whenever you want to compile your project, run this command, and everything will be compiled.
-
-```bash
-babel src --out-dir dist
-```
-
-You may find it convenient to use an npm script so you're not having to remember this and typing it out every time. Add a `"build"` field to the `"scripts"` object in your `package.json`:
-
-```json
-{
- "scripts": {
- "build": "babel src --out-dir dist"
- }
-}
-```
-
-And now, the command is a little easier to type and remember.
-
-```bash
-npm run build
-```
-
-#### Using Babel with Webpack
-
-If you want to use Webpack to bundle, it's a few more steps to set up. First, we need to install all the dependencies we need for both Babel and Webpack.
-
-- `webpack` is the core Webpack code and `webpack-cli` gives you the `webpack` command.
-- `@babel/core` is the core Babel code, a peer dependency for `babel-loader`.
-- `babel-loader` lets you teach Webpack how to use Babel to transpile your files.
-- `@babel/preset-env` helps Babel know what to transpile and how to transpile them.
-
-```bash
-npm install webpack webpack-cli @babel/core babel-loader @babel/preset-env --save-dev
-```
-
-Now, create a `.babelrc` file and set up with `@babel/preset-env`.
-
-```json
-{
- "presets": ["@babel/preset-env"],
- "sourceMaps": true
-}
-```
-
-Next, if you have *very* specific requirements on what you need to support, you may want to [configure Browserslist](https://github.com/browserslist/browserslist) so Babel (and other libraries) know what features to target.
-
-*By default, if you don't configure anything, Browserslist uses a fairly sensible query: `> 0.5%, last 2 versions, Firefox ESR, not dead`. Unless you have very specific circumstances that require you to change this, like if you need to support IE 8 with a lot of polyfills, don't bother with this step.*
-
-And finally, set up Webpack by creating a file called `webpack.config.js`.
-
-```javascript
-const path = require('path')
-
-module.exports = {
- entry: path.resolve(__dirname, 'src/index.js'),
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: 'app.js',
- },
- module: {
- rules: [{
- test: /\.js$/,
- exclude: /\/node_modules\//,
- use: {
- loader: 'babel-loader'
- }
- }]
- }
-}
-```
-
-This configuration assumes the source code file for the application entry point is in `src/index.js`, and this will output the bundle to `dist/app.js`.
-
-Now, to run the bundler, you just run this command:
-
-```bash
-webpack -d --watch
-```
-
-You may find it convenient to use an npm script so you're not having to remember this and typing it out every time. Add a `"build"` field to the `"scripts"` object in your `package.json`:
-
-```json
-{
- "scripts": {
- "start": "webpack -d --watch"
- }
-}
-```
-
-And now, the command is a little easier to type and remember.
-
-```bash
-npm start
-```
-
-For production builds, you'll want to minify your scripts. Luckily, this is also pretty easy: it's just running Webpack with a different option.
-
-```bash
-webpack -p
-```
-
-You may want to also add this to your npm scripts, so you can build it quickly and easily.
-
-```json
-{
- "scripts": {
- "start": "webpack -d --watch",
- "build": "webpack -p"
- }
-}
-```
-
-And then running this is a little easier to remember.
-
-```bash
-npm run build
-```
-
-And of course, you can do this in automatic production build scripts, too. Here's how it might look if you're using [Heroku](https://www.heroku.com/), for example:
-
-```json
-{
- "scripts": {
- "start": "webpack -d --watch",
- "build": "webpack -p",
- "heroku-postbuild": "webpack -p"
- }
-}
-```
diff --git a/docs/examples.md b/docs/examples.md
deleted file mode 100644
index e591936b..00000000
--- a/docs/examples.md
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-# Examples
-
-Here are some examples of Mithril.js in action
-
-- [Animation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/animation/mosaic.html)
-- [Community Added Examples](https://how-to-mithril.js.org)
-- [DBMonster](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/mithril/index.html)
-- [Markdown Editor](https://raw.githack.com/MithrilJS/mithril.js/master/examples/editor/index.html)
-- SVG: [Clock](https://raw.githack.com/MithrilJS/mithril.js/master/examples/svg/clock.html), [Ring](https://raw.githack.com/MithrilJS/mithril.js/master/examples/svg/ring.html), [Tiger](https://raw.githack.com/MithrilJS/mithril.js/master/examples/svg/tiger.html)
-- [ThreadItJS](https://raw.githack.com/MithrilJS/mithril.js/master/examples/threaditjs/index.html)
-- [TodoMVC](https://raw.githack.com/MithrilJS/mithril.js/master/examples/todomvc/index.html)
-- [Conway Game Of Life](https://flems.io/#0=N4IgtglgJlA2CmIBcAWFA6ATCgNCAzgMYBOA9rLMgNoCsOmA7ALp4BmEC+1oAdgIZhESEOgAWAFzCU8hUj3Hx5yECAC+OXgKEiAVlxlyFS4bJ75xAAgDK44vAEWLAXgth05uwIA6PU+YuyYAAOpPjwzhYASuiBIWE+fpbEfDwA5uEu0clp8Aly-gDuEOKipACulpnoRSXl4nlmlgBufLBl8PgR0S1tHT4N-vgQAEawEGkAwqSkxFCdLlRUALQAjDgWAAwsy2sWK9sb6-s4VLvHp+tbJ7urB+u3J6v3+0z9vvmWYKRQ8LARwD5HBB8JEyjweONUkhrLZ7GAABSsVphACUOEBFmGpD4s2hwHUGJ+sD4AE9oTZPAiVhsaWiMdkoKRIAAveBQcmwgTwlY0Ok8RxDVkcynwgDMGz5jiKUBKwrh8IAHLT0fyLGNWPBCCTCAg5VyJT5VG9EhY7OYcZULPCwHAUc4AHwWAGqm2wdDA0HgyGI5HwFEY13oImk7k0g0uuDoBlMiCsqDc3kByOC+Bi8OOQPSkqK2lJt3qzXahDw9Om+DiMrEfmuw1vAaWGqicYAIXKPDmEXhY0g4jtTkd8NkMzmfftGIAhIPprN8O7fG0fvguxAe3aAD5rgLTuZznVlRfw1Yo-08esWcSkKwjMZpACy31+nb4hEI6yGo0ho6dGOfhCo75vVImAiJFYHiVU7ArKsLF-WtT3eRoAlaQgrw-NJ5itbtii-eF3ymYd8BwocZ1HDE8O3fAMUcdAwD4IJ4VwkYv3-EYqC2CwAGotwItiWAsd9TmArjiLmQSmBPRxqPYWAFGIeFGxbNs5mXVcJMkqM2TKQhUwvVDAPvIl1nxE8z1ogBreAJl+P4XGtW0HStFMcOgAAPL9nUcBBLBEjCqFciwAFJ+NjeB1lvPgSnQVhYGneF-IAemC1kUVeVUvOCtDUgwwhkL0yElycxjMvwkipwItT0u0ih-ioiwLLJCxXJVSSLB6dpoS8EBOuayTgQAQTGJp4GhUCwh6xwfPGjLAMo1UjQjN0sRxKAqB84CXCq2A3kcSDK2rOA4NMvgLNbZaADEyDAK9WU7V03xC9y83cELGOS+lyz200UnSEt7pugAqJK-RoujrWOyzrLs2AUVev0T3ms8ctgQgymJBQrOq2zXUe1UAHlhh0TVxHQeql0DJbZhREH6MHaycZayrrPwAaICGiJGzqeEqFG+A+LajoofQCmVs2phnsywiqYQNISm23rWCtcnsVmVbrLF-rBr9b9VRaiAFdpihmc1iwAB4XEwO0PJaySleW1WKHVo3WYyCwedqxwEZ1+WrSoTB1lFdX533AXNqdobj2162bcjYX7dgR2WbZlxbHad2LE9qO9atUPE-CR1RUttOMxj5WRbV90w5dt2vY92rVAsX4wkj62s4NsDc+cFwC+bqPbZV0WK475PiFTmv07rjFVDU3boJrHhPZNMogigCL4Dy9Dbvs-tm-xwnCGJ0nBeFqnaJpzbSK93eiZJ+ASTJku7YHgD8pP0G06KwCL6jxwj9LuOxefuhFimV1quAfirQBQFB6azUo4NSJkIIfVngdeexoPimjBAAcVxgAGU3tDByVtW6Bg9GCCEaR4QRytsXfMetCw6lTIGAsWoGGUM4nsWB-FywABUVzwE5mw7e1CbYaSgMkAolC04z35CPHg2CcHwiXivdGTMobHjrusQMwYSSULUvXRu4RhHSLAVtOah0EL+GjCyCGht8H0zVOWL67YmQYzAhEK++8b531-stTh7gZjiAYl+DY6AaAWCWBYcKkUrG6Nqu4MY2lfqRIiqIKKMUZgMUDFYkK8Y7SJWpBKCwgNBYpjYYDQMpTjzqPgjtFIjIwCuNnKfBi58HI+P7uXDWzsIgpzhnLYxc9PZnnGMUU6swIiugco4YAjgAzgzGVAC6TJrqMLgOsAAcmUMAwx4ByQqS9KpGISD2AUFYeAbI1HmJNOZeA6z4AFEwVoCZcAHIZEdFbM04gLSXNVCM8QCyfkL3QXwKALRfDwBwXQiYRYXaTO3vCLWQinqkK9BQnmakmF0JYcWTFGpsWpjtFxFYaklGr0aYCtBiFUikDOgE0QzybIDkRe85FIIyHel6dPLBuCKXwRNNkm6Lg4VMtHFbLJdSYxxgRegL5xB0jE35mpP5ALsZXPQWEcQAARX4pIGVtOZSYoMOqdHwBlTieV6BFWUsGOWBZKy9XwoNWK5ML1TWyotVa35EJ-ml15WeUlKjbEbSZHEVMSMUZoxsbAdYAa17XhfojTwpzzlQAiLEUIqZY3ryyusAVUbCLWssK4mqqomgQHudCeEMyIq2HwHiEx6xNrp3TvYnaSDqzwk6jEay3Ue6SR1HwfAdaAjWWgd0gA-BYTqrRnadQsB1EAPwQXdTTuYEkuo+0tVYIYFZ0IAAGAASYAmZoDZjyYaypFhEqYFUEEFye6potVEPACAqQJD7qPSemUog2GJX2ayX9Fgb13ofUXV2CAXL7pWHsCwn7IxZh-ee-9BLb33rTgSMecgdQQEIGZStrbrZ9zLhQGIFEE7GxcOOTaY6hpgazfG9CPyo7zRalPSearEILM7NW8Qtb62TPrlPQhcyTqlyWVdF6d0LCbO2bskpBzqltqgvyYRcg-mVp43xp0Jjm1Ce3sc1eZyLnYymmWitVpNPEGHTMgTLbhNjwGZ2sesyRDCxXc57Ta6N0zIQx+498HT2IdQ3u3Tj7JIeIPrfe+i1S6vzPtuAjUdGaY0NbHESqVv6SUc64oydVb7Qmo-VRt1lNEvLYx58rUdOEsfHqgvl6CACSPAggVE7PY4xwizMFA0zBXjVn+NrLVHwHZ0bXDjE0XwFyb4FBBHWPzdYrB+SCeYmnBEnViQjd7VQDbvwwtrZAOMFr4gqDiBJEEeATgADkPAtk7OIJd14IAjJgcOxUL4PxoTXa2bsnDl2wuOCCDW3ZPAkCdTYksAAnEwf67nMuQB4P91wk3EfmHgLNsD82wNYdEN9YaDcHKLYRZwj2xOLDiVqhl2rQLOMVAvPyWy7X219q60gKtNb+v+dGzt0bi3VB6cdGtjznVhi07kL24AWGEl4atAawnfoMOZe52nPRHH-DcNIEESIpACglscCztnfW62c75yifsVEESXZlRrrXBQ-sWCoAiZsouEdOik4t6ENy7kPK0Go9Y3PPte4sI8wQl2p57fhE73jcgjJu5BzBUFKRtKQo1NC1hJmhsjdByAPqCfwUweT-QhAnUw+rYj87mPg33fUtpcQbM6f-edUwaQCwNfZZqBSvDQtFhWxR7ADb3XrVy3dYN3x43U8zdewt0LUgvebd-aoKXprR3ctSf9xYS7kQJXWPhAFFESA7fw6QIcJHkGCnTbR0gXY-MkDiucdY3JC2Qd5rUS28PS+Kgr8G2vy72riQ6LAIRPvpouMEfhNqfmGOfkEJfjSHNq0O1FosapQo-kgBqr-iGNjK-ovs1h-tpqvsNr8J9imEAWNiDuKGAdAcfqjlAdSLAb0Dfi6gBmiK7HHhqnapJvZFPOTnVmnGeOruQMMDiAPizhZr1lpjZmVnZhPi1PtlbvwTiFtqXurprtrhXrACXmPI7jPheH3ioa7nAJVpJFwdTv4MHvALjKwAXkIUPj1uztZjpstvZi1I5l2qYF8uMLsgoRofCHwbAAIcQJ-n8Oob3BHqXM9h5nPMxpKIRp2iAKIJgL2nuswjCtCHBrQnijCpQqoHupwlwbXNwTwG4F8GCIEoyCjIIPINPlACSBYEZPrl+AiKYeYQXqoTfg+GoSiFPE9iALEBwLssoAISNl0WEAgPvBAPkMoDyKKJfmoBoCAPwIIMoDEEOl0a4YoOIMoIDFbNuvIEsEiJALAA1PePIGEMQMkOIOsFYCkPgEsGcsQHrAANwYhLAFDwDDBmTFBLBYguRLCCiQjQhYizC7KfGkAuSPGqhLBfDMjAnfG-FpD-HDhAlfFgmOBfE-Gxh-GYgInEDQnIkWB1A3h448ByDwBgmeyyG+GCFWwElLDPqvrvoWAMAbB3q4mA4wAYnUjMkYgAk-DEDQgrB3r8TkDQAWAADEmorAGwrAKwuJOgZQ5gesJISwqx8g0I+AgO2knx5YLxigpJbwVuyhOuVsUAwIQQf+I0EGuJ0U8A3x0U2u0IBQyQQQMpcp4gCpSphgaxqp6p8ASwOISkup8E0+s+2uzcxpapZp4G1plpEGuxMU3WFgDpdEzp8prAipyp4gXpz4PpfpYIUAAZPgIuUeKm-Q4gqJ+AOOjI8ZTJLkew1ZewKAApSwDAApIpjAAAbAqAwKKGCV4KWc+GZKkGQLmUgASTiEsIOSCuWvIPCBeJib3usCKTQBDhDsMMMKKBYDQAFAuSgBsAqIQMubWRsLvj2X2bhoOUpO6TFLyYucuaud2SWdyUCckMaXKUgAqJyaeOIGGaaaSEgOMNSaMKQLhieSjFZjMEgCEOMLJCBeQOBSKawAhYhSedseILsQIBwGSH1Hca0MhYYGiUKJgNWbhTsS8XSRmViLAHmSWaycaXCSsKKAKaKJgB+b2QoC5KhT8LIGcWMSDkSTwCSSWWxaheWSCnaXWfyTWXWSKaKFAAwB2XwAGYWXTkgKUENMQNrL2QIWeUOe2COe4WOROcaWsTOc3liPOaKTuXuQeZuQuUuSuWuYeceQ+f2eebmZeXBZZfuRDopc7kgM+K6WzM6L2XEMUDxUgHYGjM7CeReNQR+Z7NzhYI6JsRiDReyURXMnKiAbWSxaeQOTpeyKKSsMNvuYQDBVedCPBQhcRcJSFHyfAGACedSbSW+hmRYOKDlUJb6WMKkHHtpPILstFdacJRWXaZsHsAKRsKaKkAIfCJgDQHQHNQtfNTgCEhbCeY+dic+RAK+XsDQHFXqcLKGSaRGVaaCRiKdbGaNYmU6RiL5hYEqOlaqFpXlUpBVeKZKdKeYt2tVEacdb+ZGWdaqDOj1UsMUPVcOn1dBRiLKSmWmR6SqSOv1cQLiRtXyQKfgEKamiKQqPAGgCCriaBRjbyRYJBUjfmTwOgDOoFVyS5flRVTjXjVRfkUaiCs3M9a5bpaKe9VKaSUMb8ETDxVwMIDQJfm2WoCwCADeGZELVQJoAscID2KIHcdICAJWJQMIBIOIEEHWvFPFGCEEAOaRmAPFIrcrQAAKYDoAhIoAm3FBK0cA0TjDoB6BdGnbnbKBEB3FBDrHqBy3aDJA2h8BdFq3KCa3a1IC6362G2BDxQB0rxm2rVtnoArDxRhniCx0CAryO0U0u14Bu3aCe0QDe0zF+3KCm0cA-GchgDB3EDq2xG8bh2R3NbR1Mi20lDK2V2UgW1W1W3xQeBwjO36AgD50e0kBF0+1MCqBAA)
-- [Tic Tac Toe](https://flems.io/#0=N4IgzgxgTg9gNnEAuA2gBgDRoLoZAMwEs4BTMZFUAOwEMBbE5EAOgAsAXOxPCGK9kvyYAeOISoBrAASsoJfAF4AOiA7sADmCQB6bfj7swzAOYwYx0jXWEjvOtohgwAfnz1iATwUBZGlTA0cABuNABkACY26nA0XmAA7lYqUnJwyuDsHqRgrCQk7CoAfCB4YCSkEOyEfORIIGhIAKwATAC0DQBsaCAAvhjU9Ix1zABW5DwGguxMvP7sUgDK7HL0UgpSdMxgyyT0SlT7s9tSEIEQAOqE4eysaxvhcGuFUsD7UvdwzPFXNwAU31RwjB4sxxFQSFBLtdWABKN4pfIAVygVA++x6+0ONXmxnyACU-EC6ABJfh3X50cQYDY0AAeMKeUl8N2Y+DgZigv2ZrGYUEJMDovwZACopL8AIxSADUNNpUlaG3EDJllKocIOVCO82isQhYDur1RUmWiJISBekBgciQmBpUAk5oA5AANR1SPrwtxwMrm4CW61SW10Gj2p0AeUdHqoGM12KkACMYCHwgtCAAvMh3PGs4gCTm-NWM1EAUikAGY1us0FIMNm+VRcb9MF0YerMbG5lJcewACKEGjGACC0BgTjWvxoEAg1LK7GpV3pjMN71I8ygd0nEGYs1O7F+s5QC+w6vecnYyNRUHR7a1XfyfYHPeBqIUE6nM-y8-Ci4Uz2XUlXFINynbc+F3fd8hQWdmFIBsbnlMUF2lKRxRhY94TPC8UmvDVbwBKhxGMBZ8gAIQ8O46AeJd4UIfAKQeLZ0xIBlgHed54RXfIpDAdRJ0zdY6z8RtxWpejPjAJipFFSjxMkmVUJPNjANnMBh1gMcBK2aJCHYABRIIIQ8MTGIzGdeIgMhFM4+YVKfeIXykbNlj8HjRxICDDDU0cwCsgCuNs-shxHDTuPyVTgqMORwkRCzfm7B8gvUsBqRQdCjWs0LDASuyHNs59eRIaLYviwKcpStK2L8+Z8MI-V1hUrynFAzUaD3PL7JhZrwKgsKEsasBsC61rfh6rLSufY9fMwlEpBqhswHhHopHKMoXg4hFthDPcZMUmMYyxTsZINeF8IhYjDFQXATrBCEkCoREEAweFzxRc0TRIJ6jR1Dw9WpeFE2TO6HrgT73gkjNzUwa7oXNJYVkFAAONA0HVfaO2OYN7WIioBBTcySHJGTqQkEgPGpTGJAZX81qNW8eL4rMczgPNfmzdRYHUXSAEdfkdEmPEdYnSZhDAZOYAGoHCRTAMRdRwlawqFnxxnZ1ZmDBDAAAFDneZCOBTUdEWKepbNchocJ93xkWPnFpNJelrjxHCEg5U0ohAVJZ3aTV9mYE5nm+dJwX+dbYyJal+ExfDu5HNBfwIT3J2XYwWX5dxpW+NrL4dNYGBETa-HRYY8PWwwpEZpknCDoxkMJAJQEBQziyKKo6n-0Akg6HUTIm-4m3w6Zlm2Y57ndcCA2MEdQ2HfmQdiV7u5O+7jxe7AFBu3rolST3W0l57-GjFg4x4IVVDsHhABCMXTvXUJQikOeF7vu0JF7sSYV+R+rbLl7UUr6MbxxlTgrAAKlhdYR026RwYr-O4V8YEXh-lhI6Ugq7o3mDYS4VACINgXusMSQsPBUz-PCQCetTSM19uoMe+sSCC1NrsC22YiDMwhD7EeAd+aCykCHIunwS6lyNMpMKjNjCwFlmRX4EBGQQBQOKY8Yc7bhGYMGahw8-ZgBGoHAWk9yF0MmjPHhpM6qx35po5hsA6CaxoIQKAmiVIoD0ZNFRVhfgADlER0HjBCQxmCbrrggQxG+50jCqI8oyaCJADJQCMvzRkZi44QH1s7TRIdWyJOSWQX471FLTVRH47BEI0G3ggLkCAEhiT4B7HyeILdHhQKNLRX4F82b63KTQieUclGdXEEkxEKTebTxppVa+-i7iOjcTAKQYZwRulQelBEsD-5sRjGxPJaIAG4TjBTPBHwInKzbuxIRXFvoQjqcwU5diUBi1-oNCmNE6IFJwURfGFJa7YxIJURWryibcXxswfm1IpCXOtvTCyALhYsXWmLS5a8bkXkGv6AmUopTQqCWM9Ylz1rrOWe6eEpTPkVKqTU9+SCK4PGKXGcEtJ2BgJmusMUvywXMWokadZ2Y7DqDcr8YBAg6VUD+gsimm9G6F3Wrykg-LQZsR2T8h4It4Qf2Zbk8uf8KWbOrmuMg7Atp1NZe8UZhSAlSHuggaBskMx3DQOa22yY7imrgDa740JfhIxRpSw6NASYkSUZcG4qZLX4KZUxYhwybbgwJvVJiNro6aXrI2TAEapLcRDS46hL5ni-GAPzc0qJ5LUj0U6SMgiDXoqNSEu4c0iKkSMjtD1xxdn-iCIQEg8RzRZtassLQwBfmAr+XxHoPRiEcUFI6LSfFuH-kqtsLIZop2VSkPofgAazQAAMAAkwBjLOr+DCbQYsI17uaD0dQtJV3SoXTIEghBjAcHNBurdoyXV7oPSG7Qx7T3nvWu8NkLskCrslJKTdT7d37oYhGk9Z6oyXrAmIcp5pI3PHgZ8G+Uhn4X2ZcwPRaH77UtpReAh-aLIwmgwuzD2Hn6jqw+POhZk+LUdoYItGgDOyaxiD9KACxeByGOgs5trapDtuAJ2uxSBgCXPJg8QdoaqNItaKcSW3CUCXJcfaSeSBuEqaRWlNGt4QFmDgPGEMvH3j8bbWKYT7Au1iZktJp40LebMHYAZozUAlPfo2LzeM+dnNUHFuwKggtgCwcIPB5ajI5CbSgNteVfQpATIEwAcUGIbC90z4wjE+ewCFHhNEwvY3qTqYTfgSakAuYdCyDW-DY7qTj3GPovBzQuaklzzSwuUwVqAuAPhDt8jpljxxksMBM1IMz7bQ1ov4UoqQzhPNjuMCl6kfpMikDEzu1g-7gPoufZB1dg7JNTeTGm34ls+ITcq553uS2c2Yb7cyg7Q6pAloXeaFAc3WDikFo6MoOMpA0ATNNiNqWPMjN5j9rLk7C2vtMlIMCrAhJmnC9TYM3rfU5xXYRjxXi2EkCcyGbsDHTStlI5e944cV2hNcRmubfsqh8G4WqBVF2RngZDefDV6CpBDZIGGaJI2wIrAEONxkAIgQgkgLABA+mmxYCZ6Zlt5mO1WdEz2qTj3fwOfm4MVoMBomTpC-BxDG0dXRffnF1d3Ppl862yh-xS0bDGlyLNfxF9V2owG-MEBoWQGTn05GsNY2hT6rYqcOAFwfisFJQsnFjn3NGkFPp+Armlu2blzbVDlHfjc95xCFPUm0+Cm53nuAQ79jHj2u2fYmw6B534L8IEEBPFTFtuEMmUgvcQB953mAzESggE5cQCETAjPeO4OAcoWXqj+CYM0JA4oACcvR+ggFoAwJg24nB99mAIIQdR9iin-ImWkrRwaEXNImSWEJWhH4ANyegMK0NwlI4AeCdL4fwgQQiOjvxz8HlQw3rbmhIyno-7vC5A3p3rlgdAgH378An5MTmhlhoAwEc5OYubGaH5WjOxQDmjiinrcTwBXBdhyCCCgFSCRA8Tsbmi-q0hkE0GP7sjmbxB8jqBkEjCIjbC0QeDyaTD8DmjMrX75DxB5BUA-5oxbD1byZ2r-i8ThCRANi4HIG0GwHsDwEQzlhKFoImCDBhoUHfTUGkDKFGj0FsjAjmjMFWBiGV5)
diff --git a/docs/favicon.ico b/docs/favicon.ico
deleted file mode 100644
index 961f6c3a..00000000
Binary files a/docs/favicon.ico and /dev/null differ
diff --git a/docs/favicon.png b/docs/favicon.png
deleted file mode 100644
index 0bb23f41..00000000
Binary files a/docs/favicon.png and /dev/null differ
diff --git a/docs/fragment.md b/docs/fragment.md
deleted file mode 100644
index 86602d17..00000000
--- a/docs/fragment.md
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-# fragment(attrs, children)
-
-- [Description](#description)
-- [Signature](#signature)
-- [How it works](#how-it-works)
-
----
-
-### Description
-
-Allows attaching lifecycle methods to a fragment [vnode](vnodes.md)
-
-```javascript
-var groupVisible = true
-var log = function() {
- console.log("group is now visible")
-}
-
-m("ul", [
- m("li", "child 1"),
- m("li", "child 2"),
- groupVisible ? m.fragment({oninit: log}, [
- // a fragment containing two elements
- m("li", "child 3"),
- m("li", "child 4"),
- ]) : null
-])
-```
-
----
-
-### Signature
-
-Generates a fragment [vnode](vnodes.md)
-
-`vnode = m.fragment(attrs, children)`
-
-Argument | Type | Required | Description
------------ | --------------------------------------------------- | -------- | ---
-`attrs` | `Object` | No | HTML attributes or element properties
-`children` | `Array|String|Number|Boolean` | No | Child [vnodes](vnodes.md#structure). Can be written as [splat arguments](signatures.md#splats)
-**returns** | `Vnode` | | A fragment [vnode](vnodes.md#structure)
-
-[How to read signatures](signatures.md)
-
----
-
-### How it works
-
-`m.fragment()` creates a [fragment vnode](vnodes.md) with attributes. It is meant for advanced use cases involving [keys](keys.md) or [lifecyle methods](lifecycle-methods.md).
-
-A fragment vnode represents a list of DOM elements. If you want a regular element vnode that represents only one DOM element and don't require keyed logic, you should use [`m()`](hyperscript.md) instead.
-
-Normally you can use simple arrays or splats instead to denote a list of nodes:
-
-```javascript
-var groupVisible = true
-
-m("ul",
- m("li", "child 1"),
- m("li", "child 2"),
- groupVisible ? [
- // a fragment containing two elements
- m("li", "child 3"),
- m("li", "child 4"),
- ] : null
-)
-```
-
-However, JavaScript arrays cannot be keyed or hold lifecycle methods. One option would be to create a wrapper element to host the key or lifecycle method, but sometimes it is not desirable to have an extra element (for example in complex table structures). In those cases, a fragment vnode can be used instead.
-
-There are a few benefits that come from using `m.fragment` instead of handwriting a vnode object structure: m.fragment creates [monomorphic objects](vnodes.md#monomorphic-class), which have better performance characteristics than creating objects dynamically. In addition, using `m.fragment` makes your intentions clear to other developers, and it makes it less likely that you'll mistakenly set attributes on the vnode object itself rather than on its `attrs` map.
diff --git a/docs/framework-comparison.md b/docs/framework-comparison.md
deleted file mode 100644
index 1612baa4..00000000
--- a/docs/framework-comparison.md
+++ /dev/null
@@ -1,220 +0,0 @@
-
-
-# Framework comparison
-
-- [Why not X?](#why-not-insert-favorite-framework-here?)
-- [Why use Mithril.js?](#why-use-mithril?)
-- [React](#react)
-- [Angular](#angular)
-- [Vue](#vue)
-
-If you're reading this page, you probably have used other frameworks to build applications, and you want to know if Mithril.js would help you solve your problems more effectively.
-
----
-
-## Why not [insert favorite framework here]?
-
-The reality is that most modern frameworks are fast, well-suited to build complex applications, and maintainable if you know how to use them effectively. There are examples of highly complex applications in the wild using just about every popular framework: Udemy uses Angular, AirBnB uses React, Gitlab uses Vue, Guild Wars 2 uses Mithril.js (yes, inside the game!). Clearly, these are all production-quality frameworks.
-
-As a rule of thumb, if your team is already heavily invested in another framework/library/stack, it makes more sense to stick with it, unless your team agrees that there's a very strong reason to justify a costly rewrite.
-
-However, if you're starting something new, do consider giving Mithril.js a try, if nothing else, to see how much value Mithril.js adopters have been getting out of under 10kb (gzipped) of code. Mithril.js is used by many well-known companies (e.g. Vimeo, Nike, Fitbit), and it powers large open-sourced platforms too (e.g. Lichess, Flarum).
-
----
-
-## Why use Mithril.js?
-
-In one sentence: because **Mithril.js is pragmatic**. This [10 minute guide](index.md) is a good example: that's how long it takes to learn components, XHR and routing - and that's just about the right amount of knowledge needed to build useful applications.
-
-Mithril.js is all about getting meaningful work done efficiently. Doing file uploads? [The docs show you how](request.md#file-uploads). Authentication? [Documented too](route.md#authentication). Exit animations? [You got it](animation.md). No extra libraries, no magic.
-
----
-
-## Comparisons
-
-### React
-
-React is a view library maintained by Facebook.
-
-React and Mithril.js share a lot of similarities. If you already learned React, you already know almost all you need to build apps with Mithril.
-
-- They both use virtual DOM, lifecycle methods and key-based reconciliation
-- They both organize views via components
-- They both use JavaScript as a flow control mechanism within views
-
-The most obvious difference between React and Mithril.js is in their scope. React is a view library, so a typical React-based application relies on third-party libraries for routing, XHR and state management. Using a library oriented approach allows developers to customize their stack to precisely match their needs. The not-so-nice way of saying that is that React-based architectures can vary wildly from project to project, and that those projects are that much more likely to cross the 1MB size line.
-
-Mithril.js has built-in modules for common necessities such as routing and XHR, and the [guide](simple-application.md) demonstrates idiomatic usage. This approach is preferable for teams that value consistency and ease of onboarding.
-
-#### Performance
-
-Both React and Mithril.js care strongly about rendering performance, but go about it in different ways. In the past React had two DOM rendering implementations (one using the DOM API, and one using `innerHTML`). Its upcoming fiber architecture introduces scheduling and prioritization of units of work. React also has a sophisticated build system that disables various checks and error messages for production deployments, and various browser-specific optimizations. In addition, there are also several performance-oriented libraries that leverage React's `shouldComponentUpdate` hook and immutable data structure libraries' fast object equality checking properties to reduce virtual DOM reconciliation times. Generally speaking, React's approach to performance is to engineer relatively complex solutions.
-
-Mithril.js follows the less-is-more school of thought. It has a substantially smaller, aggressively optimized codebase. The rationale is that a small codebase is easier to audit and optimize, and ultimately results in less code being run.
-
-Here's a comparison of library load times, i.e. the time it takes to parse and run the JavaScript code for each framework, by adding a `console.time()` call on the first line and a `console.timeEnd()` call on the last of a script that is composed solely of framework code. For your reading convenience, here are best-of-20 results with logging code manually added to bundled scripts, running from the filesystem, in Chrome on a modest 2010 PC desktop:
-
-React | Mithril.js
-------- | -------
-55.8 ms | 4.5 ms
-
-Library load times matter in applications that don't stay open for long periods of time (for example, anything in mobile) and cannot be improved via caching or other optimization techniques.
-
-Since this is a micro-benchmark, you are encouraged to replicate these tests yourself since hardware can heavily affect the numbers. Note that bundler frameworks like Webpack can move dependencies out before the timer calls to emulate static module resolution, so you should either copy the code from the compiled CDN files or open the output file from the bundler library, and manually add the high resolution timer calls `console.time` and `console.timeEnd` to the bundled script. Avoid using `new Date` and `performance.now`, as those mechanisms are not as statistically accurate.
-
-For your reading convenience, here's a version of that benchmark adapted to use CDNs on the web: the [benchmark for React is here](https://jsfiddle.net/0ovkv64u/), and the [benchmark for Mithril.js is here](https://jsfiddle.net/o7hxooqL/). Note that we're benchmarking all of Mithril.js rather than benchmarking only the rendering module (which would be equivalent in scope to React). Also note that this CDN-driven setup incurs some overheads due to fetching resources from disk cache (~2ms per resource). Due to those reasons, the numbers here are not entirely accurate, but they should be sufficient to observe that Mithril.js' initialization speed is noticeably better than React.
-
-Here's a slightly more meaningful benchmark: measuring the scripting time for creating 10,000 divs (and 10,000 text nodes). Again, here's the benchmark code for [React](https://jsfiddle.net/bfoeay4f/) and [Mithril.js](https://jsfiddle.net/fft0ht7n/). Their best results are shown below:
-
-React | Mithril.js
-------- | -------
-99.7 ms | 42.8 ms
-
-What these numbers show is that not only does Mithril.js initializes significantly faster, it can process upwards of 20,000 virtual DOM nodes before React is ready to use.
-
-##### Update performance
-
-Update performance can be even more important than first-render performance, since updates can happen many times while a Single Page Application is running.
-
-A useful tool to benchmark update performance is a tool developed by the Ember team called DbMonster. It updates a table as fast as it can and measures frames per second (FPS) and JavaScript times (min, max and mean). The FPS count can be difficult to evaluate since it also includes browser repaint times and `setTimeout` clamping delay, so the most meaningful number to look at is the mean render time. You can compare a [React implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/react/index.html) and a [Mithril.js implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/mithril/index.html). Sample results are shown below:
-
-React | Mithril.js
-------- | -------
-12.1 ms | 6.4 ms
-
-##### Development performance
-
-Another thing to keep in mind is that because React adds extra checks and helpful error messages in development mode, it is slower in development than the production version used for the benchmarks above. To illustrate, [here's the 10,000 node benchmark from above using the development version of React](https://jsfiddle.net/r1jfckrd/).
-
-##### Drop-in replacements
-
-There are [several](https://preactjs.com/) [projects](https://github.com/Lucifier129/react-lite) [that](https://infernojs.org/) [claim](https://github.com/alibaba/rax) API parity with React (some via compatibility layer libraries), but they are not fully compatible (e.g. PropType support is usually stubbed out, synthetic events are sometimes not supported, and some APIs have different semantics). Note that these libraries typically also include features of their own that are not part of the official React API, which may become problematic down the road if one decides to switch back to React Fiber.
-
-Claims about small download size (compared to React) are accurate, but most of these libraries are slightly larger than Mithril.js' renderer module. Preact is the only exception.
-
-Be wary of aggressive performance claims, as benchmarks used by some of these projects are known to be out-of-date and flawed (in the sense that they can be - and are - exploited). Boris Kaul (author of some of the benchmarks) has [written in detail about how benchmarks are gamed](https://medium.com/@localvoid/how-to-win-in-web-framework-benchmarks-8bc31af76ce7). Another thing to keep in mind is that some benchmarks aggressively use advanced optimization features and thus demonstrate *potential* performance, i.e. performance that is possible given some caveats, but realistically unlikely unless you actively spend the time to go over your entire codebase identifying optimization candidates and evaluating the regression risks brought by the optimization caveats.
-
-In the spirit of demonstrating *typical* performance characteristics, the benchmarks presented in this comparison page are implemented in an apples-to-apples, naive, idiomatic way (i.e. the way you would normally write 99% of your code) and do not employ tricks or advanced optimizations to make one or other framework look artificially better. You are encouraged to contribute a PR if you feel any DbMonster implementation here could be written more idiomatically.
-
-#### Complexity
-
-Both React and Mithril.js have relatively small API surfaces compared to other frameworks, which help ease learning curve. However, whereas idiomatic Mithril.js can be written without loss of readability using plain ES5 and no other dependencies, idiomatic React relies heavily on complex tooling (e.g. Babel, JSX plugin, etc), and this level of complexity frequently extends to popular parts of its ecosystem, be it in the form of syntax extensions (e.g. non-standard object spread syntax in Redux), architectures (e.g. ones using immutable data libraries), or bells and whistles (e.g. hot module reloading).
-
-While complex toolchains are also possible with Mithril.js and other frameworks alike, it's *strongly* recommended that you follow the [KISS](https://en.wikipedia.org/wiki/KISS_principle) and [YAGNI](https://en.wikipedia.org/wiki/You_aren't_gonna_need_it) principles when using Mithril.
-
-#### Learning curve
-
-Both React and Mithril.js have relatively small learning curves. React's learning curve mostly involves understanding components and their lifecycle. The learning curve for Mithril.js components is nearly identical. There are obviously more APIs to learn in Mithril.js, since Mithril.js also includes routing and XHR, but the learning curve would be fairly similar to learning React, React Router and a XHR library like superagent or axios.
-
-Idiomatic React requires working knowledge of JSX and its caveats, and therefore there's also a small learning curve related to Babel.
-
-#### Documentation
-
-React documentation is clear and well written, and includes a good API reference, tutorials for getting started, as well as pages covering various advanced concepts. Unfortunately, since React is limited to being only a view library, its documentation does not explore how to use React idiomatically in the context of a real-life application. As a result, there are many popular state management libraries and thus architectures using React can differ drastically from company to company (or even between projects).
-
-Mithril.js documentation also includes [introductory](index.md) [tutorials](simple-application.md), pages about advanced concepts, and an extensive API reference section, which includes input/output type information, examples for various common use cases and advice against misuse and anti-patterns. It also includes a cheatsheet for quick reference.
-
-Mithril.js documentation also demonstrates simple, close-to-the-metal solutions to common use cases in real-life applications where it's appropriate to inform a developer that web standards may be now on par with larger established libraries.
-
----
-
-### Angular
-
-Angular is a web application framework maintained by Google.
-
-Angular and Mithril.js are fairly different, but they share a few similarities:
-
-- Both support componentization
-- Both have an array of tools for various aspects of web applications (e.g. routing, XHR)
-
-The most obvious difference between Angular and Mithril.js is in their complexity. This can be seen most easily in how views are implemented. Mithril.js views are plain JavaScript, and flow control is done with JavaScript built-in mechanisms such as ternary operators or `Array.prototype.map`. Angular, on the other hand, implements a directive system to extend HTML views so that it's possible to evaluate JavaScript-like expressions within HTML attributes and interpolations. Angular actually ships with a parser and a compiler written in JavaScript to achieve that. If that doesn't seem complex enough, there's actually two compilation modes (a default mode that generates JavaScript functions dynamically for performance, and [a slower mode](https://docs.angularjs.org/api/ng/directive/ngCsp) for dealing with Content Security Policy restrictions).
-
-#### Performance
-
-Angular has made a lot of progress in terms of performance over the years. Angular 1 used a mechanism known as dirty checking which tended to get slow due to the need to constantly diff large `$scope` structures. Angular 2 uses a template change detection mechanism that is much more performant. However, even despite Angular's improvements, Mithril.js is often faster than Angular, due to the ease of auditing that Mithril.js' small codebase size affords.
-
-It's difficult to make a comparison of load times between Angular and Mithril.js for a couple of reasons. The first is that Angular 1 and 2 are in fact completely different codebases, and both versions are officially supported and maintained (and the vast majority of Angular codebases in the wild currently still use version 1). The second reason is that both Angular and Mithril.js are modular. In both cases, it's possible to remove a significant part of the framework that is not used in a given application.
-
-With that being said, the smallest known Angular 2 bundle is a [29kb hello world](https://www.lucidchart.com/techblog/2016/09/26/improving-angular-2-load-times/) compressed w/ the Brotli algorithm (it's 35kb using standard gzip), and with most of Angular's useful functionality removed. By comparison, a Mithril.js hello world - including the entire Mithril.js core with batteries and everything - would be about 10kb gzipped.
-
-Also, remember that frameworks like Angular and Mithril.js are designed for non-trivial application, so an application that managed to use all of Angular's API surface would need to download several hundred kb of framework code, rather than merely 29kb.
-
-##### Update performance
-
-A useful tool to benchmark update performance is a tool developed by the Ember team called DbMonster. It updates a table as fast as it can and measures frames per second (FPS) and JavaScript times (min, max and mean). The FPS count can be difficult to evaluate since it also includes browser repaint times and `setTimeout` clamping delay, so the most meaningful number to look at is the mean render time. You can compare an [Angular implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/angular/index.html) and a [Mithril.js implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/mithril/index.html). Both implementations are naive (i.e. no optimizations). Sample results are shown below:
-
-Angular | Mithril.js
-------- | -------
-11.5 ms | 6.4 ms
-
-#### Complexity
-
-Angular is superior to Mithril.js in the amount of tools it offers (in the form of various directives and services), but it is also far more complex. Compare [Angular's API surface](https://angular.io/docs/ts/latest/api/) with [Mithril.js'](api.md). You can make your own judgment on which API is more self-descriptive and more relevant to your needs.
-
-Angular 2 has a lot more concepts to understand: on the language level, Typescript is the recommended language, and on top of that there's also Angular-specific template syntax such as bindings, pipes, "safe navigator operator". You also need to learn about architectural concepts such as modules, components, services, directives, etc, and where it's appropriate to use what.
-
-#### Learning curve
-
-If we compare apples to apples, Angular 2 and Mithril.js have similar learning curves: in both, components are a central aspect of architecture, and both have reasonable routing and XHR tools.
-
-With that being said, Angular has a lot more concepts to learn than Mithril. It offers Angular-specific APIs for many things that often can be trivially implemented (e.g. pluralization is essentially a switch statement, "required" validation is simply an equality check, etc). Angular templates also have several layers of abstractions to emulate what JavaScript does natively in Mithril.js - Angular's `ng-if`/`ngIf` is a *directive*, which uses a custom *parser* and *compiler* to evaluate an expression string and emulate lexical scoping... and so on. Mithril.js tends to be a lot more transparent, and therefore easier to reason about.
-
-#### Documentation
-
-Angular 2 documentation provides an extensive introductory tutorial, and another tutorial that implements an application. It also has various guides for advanced concepts, a cheatsheet and a style guide. Unfortunately, at the moment, the API reference leaves much to be desired. Several APIs are either undocumented or provide no context for what the API might be used for.
-
-Mithril.js documentation includes [introductory](index.md) [tutorials](simple-application.md), pages about advanced concepts, and an extensive API reference section, which includes input/output type information, examples for various common use cases and advice against misuse and anti-patterns. It also includes a cheatsheet for quick reference.
-
-Mithril.js documentation also demonstrates simple, close-to-the-metal solutions to common use cases in real-life applications where it's appropriate to inform a developer that web standards may be now on par with larger established libraries.
-
-
----
-
-### Vue
-
-Vue is a view library similar to Angular.
-
-Vue and Mithril.js have a lot of differences but they also share some similarities:
-
-- They both use virtual DOM and lifecycle methods
-- Both organize views via components
-
-Vue 2 uses a fork of Snabbdom as its virtual DOM system. In addition, Vue also provides tools for routing and state management as separate modules. Vue looks very similar to Angular and provides a similar directive system, HTML-based templates and logic flow directives. It differs from Angular in that it implements a monkeypatching reactive system that overwrites native methods in a component's data tree (whereas Angular 1 uses dirty checking and digest/apply cycles to achieve similar results). Similar to Angular 2, Vue compiles HTML templates into functions, but the compiled functions look more like Mithril.js or React views, rather than Angular's compiled rendering functions.
-
-Vue is significantly smaller than Angular when comparing apples to apples, but not as small as Mithril.js (Vue core is around 23kb gzipped, whereas the equivalent rendering module in Mithril.js is around 4kb gzipped). Both have similar performance characteristics, but benchmarks usually suggest Mithril.js is slightly faster.
-
-#### Performance
-
-Here's a comparison of library load times, i.e. the time it takes to parse and run the JavaScript code for each framework, by adding a `console.time()` call on the first line and a `console.timeEnd()` call on the last of a script that is composed solely of framework code. For your reading convenience, here are best-of-20 results with logging code manually added to bundled scripts, running from the filesystem, in Chrome on a modest 2010 PC desktop:
-
-Vue | Mithril.js
-------- | -------
-21.8 ms | 4.5 ms
-
-Library load times matter in applications that don't stay open for long periods of time (for example, anything in mobile) and cannot be improved via caching or other optimization techniques.
-
-##### Update performance
-
-A useful tool to benchmark update performance is a tool developed by the Ember team called DbMonster. It updates a table as fast as it can and measures frames per second (FPS) and JavaScript times (min, max and mean). The FPS count can be difficult to evaluate since it also includes browser repaint times and `setTimeout` clamping delay, so the most meaningful number to look at is the mean render time. You can compare a [Vue implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/vue/index.html) and a [Mithril.js implementation](https://raw.githack.com/MithrilJS/mithril.js/master/examples/dbmonster/mithril/index.html). Both implementations are naive (i.e. no optimizations). Sample results are shown below:
-
-Vue | Mithril.js
------- | -------
-9.8 ms | 6.4 ms
-
-#### Complexity
-
-Vue is heavily inspired by Angular and has many things that Angular does (e.g. directives, filters, bi-directional bindings, `v-cloak`), but also has things inspired by React (e.g. components). As of Vue 2.0, it's also possible to write templates using hyperscript/JSX syntax (in addition to single-file components and the various webpack-based language transpilation plugins). Vue provides both bi-directional data binding and an optional Redux-like state management library, but unlike Angular, it provides no style guide. The many-ways-of-doing-one-thing approach can cause architectural fragmentation in long-lived projects.
-
-Mithril.js has far less concepts and typically organizes applications in terms of components and a data layer. All component creation styles in Mithril.js output the same vnode structure using native JavaScript features only. The direct consequence of leaning on the language is less tooling and a simpler project setup.
-
-#### Documentation
-
-Both Vue and Mithril.js have good documentation. Both include a good API reference with examples, tutorials for getting started, as well as pages covering various advanced concepts.
-
-However, due to Vue's many-ways-to-do-one-thing approach, some things may not be adequately documented. For example, there's no documentation on hyperscript syntax or usage.
-
-Mithril.js documentation typically errs on the side of being overly thorough if a topic involves things outside of the scope of Mithril. For example, when a topic involves a 3rd party library, Mithril.js documentation walks through the installation process for the 3rd party library. Mithril.js documentation also often demonstrates simple, close-to-the-metal solutions to common use cases in real-life applications where it's appropriate to inform a developer that web standards may be now on par with larger established libraries.
-
-Mithril.js' tutorials also cover a lot more ground than Vue's: the [Vue tutorial](https://vuejs.org/v2/guide/#Getting-Started) finishes with a static list of foodstuff. [Mithril.js' 10 minute guide](index.md) covers the majority of its API and goes over key aspects of real-life applications, such as fetching data from a server and routing (and there's a [longer, more thorough tutorial](simple-application.md) if that's not enough).
diff --git a/docs/hyperscript.md b/docs/hyperscript.md
deleted file mode 100644
index 6f4fdfd3..00000000
--- a/docs/hyperscript.md
+++ /dev/null
@@ -1,529 +0,0 @@
-
-
-# m(selector, attributes, children)
-
-- [Description](#description)
-- [Signature](#signature)
-- [How it works](#how-it-works)
-- [Flexibility](#flexibility)
-- [CSS selectors](#css-selectors)
-- [Attributes passed as the second argument](#attributes-passed-as-the-second-argument)
-- [DOM attributes](#dom-attributes)
-- [Style attribute](#style-attribute)
-- [Events](#events)
-- [Properties](#properties)
-- [Components](#components)
-- [Lifecycle methods](#lifecycle-methods)
-- [Keys](#keys)
-- [SVG and MathML](#svg-and-mathml)
-- [Making templates dynamic](#making-templates-dynamic)
-- [Converting HTML](#converting-html)
-- [Avoid anti-patterns](#avoid-anti-patterns)
-
----
-
-### Description
-
-Represents an HTML element in a Mithril.js view
-
-```javascript
-m("div.foo", {style: {color: "red"}}, "hello")
-// renders to this HTML:
-//
hello
-```
-
-You can also use an HTML-like syntax called [JSX](jsx.md), using Babel to convert it to equivalent hyperscript calls. This is equivalent to the above.
-
-```jsx
-
hello
-```
-
----
-
-### Signature
-
-`vnode = m(selector, attrs, children)`
-
-Argument | Type | Required | Description
------------- | ------------------------------------------ | -------- | ---
-`selector` | `String|Object|Function` | Yes | A CSS selector or a [component](components.md)
-`attrs` | `Object` | No | HTML attributes or element properties
-`children` | `Array|String|Number|Boolean` | No | Child [vnodes](vnodes.md#structure). Can be written as [splat arguments](signatures.md#splats)
-**returns** | `Vnode` | | A [vnode](vnodes.md#structure)
-
-[How to read signatures](signatures.md)
-
----
-
-### How it works
-
-Mithril.js provides a hyperscript function `m()`, which allows expressing any HTML structure using JavaScript syntax. It accepts a `selector` string (required), an `attrs` object (optional) and a `children` array (optional).
-
-```javascript
-m("div", {id: "box"}, "hello")
-
-// renders to this HTML:
-//
hello
-```
-
-The `m()` function does not actually return a DOM element. Instead it returns a [virtual DOM node](vnodes.md), or *vnode*, which is a JavaScript object that represents the DOM element to be created.
-
-```javascript
-// a vnode
-var vnode = {tag: "div", attrs: {id: "box"}, children: [ /*...*/ ]}
-```
-
-To transform a vnode into an actual DOM element, use the [`m.render()`](render.md) function:
-
-```javascript
-m.render(document.body, m("br")) // puts a in
-```
-
-Calling `m.render()` multiple times does **not** recreate the DOM tree from scratch each time. Instead, each call will only make a change to a DOM tree if it is absolutely necessary to reflect the virtual DOM tree passed into the call. This behavior is desirable because recreating the DOM from scratch is very expensive, and causes issues such as loss of input focus, among other things. By contrast, updating the DOM only where necessary is comparatively much faster and makes it easier to maintain complex UIs that handle multiple user stories.
-
----
-
-### Flexibility
-
-The `m()` function is both *polymorphic* and *variadic*. In other words, it's very flexible in what it expects as input parameters:
-
-```javascript
-// simple tag
-m("div") //
-
-// attributes and children are optional
-m("a", {id: "b"}) //
-m("span", "hello") // hello
-
-// tag with child nodes
-m("ul", [ //
- m("li", "hello"), //
hello
- m("li", "world"), //
world
-]) //
-
-// array is optional
-m("ul", //
- m("li", "hello"), //
hello
- m("li", "world") //
world
-) //
-```
-
----
-
-### CSS selectors
-
-The first argument of `m()` can be any CSS selector that can describe an HTML element. It accepts any valid CSS combinations of `#` (id), `.` (class) and `[]` (attribute) syntax.
-
-```javascript
-m("div#hello")
-//
-
-m("section.container")
-//
-
-m("input[type=text][placeholder=Name]")
-//
-
-m("a#exit.external[href='https://example.com']", "Leave")
-// Leave
-```
-
-If you omit the tag name, Mithril.js assumes a `div` tag.
-
-```javascript
-m(".box.box-bordered") //
-```
-
-Typically, it's recommended that you use CSS selectors for static attributes (i.e. attributes whose value do not change), and pass an attributes object for dynamic attribute values.
-
-```javascript
-var currentURL = "/"
-
-m("a.link[href=/]", {
- class: currentURL === "/" ? "selected" : ""
-}, "Home")
-
-// renders to this HTML:
-// Home
-```
-
-### Attributes passed as the second argument
-
-You can pass attributes, properties, events and lifecycle hooks in the second, optional argument (see the next sections for details).
-
-```JS
-m("button", {
- class: "my-button",
- onclick: function() {/* ... */},
- oncreate: function() {/* ... */}
-})
-```
-
-If the value of such an attribute is `null` or `undefined`, it is treated as if the attribute was absent.
-
-If there are class names in both first and second arguments of `m()`, they are merged together as you would expect. If the value of the class in the second argument is `null` or `undefined`, it is ignored.
-
-If another attribute is present in both the first and the second argument, the second one takes precedence even if it is is `null` or `undefined`.
-
----
-
-### DOM attributes
-
-Mithril.js uses both the JavaScript API and the DOM API (`setAttribute`) to resolve attributes. This means you can use both syntaxes to refer to attributes.
-
-For example, in the JavaScript API, the `readonly` attribute is called `element.readOnly` (notice the uppercase). In Mithril.js, all of the following are supported:
-
-```javascript
-m("input", {readonly: true}) // lowercase
-m("input", {readOnly: true}) // uppercase
-m("input[readonly]")
-m("input[readOnly]")
-```
-
-This even includes custom elements. For example, you can use [A-Frame](https://aframe.io/docs/0.8.0/introduction/) within Mithril.js, no problem!
-
-```javascript
-m("a-scene", [
- m("a-box", {
- position: "-1 0.5 -3",
- rotation: "0 45 0",
- color: "#4CC3D9",
- }),
-
- m("a-sphere", {
- position: "0 1.25 -5",
- radius: "1.25",
- color: "#EF2D5E",
- }),
-
- m("a-cylinder", {
- position: "1 0.75 -3",
- radius: "0.5",
- height: "1.5",
- color: "#FFC65D",
- }),
-
- m("a-plane", {
- position: "0 0 -4",
- rotation: "-90 0 0",
- width: "4",
- height: "4",
- color: "#7BC8A4",
- }),
-
- m("a-sky", {
- color: "#ECECEC",
- }),
-])
-```
-
-And yes, this translates to both attributes and properties, and it works just like they would in the DOM. Using Brick's `brick-deck` (DEAD LINK, FIXME: http //brick.mozilla.io/docs/brick-deck) as an example, they have a `selected-index` attribute with a corresponding `selectedIndex` getter/setter property.
-
-```javascript
-m("brick-deck[selected-index=0]", [/* ... */]) // lowercase
-m("brick-deck[selectedIndex=0]", [/* ... */]) // uppercase
-// I know these look odd, but `brick-deck`'s `selectedIndex` property is a
-// string, not a number.
-m("brick-deck", {"selected-index": "0"}, [/* ... */])
-m("brick-deck", {"selectedIndex": "0"}, [/* ... */])
-```
-
-For custom elements, it doesn't auto-stringify properties, in case they are objects, numbers, or some other non-string value. So assuming you had some custom element `my-special-element` that has an `elem.whitelist` array getter/setter property, you could do this, and it'd work as you'd expect:
-
-```javascript
-m("my-special-element", {
- whitelist: [
- "https://example.com",
- "https://neverssl.com",
- "https://google.com",
- ],
-})
-```
-
-If you have classes or IDs for those elements, the shorthands still work as you would expect. To pull another A-Frame example:
-
-```javascript
-// These two are equivalent
-m("a-entity#player")
-m("a-entity", {id: "player"})
-```
-
-Do note that all the properties with magic semantics, like lifecycle attributes, `onevent` handlers, `key`s, `class`, and `style`, those are still treated the same way they are for normal HTML elements.
-
----
-
-### Style attribute
-
-Mithril.js supports both strings and objects as valid `style` values. In other words, all of the following are supported:
-
-```javascript
-m("div", {style: "background:red;"})
-m("div", {style: {background: "red"}})
-m("div[style=background:red]")
-```
-
-Using a string as a `style` would overwrite all inline styles in the element if it is redrawn, and not only CSS rules whose values have changed.
-
-You can use both hyphenated CSS property names (like `background-color`) and camel cased DOM `style` property names (like `backgroundColor`). You can also define [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables), if your browser supports them.
-
-Mithril.js does not attempt to add units to number values. It simply stringifies them.
-
----
-
-### Events
-
-Mithril.js supports event handler binding for all DOM events, including events whose specs do not define an `on${event}` property, such as `touchstart`
-
-```javascript
-function doSomething(e) {
- console.log(e)
-}
-
-m("div", {onclick: doSomething})
-```
-
-Mithril.js accepts functions and [EventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventListener) objects. So this will also work:
-
-```javascript
-var clickListener = {
- handleEvent: function(e) {
- console.log(e)
- }
-}
-
-m("div", {onclick: clickListener})
-```
-
-By default, when an event attached with hyperscript fires, this will trigger Mithril.js' auto-redraw after your event callback returns (assuming you are using `m.mount` or `m.route` instead of `m.render` directly). You can disable auto-redraw specifically for a single event by setting `e.redraw = false` on it:
-
-```javascript
-m("div", {
- onclick: function(e) {
- // Prevent auto-redraw
- e.redraw = false
- }
-})
-```
-
----
-
-### Properties
-
-Mithril.js supports DOM functionality that is accessible via properties such as `