Extract html into separate module (#103)

This commit is contained in:
Todd Kennedy
2016-07-02 12:55:41 +02:00
committed by Yoshua Wuyts
parent d0920f153f
commit 8f8df602c5
19 changed files with 61 additions and 52 deletions
+18 -13
View File
@@ -118,6 +118,7 @@ Let's create an input box that changes the content of a textbox in real time.
First we import `choo` and create a new instance: First we import `choo` and create a new instance:
```js ```js
const choo = require('choo') const choo = require('choo')
const html = require('choo/html')
const app = choo() const app = choo()
``` ```
@@ -136,7 +137,7 @@ Then we create a new view. It has an `h1` tag which displays the current title,
and an `<input>` field which sends the current value of the text box on every and an `<input>` field which sends the current value of the text box on every
input: input:
```js ```js
const mainView = (params, state, send) => choo.view` const mainView = (params, state, send) => html`
<main> <main>
<h1>${state.title}</h1> <h1>${state.title}</h1>
<input <input
@@ -166,6 +167,7 @@ document.body.appendChild(tree)
And all together now: And all together now:
```js ```js
const choo = require('choo') const choo = require('choo')
const html = require('choo/html')
const app = choo() const app = choo()
app.model({ app.model({
@@ -175,7 +177,7 @@ app.model({
} }
}) })
const mainView = (params, state, send) => choo.view` const mainView = (params, state, send) => html`
<main> <main>
<h1>${state.title}</h1> <h1>${state.title}</h1>
<input <input
@@ -338,7 +340,7 @@ Views are also passed the `send` function, which they can use to dispatch action
```javascript ```javascript
const view = (params, state, send) => { const view = (params, state, send) => {
return choo.view` return html`
<div> <div>
<h1>Total todos: ${state.todos.length}</h1> <h1>Total todos: ${state.todos.length}</h1>
<button onclick=${(e) => send('add', { payload: {title: 'demo'})}>Add</button> <button onclick=${(e) => send('add', { payload: {title: 'demo'})}>Add</button>
@@ -478,10 +480,11 @@ links they comprise most of what can be done on web pages.
```js ```js
const choo = require('choo') const choo = require('choo')
const http = require('choo/http') const http = require('choo/http')
const html = require('choo/html')
const app = choo() const app = choo()
function view (params, state, send) { function view (params, state, send) {
return choo.view` return html`
<form onsubmit=${onSubmit}> <form onsubmit=${onSubmit}>
<fieldset> <fieldset>
<label>username</label> <label>username</label>
@@ -521,7 +524,7 @@ app.start()
If you want a form element to be selected when it's loaded, add the If you want a form element to be selected when it's loaded, add the
[`autofocus`][html-input] property. [`autofocus`][html-input] property.
```js ```js
const view = choo.view` const view = html`
<form> <form>
<input type="text" autofocus> <input type="text" autofocus>
</form> </form>
@@ -535,7 +538,7 @@ is clicked, the click event is caught, and the value of `href` is passed into
the router causing a state change. If you want to disable this behavior, set the router causing a state change. If you want to disable this behavior, set
`app.start({ href: false })`. `app.start({ href: false })`.
```js ```js
const nav = choo.view` const nav = html`
<a href="/">home</a> <a href="/">home</a>
<a href="/first-link">first link</a> <a href="/first-link">first link</a>
<a href="/second-link">second link</a> <a href="/second-link">second link</a>
@@ -574,10 +577,11 @@ In order to make our `choo` app call `app.start()` in the browser and be
`require()`-able in Node, we check if [`module.parent`][module-parent] exists: `require()`-able in Node, we check if [`module.parent`][module-parent] exists:
```js ```js
const choo = require('choo') const choo = require('choo')
const html = require('choo/html')
const app = choo() const app = choo()
app.router((route) => [ app.router((route) => [
route('/', (params, state, send) => choo.view` route('/', (params, state, send) => html`
<h1>${state.message}</h1> <h1>${state.message}</h1>
`) `)
]) ])
@@ -603,10 +607,11 @@ dehydrated DOM nodes to make them dynamic, rather than a new DOM tree and
attaching it to the DOM. attaching it to the DOM.
```js ```js
const choo = require('choo') const choo = require('choo')
const html = require('choo/html')
const app = choo() const app = choo()
app.router((route) => [ app.router((route) => [
route('/', (params, state, send) => choo.view` route('/', (params, state, send) => html`
<h1 id="app-root">${state.message}</h1> <h1 id="app-root">${state.message}</h1>
`) `)
]) ])
@@ -642,11 +647,6 @@ arguments:
a signature of `(action, state, send)` where `send` is a reference to a signature of `(action, state, send)` where `send` is a reference to
`app.send()` `app.send()`
### choo.view\`html\`
Tagged template string HTML builder. See
[`yo-yo`](https://github.com/maxogden/yo-yo) for full documentation. Views
should be passed to `app.router()`
### app.router(params, state, send) ### app.router(params, state, send)
Creates a new router. See Creates a new router. See
[`sheet-router`](https://github.com/yoshuawuyts/sheet-router) for full [`sheet-router`](https://github.com/yoshuawuyts/sheet-router) for full
@@ -677,6 +677,11 @@ following values:
changes (eg `localhost/#posts/123`). Enabling this option automatically changes (eg `localhost/#posts/123`). Enabling this option automatically
disables `opts.history` and `opts.href`. disables `opts.history` and `opts.href`.
### choo/html\`html\`
Tagged template string HTML builder. See
[`yo-yo`](https://github.com/maxogden/yo-yo) for full documentation. Views
should be passed to `app.router()`
## Errors ## Errors
### Could not find DOM node (#id) to update ### Could not find DOM node (#id) to update
This means that a re-render of the DOM was triggered before the first render This means that a re-render of the DOM was triggered before the first render
+2 -2
View File
@@ -1,9 +1,9 @@
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const error = state.app.error[0] const error = state.app.error[0]
const title = state.api.title const title = state.api.title
return choo.view` return html`
<section> <section>
<h1>${title}</h1> <h1>${title}</h1>
<h2>Latest error: ${error}</h2> <h2>Latest error: ${error}</h2>
+3 -3
View File
@@ -1,10 +1,10 @@
const dateformat = require('dateformat') const dateformat = require('dateformat')
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const mailbox = params.mailbox const mailbox = params.mailbox
const messages = state[mailbox].messages const messages = state[mailbox].messages
return choo.view` return html`
<div> <div>
<div class="db cf w-100"> <div class="db cf w-100">
<div class="fl mb3 w-25 mt0 b">Date</th> <div class="fl mb3 w-25 mt0 b">Date</th>
@@ -20,7 +20,7 @@ module.exports = function (params, state, send) {
} }
function createMessage (message, mailbox) { function createMessage (message, mailbox) {
return choo.view` return html`
<div class="db cf w-100"> <div class="db cf w-100">
<a href="${'/' + mailbox + '/' + message.id}"> <a href="${'/' + mailbox + '/' + message.id}">
<div class="fl mb3 w-25 f6 link"> <div class="fl mb3 w-25 f6 link">
+3 -3
View File
@@ -1,4 +1,4 @@
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const mailbox = params.mailbox const mailbox = params.mailbox
@@ -8,7 +8,7 @@ module.exports = function (params, state, send) {
return String(msg.id) === message return String(msg.id) === message
})[0] })[0]
return choo.view` return html`
<div> <div>
${email ? createEmail(email) : 'error: no email found'} ${email ? createEmail(email) : 'error: no email found'}
</div </div
@@ -16,7 +16,7 @@ module.exports = function (params, state, send) {
} }
function createEmail (message) { function createEmail (message) {
return choo.view` return html`
<div class="mail"> <div class="mail">
<dl> <dl>
<dt>From</dt> <dt>From</dt>
+2 -2
View File
@@ -1,7 +1,7 @@
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
return choo.view` return html`
<section> <section>
<p>Select a mailbox</p> <p>Select a mailbox</p>
</section> </section>
+6 -6
View File
@@ -1,5 +1,5 @@
const dateformat = require('dateformat') const dateformat = require('dateformat')
const choo = require('../../../') const html = require('../../../html')
module.exports = function () { module.exports = function () {
return function (params, state, send) { return function (params, state, send) {
@@ -12,7 +12,7 @@ module.exports = function () {
return String(msg.id) === message return String(msg.id) === message
})[0] })[0]
return choo.view` return html`
<section class="fl mt4 w-80 db"> <section class="fl mt4 w-80 db">
<div> <div>
${createHeader()} ${createHeader()}
@@ -26,7 +26,7 @@ module.exports = function () {
</section> </section>
` `
} else { } else {
return choo.view` return html`
<section class="fl mt4 w-80 db"> <section class="fl mt4 w-80 db">
${createHeader()} ${createHeader()}
${messages.map(function (msg) { ${messages.map(function (msg) {
@@ -39,7 +39,7 @@ module.exports = function () {
} }
function createHeader () { function createHeader () {
return choo.view` return html`
<div class="db cf w-100"> <div class="db cf w-100">
<div class="fl mb3 w-25 mt0 b">Date</th> <div class="fl mb3 w-25 mt0 b">Date</th>
<div class="fl mb3 w-25 mt0 b">Subject</th> <div class="fl mb3 w-25 mt0 b">Subject</th>
@@ -50,7 +50,7 @@ function createHeader () {
} }
function createMessage (message, mailbox) { function createMessage (message, mailbox) {
return choo.view` return html`
<div class="db cf w-100"> <div class="db cf w-100">
<a href="${'/' + mailbox + '/' + message.id}"> <a href="${'/' + mailbox + '/' + message.id}">
<div class="fl mb3 w-25 f6 link"> <div class="fl mb3 w-25 f6 link">
@@ -65,7 +65,7 @@ function createMessage (message, mailbox) {
} }
function createEmail (message) { function createEmail (message) {
return choo.view` return html`
<div class="mail"> <div class="mail">
<dl> <dl>
<dt>From</dt> <dt>From</dt>
+3 -3
View File
@@ -1,9 +1,9 @@
const choo = require('../../../') const html = require('../../../html')
const mailboxes = [ 'inbox', 'spam', 'sent' ] const mailboxes = [ 'inbox', 'spam', 'sent' ]
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
return choo.view` return html`
<aside class="fl mt4 w-20 db"> <aside class="fl mt4 w-20 db">
<ul> <ul>
<li> <li>
@@ -19,7 +19,7 @@ module.exports = function (params, state, send) {
} }
function createLi (mailbox, messages) { function createLi (mailbox, messages) {
return choo.view` return html`
<li class="mt4 f6"> <li class="mt4 f6">
<a href="/${mailbox}"> <a href="/${mailbox}">
${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)} ${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}
+2 -2
View File
@@ -1,9 +1,9 @@
const pathname = require('pathname-match') const pathname = require('pathname-match')
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const location = state.app.location const location = state.app.location
return choo.view` return html`
<span class="fl mt4 w-100 f4 b"> <span class="fl mt4 w-100 f4 b">
URL: ${pathname(location) || '/'} URL: ${pathname(location) || '/'}
</span> </span>
+2 -2
View File
@@ -1,4 +1,4 @@
const choo = require('../../../') const html = require('../../../html')
const emailList = require('../elements/email-list') const emailList = require('../elements/email-list')
const pathname = require('../elements/pathname') const pathname = require('../elements/pathname')
@@ -6,7 +6,7 @@ const email = require('../elements/email')
const nav = require('../elements/nav') const nav = require('../elements/nav')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
return choo.view` return html`
<main class="mw5 mw7-ns center cf"> <main class="mw5 mw7-ns center cf">
${pathname(params, state, send)} ${pathname(params, state, send)}
${nav(params, state, send)} ${nav(params, state, send)}
+2 -2
View File
@@ -1,11 +1,11 @@
const choo = require('../../../') const html = require('../../../html')
const empty = require('../elements/empty-mailbox') const empty = require('../elements/empty-mailbox')
const pathname = require('../elements/pathname') const pathname = require('../elements/pathname')
const nav = require('../elements/nav') const nav = require('../elements/nav')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
return choo.view` return html`
<main class="mw5 mw7-ns center cf"> <main class="mw5 mw7-ns center cf">
${pathname(params, state, send)} ${pathname(params, state, send)}
${nav(params, state, send)} ${nav(params, state, send)}
+2 -2
View File
@@ -1,11 +1,11 @@
const choo = require('../../../') const html = require('../../../html')
const emailList = require('../elements/email-list') const emailList = require('../elements/email-list')
const pathname = require('../elements/pathname') const pathname = require('../elements/pathname')
const nav = require('../elements/nav') const nav = require('../elements/nav')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
return choo.view` return html`
<main class="mw5 mw7-ns center cf"> <main class="mw5 mw7-ns center cf">
${pathname(params, state, send)} ${pathname(params, state, send)}
${nav(params, state, send)} ${nav(params, state, send)}
+2 -2
View File
@@ -1,5 +1,5 @@
const assert = require('assert') const assert = require('assert')
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const serverMessage = state.message.server const serverMessage = state.message.server
@@ -8,7 +8,7 @@ module.exports = function (params, state, send) {
assert.equal(typeof serverMessage, 'string', 'server should be a string') assert.equal(typeof serverMessage, 'string', 'server should be a string')
assert.equal(typeof clientMessage, 'string', 'client should be a string') assert.equal(typeof clientMessage, 'string', 'client should be a string')
return choo.view` return html`
<section id="app-root"> <section id="app-root">
<h1>server message: ${serverMessage}</h1> <h1>server message: ${serverMessage}</h1>
<h1>client message: ${clientMessage}</h1> <h1>client message: ${clientMessage}</h1>
+2 -1
View File
@@ -1,4 +1,5 @@
const choo = require('../../') const choo = require('../../')
const html = require('../../html')
const app = choo() const app = choo()
app.model(createModel()) app.model(createModel())
@@ -10,7 +11,7 @@ const tree = app.start()
document.body.appendChild(tree) document.body.appendChild(tree)
function mainView (params, state, send) { function mainView (params, state, send) {
return choo.view` return html`
<div>${state.logger.msg}</div> <div>${state.logger.msg}</div>
` `
} }
+2 -2
View File
@@ -1,9 +1,9 @@
const choo = require('../../../') const html = require('../../../html')
module.exports = function (params, state, send) { module.exports = function (params, state, send) {
const error = state.app.error[0] const error = state.app.error[0]
const title = state.api.title const title = state.api.title
return choo.view` return html`
<section> <section>
<h1>${title}</h1> <h1>${title}</h1>
<h2>Latest error: ${error}</h2> <h2>Latest error: ${error}</h2>
+2 -1
View File
@@ -1,4 +1,5 @@
const choo = require('../../') const choo = require('../../')
const html = require('../../html')
const app = choo() const app = choo()
app.model({ app.model({
@@ -15,7 +16,7 @@ app.model({
}) })
const mainView = (params, state, send) => { const mainView = (params, state, send) => {
return choo.view` return html`
<main class="app"> <main class="app">
<h1>${state.input.title}</h1> <h1>${state.input.title}</h1>
<label>Set the title</label> <label>Set the title</label>
+1
View File
@@ -0,0 +1 @@
module.exports = require('yo-yo')
-1
View File
@@ -10,7 +10,6 @@ const assert = require('assert')
const xtend = require('xtend') const xtend = require('xtend')
const yo = require('yo-yo') const yo = require('yo-yo')
choo.view = yo
module.exports = choo module.exports = choo
// framework for creating sturdy web applications // framework for creating sturdy web applications
+2 -1
View File
@@ -1,5 +1,6 @@
const tape = require('tape') const tape = require('tape')
const choo = require('../../') const choo = require('../../')
const view = require('../../html')
tape('should render on the client', function (t) { tape('should render on the client', function (t) {
t.test('state should not be mutable', function (t) { t.test('state should not be mutable', function (t) {
@@ -50,7 +51,7 @@ tape('should render on the client', function (t) {
++loop ++loop
asserts[loop] && asserts[loop](state.test) asserts[loop] && asserts[loop](state.test)
setTimeout(() => triggers[loop] && triggers[loop](send), 5) setTimeout(() => triggers[loop] && triggers[loop](send), 5)
return choo.view`<div><span class="test">${state.foo}:${state.beep}</span></div>` return view`<div><span class="test">${state.foo}:${state.beep}</span></div>`
}) })
]) ])
+5 -4
View File
@@ -1,5 +1,6 @@
const tape = require('tape') const tape = require('tape')
const choo = require('../../') const choo = require('../../')
const view = require('../../html')
tape('should render on the server', function (t) { tape('should render on the server', function (t) {
t.test('should render a static response', function (t) { t.test('should render a static response', function (t) {
@@ -7,7 +8,7 @@ tape('should render on the server', function (t) {
const app = choo() const app = choo()
app.router((route) => [ app.router((route) => [
route('/', () => choo.view`<h1>Hello Tokyo!</h1>`) route('/', () => view`<h1>Hello Tokyo!</h1>`)
]) ])
const html = app.toString('/') const html = app.toString('/')
@@ -21,7 +22,7 @@ tape('should render on the server', function (t) {
const app = choo() const app = choo()
app.router((route) => [ app.router((route) => [
route('/', function (params, state) { route('/', function (params, state) {
return choo.view`<h1>meow meow ${state.message}</h1>` return view`<h1>meow meow ${state.message}</h1>`
}) })
]) ])
@@ -37,7 +38,7 @@ tape('should render on the server', function (t) {
app.model({ state: { bin: 'baz', beep: 'boop' } }) app.model({ state: { bin: 'baz', beep: 'boop' } })
app.router((route) => [ app.router((route) => [
route('/', function (params, state) { route('/', function (params, state) {
return choo.view`<h1>${state.foo} ${state.bin} ${state.beep}</h1>` return view`<h1>${state.foo} ${state.bin} ${state.beep}</h1>`
}) })
]) ])
@@ -57,7 +58,7 @@ tape('should render on the server', function (t) {
}) })
app.router((route) => [ app.router((route) => [
route('/', function (params, state) { route('/', function (params, state) {
return choo.view` return view`
<h1>${state.hello.foo} ${state.hello.bin} ${state.hello.beep}</h1> <h1>${state.hello.foo} ${state.hello.bin} ${state.hello.beep}</h1>
` `
}) })