README
spect
DOM aspects: pieces of logic declared with CSS rules.
spect( [ container=document, ] selector, handler? )
Observe selector
within container
, call handler
when matching elements found.
Handler can return a teardown function, called for unmatched elements.
Returns live collection of elements SelectorCollection.
import spect from 'spect'
const foos = spect('.foo', el => {
console.log('active')
return () => console.log('inactive') // teardown
})
const foo = document.createElement('div')
foo.className = 'foo'
document.body.append(foo)
// ... "active"
foo.remove()
// ... "inactive"
SelectorCollection
Extends Array, implements Set, HTMLCollection methods, and provides Observable, AsyncIterable, Disposable interfaces.
foos[idx] // Array
foos.has(el), foos.add(el), foos.delete(el) // Set
foos.item(idx), foos.namedItem(elementId) // HTMLCollection
foos.subscribe(fn) // Observable
foos.dispose() // destroy selector observer / unsubscribe
Technique
It combines selector parts indexing from selector-observer for simple queries and animation events insertionQuery for complex selectors.
Examples
Hello World
<div class="user">{{ user.name || "Loading..." }}</div>
<script type="module">
import spect from 'spect'
import templize from 'templize'
// initialize template
spect('.user', async el => templize(el, {
user: (await fetch('/user')).json() // value is available when resolved
}))
</script>
Timer
<time class="timer">{{ count }}</time>
<time class="timer">{{ count }}</time>
<script type="module">
import spect from 'spect'
import templize from 'templize'
spect('.timer', timer => {
const params = templize(timer, { count: 0 })
const id = setInterval(() => params.count++, 1000)
return () => clearInterval(id)
})
</script>
Counter
<output id="count">{{ count }}</output>
<button id="inc" onclick="{{ inc }}">+</button>
<button id="dec" onclick="{{ dec }}">-</button>
<script type="module">
import spect from 'spect'
import v from 'value-ref'
import templize from 'templize'
const count = v(0)
spect('#count', el => templize(el, { count }))
// bind events via HTML template
spect('#inc', el => templize(el, { inc: () => count.value++ }))
spect('#dec', el => templize(el, { dec: () => count.value-- }))
</script>
Todo list
<form class="todo-form">
<label for="add-todo">
<span>Add Todo</span>
<input name="text" required>
</label>
<button type="submit">Add</button>
<ul class="todo-list">{{ todos }}<ul>
</form>
<script type="module">
import spect from 'spect'
import v from 'value-ref'
import h from 'hyperf'
import tpl from 'templize'
const todos = v([])
spect('.todo-list', el => tpl(el, {
todos: v.from(todos, item => h`<li>${ item.text }</li>`)
}))
spect('.todo-form', form => form.addEventListener('submit', e => {
e.preventDefault()
if (!form.checkValidity()) return
todos.value = [...todos.value, { text: form.text.value }]
form.reset()
}))
</script>
Form validator
<form id="email-form">
<label for="email">Please enter an email address:</label>
<input id="email" onchange={{ validate }}/>
The address is {{ valid ? "valid" : "invalid" }}
</form>
<script type="module">
import spect from 'spect'
import templize from 'templize'
const isValidEmail = s => /.+@.+\..+/i.test(s)
spect('#email-form', form => {
const params = templize(form, {
valid: false,
validate: () => params.valid = isValidEmail(e.target.value)
})
})
</script>
Prompt
<dialog class="dialog" open={{showPrompt}}>
Proceed?
<menu>
<button onclick={{cancel}}>Cancel</button>
<button onclick={{confirm}}>Confirm</button>
</menu>
</dialog>
<script>
import v from 'value-ref'
import spect from 'spect'
spect('.dialog', el => {
const showPrompt = v(false), proceed = v(false)
templize(el, {
showPrompt, proceed,
cancel() {showPrompt.value = proceed.value = false;},
confirm() {showPrompt.value = false; proceed.value = true;}
})
})
</script>
Best Buddies
- value-ref − value container with observable interface. Indispensible for reactive data.
- templize − DOM buddy - hooks up reactive values to template parts.
- hyperf − builds HTML fragments with reactive fields.
- subscribable-things − collection of observables for different browser APIs.
Refs
fast-on-load, selector-set, insertionQuery, selector-observer, reuse, aspect-oriended-programming, qso, pure-js, element-observer, livequery, selector-listener, mutation-summary, rkusa/selector-observer.
ॐ