pico-dom
v1.0.1
Published
small DOM component system
Downloads
14
Maintainers
Readme
pico-dom
minimalist tool for dynamic DOM tree and component creation, updates, events and lifecycles functions. Supports svg, namespace, keyed lists, and conditional elements, all in 2kb gzip, ES5, no dependencies. Support direct use in browser, CJS and ES modules
• Example • Why • API • License
Example
supports different environments
- CJS:
require('pico-dom').element
- can also be used server-side. See
setDocument
below
- can also be used server-side. See
- ES modules:
import {element} from 'pico-dom'
- browser: (
picoDOM.element
)*
import {D, element as el, list} from '../module'
import {Store} from './Store' // any user store will do
import {ic_remove, ic_add} from './icons'
var store = new Store([]),
i = 0,
j = 0
var table = el('table',
el('caption', {class: 'f4'}, 'table example with...'),
el('tbody',
list(
el('tr',
function() { i = this.key },
el('td', //leading column with icon
function() { this.i = i },
{ events: { click: function() { this.root.store.delRow(this.i) } } },
ic_remove
),
list( // data columns
el('td',
function() { j = this.key },
el('input',
function() {
this.i = i; this.j = j
this.update = function(v) { this.node.value = v }
this.event('change', function() {
this.root.store.set(this.node.value, [this.i, this.j])
})
}
)
)
)
)
),
el('tr',
el('td',
{ events: {click: function() { this.root.store.addRow() } } },
ic_add
)
)
)
).create()
.extra('store', store)
.moveTo(D.body)
store.onchange = function() { table.update( store.get() ) }
store.set([
['icons', 'SVG icons'],
['keyed', 'keyed list'],
['store', 'data flow'],
['event', 'event listeners']
])
Why
To explore ideas for a flexible and concise API with minimal tooling and memory footprint.
Features
- dynamic lists and nested lists (keyed, indexed or select)
- svg and namespace support
- ability to inject a
document API
for server use and/or testing (e.g.jsdom
) - no virtual DOM, all operations are done on actual nodes
- 2kb gzip, no dependencies, all under 600 lines including comments and jsDocs
- all text injections and manipulations done through the secure
textContent
andnodeValue
DOM API - available in CommonJS, ES6 modules and browser versions
- All in ES5 with ES modules, CJS module and iife for browsers. Should work well on mobile and older browsers like IE9.
Limitations
- view and event helpers only
- limited css utility
- strictly DOM element creation and manipulation (no router, no store)
API
Templates
A template is an immutable set of instructions to generate multiple components.
Element templates
element(tagName [, ...options|children|transforms])
elementNS(nsURI, tagName [, ...options|children|transforms])
svg(tagName [, ...options|children|transforms])
Node template
text(textContent [, ...options|transforms])
template(node, [, ...options|transforms])
List template
list(template, [, ...options|transforms])
The 6 template generating functions take the following types of arguments:
options: Object to define future operations
{methodName: arguments}
upon component creation. Examples{class: 'abc'}
to set the component node class attribute once an element component is created{attrs: {id: 'abc'}}
to set component node attributes once an element component is created{events: {click: function() { this.text('CLICKED!') } }}
to set element component event listeners{props: {id: 'abc'}}
to set component node properties{extras: {someKey: someValue}}
to set component properties on the component itself
transforms are just functions called with the component context. Examples
function() { this.class('abc') }
to set the component node class attribute once an element component is createdfunction() { this.attr(id: 'abc') }
to set component node attributes once an element component is createdfunction() { this.event('click', handler) }
to set element component event listeners
children can be templates, nodes or numbers and strings to be converted to text nodes. Same as using the
{append: [...]}
option
Templates have a number of chainable methods that generate new templates (templates are immutable). The methods are the same as the option keys listed above with additional methods that take more than one argument.
- element attributes:
.attr(key, val)
,.attrs({key, val})
- element children:
.append(node, number, string, template)
- element event listeners:
.event(name, callback)
,.events({name, callback})
- node properties:
.prop(key, val)
,.props({key, val})
- component properties:
.extra(key, val)
,.extras({key, val})
- component operations:
.call(funtion() {})
List
List are special components representing a group of multiple nodes.
Resizable lists take a single template that will be used to generate list of varying sizes
list(template)
to create dynamic indexed set of nodes based on the size of the array upon updateslist(template, {getKey: function(v) {return v.id}})
for a keyed list
Select lists have predefined templates that are used to conditionally display subsets on updates
list({a: templateA, b:templateB}, {select: function(v) {return [v.id]}})
created a conditional list template
lists can be stacked and nested.
Components
Components are created from templates: template.create()
.
Normally, only the main component is manually created and all other templates are initiated from within.
In addition to the same methods found in templates (attr(s)
, extra(s)
, call
, append
, class
, event
), Components have the following properties and methods for dealing with DOM Nodes
DOM references
.node
: the associated DOM node or anchor node for lists.root
: the root component that created the component. (null
for the main one created by the user)
DOM functions
.moveTo(parent [,before])
: to move a component.remove()
: to remove a component from the DOM.destroy()
: to remove a component and remove listeners
Update Functions
.text(v)
: to set the node textContent of element Component.update(...)
the function to trigger changes based on external data.updateChildren(..)
to pass update data down the tree.
By default, update is set to text
for text components and updateChildren
for the rest.
Normally, only the main component is updated and the update trickles down the DOM tree according the the rules predefined in the templates.
Other
.key
key for identification and sorting. Set by parent lists on componet children.refs
: used in list to hold node references.getKey(val, key, arr) => string
: to get the unique key for keyed lists.select(val, key) => array
: array of keys for conditional/select lists
Lifecycle operations
Lifecycle hooks are not provided directly but can be acheived by wrapping component methods
- on creation:
template.call(...)
- on insert:
template.call(...)
or wrapcomponent.moveTo(...)
- on remove: wrap
component.remove()
- on destroy: wrap
component.destroy()
var textTemplate = text('ABC', function() {
var item = this,
remove = item.remove
this.remove = function() {
window.requestAnimationFrame(remove.call(item))
}
})
Other helpers
setDocument(document)
to set the Document interface for testing or server use- eg.
setDocument((new JSDOM).window.document)
- eg.
D
reference to the Document interface for testing or server use- eg.
var body = D.body
- eg.
find(from [, test] [, until])
find a component within nodes or components and matching the test function. It parses nodes up and down following the html markup order.- eg.
find(document.body)
to get the first component in the document - eg.
find(tableComponent, function(c) { return c.key === 5 } )
- eg.
css(ruleText)
to insert a rule in the document for cases where an exported template relies on a specific css rule that is not convenient or practical to include in a seperate css file