-
Notifications
You must be signed in to change notification settings - Fork 597
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add components * example: componentize header * fix choo SSR * example: componentize footer * example: fix footer * update component cache asserts * componentize todos * reorder example dir * fix example tests * fix dep check test * Add garbage collection of unused components * Apply args when calling identity * update to new component preview * update nanocomponent * fix cache err name * remove static methods from example * restore app.emit() function * public API tests * offset component cache iteration by 2 * whitelist contents of component folder (#643) * allow lru number arg * fix lint typo
- Loading branch information
1 parent
357d508
commit bddcfbe
Showing
17 changed files
with
411 additions
and
259 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
var assert = require('assert') | ||
var LRU = require('nanolru') | ||
|
||
module.exports = ChooComponentCache | ||
|
||
function ChooComponentCache (state, emit, lru) { | ||
assert.ok(this instanceof ChooComponentCache, 'ChooComponentCache should be created with `new`') | ||
|
||
assert.equal(typeof state, 'object', 'ChooComponentCache: state should be type object') | ||
assert.equal(typeof emit, 'function', 'ChooComponentCache: emit should be type function') | ||
|
||
if (typeof lru === 'number') this.cache = new LRU(lru) | ||
else this.cache = lru || new LRU(100) | ||
this.state = state | ||
this.emit = emit | ||
} | ||
|
||
// Get & create component instances. | ||
ChooComponentCache.prototype.render = function (Component, id) { | ||
assert.equal(typeof Component, 'function', 'ChooComponentCache.render: Component should be type function') | ||
assert.ok(typeof id === 'string' || typeof id === 'number', 'ChooComponentCache.render: id should be type string or type number') | ||
|
||
var el = this.cache.get(id) | ||
if (!el) { | ||
var args = [] | ||
for (var i = 2, len = arguments.length; i < len; i++) { | ||
args.push(arguments[i]) | ||
} | ||
args.unshift(Component, id, this.state, this.emit) | ||
el = newCall.apply(newCall, args) | ||
this.cache.set(id, el) | ||
} | ||
|
||
return el | ||
} | ||
|
||
// Because you can't call `new` and `.apply()` at the same time. This is a mad | ||
// hack, but hey it works so we gonna go for it. Whoop. | ||
function newCall (Cls) { | ||
return new (Cls.bind.apply(Cls, arguments)) // eslint-disable-line | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('nanocomponent') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
var html = require('bel') | ||
|
||
module.exports = deleteCompleted | ||
|
||
function deleteCompleted (emit) { | ||
return html` | ||
<button class="clear-completed" onclick=${deleteAllCompleted}> | ||
Clear completed | ||
</button> | ||
` | ||
|
||
function deleteAllCompleted () { | ||
emit('todos:deleteCompleted') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
var html = require('bel') | ||
|
||
module.exports = filterButton | ||
|
||
function filterButton (name, filter, currentFilter, emit) { | ||
var filterClass = filter === currentFilter | ||
? 'selected' | ||
: '' | ||
|
||
var uri = '#' + name.toLowerCase() | ||
if (uri === '#all') uri = '/' | ||
|
||
return html`<li> | ||
<a href=${uri} class=${filterClass}> | ||
${name} | ||
</a> | ||
</li>` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
var Component = require('../../../component') | ||
var html = require('bel') | ||
|
||
var clearButton = require('./clear-button') | ||
var filterButton = require('./filter-button') | ||
|
||
module.exports = class Footer extends Component { | ||
constructor (name, state, emit) { | ||
super(name) | ||
this.state = state | ||
this.emit = emit | ||
|
||
this.local = this.state.components.footer = {} | ||
this.setState() | ||
} | ||
|
||
setState () { | ||
this.local.rawTodos = this.state.todos.clock | ||
this.local.rawHref = this.state.href | ||
|
||
this.local.filter = this.state.href.replace(/^\//, '') || '' | ||
this.local.activeCount = this.state.todos.active.length | ||
this.local.hasDone = this.state.todos.done.length || null | ||
} | ||
|
||
update () { | ||
if (this.local.rawTodos !== this.state.todos.clock || | ||
this.local.rawHref !== this.state.href) { | ||
this.setState() | ||
return true | ||
} else { | ||
return false | ||
} | ||
} | ||
|
||
createElement () { | ||
return html`<footer class="footer"> | ||
<span class="todo-count"> | ||
<strong>${this.local.activeCount}</strong> | ||
item${this.state.todos.all === 1 ? '' : 's'} left | ||
</span> | ||
<ul class="filters"> | ||
${filterButton('All', '', this.local.filter, this.emit)} | ||
${filterButton('Active', 'active', this.local.filter, this.emit)} | ||
${filterButton('Completed', 'completed', this.local.filter, this.emit)} | ||
</ul> | ||
${this.local.hasDone && clearButton(this.emit)} | ||
</footer>` | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
var Component = require('../../component') | ||
var html = require('bel') | ||
|
||
module.exports = class Header extends Component { | ||
constructor (name, state, emit) { | ||
super(name) | ||
this.state = state | ||
this.emit = emit | ||
} | ||
|
||
update () { | ||
return false | ||
} | ||
|
||
createElement () { | ||
return html`<header class="header"> | ||
<h1>todos</h1> | ||
<input class="new-todo" | ||
autofocus | ||
placeholder="What needs to be done?" | ||
onkeydown=${this.createTodo.bind(this)} /> | ||
</header>` | ||
} | ||
|
||
createTodo (e) { | ||
var value = e.target.value | ||
if (e.keyCode === 13) { | ||
e.target.value = '' | ||
this.emit('todos:create', value) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
var Component = require('../../component') | ||
var html = require('bel') | ||
|
||
module.exports = class Info extends Component { | ||
update () { | ||
return false | ||
} | ||
|
||
createElement () { | ||
return html`<footer class="info"> | ||
<p>Double-click to edit a todo</p> | ||
<p>choo by <a href="https://yoshuawuyts.com/">Yoshua Wuyts</a></p> | ||
<p>Created by <a href="http://shuheikagawa.com">Shuhei Kagawa</a></p> | ||
</footer>` | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
var Component = require('../../../component') | ||
var html = require('bel') | ||
|
||
var Todo = require('./todo') | ||
|
||
module.exports = class Header extends Component { | ||
constructor (name, state, emit) { | ||
super(name) | ||
this.state = state | ||
this.emit = emit | ||
this.local = this.state.components[name] = {} | ||
this.setState() | ||
} | ||
|
||
setState () { | ||
this.local.rawTodos = this.state.todos.clock | ||
this.local.rawHref = this.state.href | ||
|
||
this.local.allDone = this.state.todos.done.length === this.state.todos.all.length | ||
this.local.filter = this.state.href.replace(/^\//, '') || '' | ||
this.local.todos = this.local.filter === 'completed' | ||
? this.state.todos.done | ||
: this.local.filter === 'active' | ||
? this.state.todos.active | ||
: this.state.todos.all | ||
} | ||
|
||
update () { | ||
if (this.local.rawTodos !== this.state.todos.clock || | ||
this.local.rawHref !== this.state.href) { | ||
this.setState() | ||
return true | ||
} else { | ||
return false | ||
} | ||
} | ||
|
||
createElement () { | ||
return html`<section class="main"> | ||
<input | ||
class="toggle-all" | ||
type="checkbox" | ||
checked=${this.local.allDone} | ||
onchange=${() => this.toggleAll()}/> | ||
<label for="toggle-all" style="display: none;"> | ||
Mark all as done | ||
</label> | ||
<ul class="todo-list"> | ||
${this.local.todos.map(todo => Todo(todo, this.emit))} | ||
</ul> | ||
</section>` | ||
} | ||
|
||
createTodo (e) { | ||
var value = e.target.value | ||
if (e.keyCode === 13) { | ||
e.target.value = '' | ||
this.emit('todos:create', value) | ||
} | ||
} | ||
|
||
toggleAll () { | ||
this.emit('todos:toggleAll') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
var html = require('bel') | ||
|
||
module.exports = Todo | ||
|
||
function Todo (todo, emit) { | ||
var clx = classList({ completed: todo.done, editing: todo.editing }) | ||
return html` | ||
<li id=${todo.id} class=${clx}> | ||
<div class="view"> | ||
<input | ||
type="checkbox" | ||
class="toggle" | ||
checked="${todo.done}" | ||
onchange=${toggle} /> | ||
<label ondblclick=${edit}>${todo.name}</label> | ||
<button | ||
class="destroy" | ||
onclick=${destroy} | ||
></button> | ||
</div> | ||
<input | ||
class="edit" | ||
value=${todo.name} | ||
onkeydown=${handleEditKeydown} | ||
onblur=${update} /> | ||
</li> | ||
` | ||
|
||
function toggle (e) { | ||
emit('todos:toggle', todo.id) | ||
} | ||
|
||
function edit (e) { | ||
emit('todos:edit', todo.id) | ||
} | ||
|
||
function destroy (e) { | ||
emit('todos:delete', todo.id) | ||
} | ||
|
||
function update (e) { | ||
emit('todos:update', { | ||
id: todo.id, | ||
editing: false, | ||
name: e.target.value | ||
}) | ||
} | ||
|
||
function handleEditKeydown (e) { | ||
if (e.keyCode === 13) update(e) // Enter | ||
else if (e.code === 27) emit('todos:unedit') // Escape | ||
} | ||
|
||
function classList (classes) { | ||
var str = '' | ||
var keys = Object.keys(classes) | ||
for (var i = 0, len = keys.length; i < len; i++) { | ||
var key = keys[i] | ||
var val = classes[key] | ||
if (val) str += (key + ' ') | ||
} | ||
return str | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.