Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

attodom

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

attodom - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

co.js

11

CHANGELOG.md

@@ -8,7 +8,10 @@ # Change Log

~~Removed, Changed, Deprecated, Added, Fixed, Security~~
--wrap in seperate function, async only, normal callback
--esm to cjs
--remove parent getter. use find
--setDocument
## [0.5.0] - 2018-01-21
### Removed
- `.find`, `.text`
### Changed
- reverted to an hyperscript style API
## [0.4.0] - 2017-06-04

@@ -15,0 +18,0 @@ ### Removed

@@ -1,2 +0,2 @@

var common = require('./config')
var root = require('./root')

@@ -23,3 +23,3 @@ var media = /^$|^all$/ //mediaTypes: all, print, screen, speach

function getSheet() {
var sheets = common.document.styleSheets
var sheets = root.document.styleSheets
// get existing sheet

@@ -30,3 +30,3 @@ for (var i=0; i<sheets.length; ++i) {

// or create a new one
return common.document.head.appendChild(common.document.createElement('style')).sheet
return root.document.head.appendChild(root.document.createElement('style')).sheet
}

@@ -1,11 +0,34 @@

var common = require('./config')
var CElement = require('./src/_c-element')
var root = require('./root'),
mount = require('./mount')
var htmlProps = {
id: true,
nodeValue: true,
textContent: true,
className: true,
innerHTML: true,
tabIndex: true,
value: true
}
/**
* @function element
* @param {!string} tagName tagName
* @return {!Object} Component
* @param {string} tagName
* @return {Element}
*/
module.exports = function element(tagName) {
return new CElement(common.document.createElement(tagName))
module.exports = function(tagName) {
var node = root.document.createElement(tagName)
for (var i=1; i<arguments.length; ++i) {
var arg = arguments[i]
if (arg != null) {
if (arg.constructor && arg.constructor !== Object) mount(node, arg)
else for (var j=0, ks=Object.keys(arg); j<ks.length; ++j) {
var key = ks[j],
val = arg[key]
if (key === 'style') node.style.cssText = val
else if (typeof val !== 'string' || htmlProps[key]) node[key] = val
else node.setAttribute(key, val)
}
}
}
return node
}
// @ts-check
/* eslint-disable global-require */
module.exports = {
component: require('./component'),
text: require('./text'),
co: require('./co'),
el: require('./el'),
svg: require('./svg'),
el: require('./el'),
elNS: require('./elNS'),
list: require('./list'),
select: require('./list'),
find: require('./find'),
mount: require('./mount'),
css: require('./css')
}

@@ -1,15 +0,8 @@

var common = require('./config'),
placeItem = require('./src/place-item'),
thisAssign = require('./src/this-assign'),
move = require('./src/list-move'),
remove = require('./src/list-remove')
/**
* @function
* @param {!Function} factory
* @param {Function} [getKey]
* @return {!Object} Component
* @return {List}
*/
module.exports = function list(factory, getKey) {
return new CKeyed(factory, getKey)
module.exports = function(factory, getKey) {
return new List(factory, getKey)
}

@@ -22,48 +15,13 @@

*/
function CKeyed(factory, getKey) {
this.refs = Object.create(null)
function List(factory, getKey) {
this.kids = Object.create(null) //TODO
this.factory = factory
this.getKey = getKey || getIndex
this.node = common.document.createComment('^')
this.foot = common.document.createComment('$')
this.node[common.key] = this
this.foot[common.key] = this
if (getKey) this.getKey = getKey
}
CKeyed.prototype = {
c: thisAssign,
remove: remove,
moveTo: move,
update: updateKeyedChildren,
updateChildren: updateKeyedChildren
}
List.prototype.head =
List.prototype.foot = null
function updateKeyedChildren(arr) {
var foot = this.foot,
parent = foot.parentNode,
spot = this.node.nextSibling,
items = this.refs,
refs = Object.create(null)
if (!parent) throw Error('list update requires a parent node')
for (var i = 0; i < arr.length; ++i) {
var key = this.getKey(arr[i], i, arr),
item = refs[key] = items[key] || this.factory(key, arr[i], i, arr)
// place before update since lists require a parent before update
spot = placeItem(parent, item, spot, foot).nextSibling
if (item.update) item.update(arr[i], i, arr)
}
this.refs = refs
while (spot !== this.foot) {
item = spot[common.key]
spot = (item.foot || item.node).nextSibling
item.remove()
}
return this
}
function getIndex(v,i) {
List.prototype.getKey = function(v,i) {
return i // default: indexed
}
{
"name": "attodom",
"version": "0.4.0",
"main": "./dist/index.js",
"module": "./module.js",
"browser": "./dist/browser.js",
"version": "0.5.0",
"main": "./index.js",
"description": "yet another small DOM component library",

@@ -8,0 +6,0 @@ "keywords": [

# attodom
*yet another small DOM component library, <2kb*
*yet another experimental small DOM component library, <2kb*
• [Example](#example) • [Why](#why) • [API](#api) • [License](#license)
• [Why](#why) • [API](#api) • [License](#license)
## Examples
```javascript
var {el, list} = require('attodom'),
Store = require('./Store'), // any user store will do
{ic_remove, ic_add} = require('./icons') //any pre-defined component
var store = new Store([])
var table = el('table').append(
el('caption').a('class', 'f4').text('table example with...'),
el('tbody').append(
list(function(rowKey) {
return el('tr').append(
el('td') //leading column with icon
.on('click', function() {store.delRow(rowKey) })
.child(ic_remove.cloneNode(true)),
list(function(colKey) {
return el('td') // data columns
.child(
el('input')
.set('update', function(v) { this.node.value = v })
.on('change', function() {store.set(this.node.value, [rowKey, colKey]) } )
)
})
)
}),
el('tr').append(
el('td')
.on('click', function() { store.addRow() } )
.child(ic_add)
)
)
)
.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

@@ -63,3 +17,3 @@

* dynamic lists and nested lists (keyed, indexed or select)
* multiple dynamic lists within the same parent
* svg and namespace support

@@ -81,73 +35,25 @@ * ability to inject a `document API` for server use and/or testing (e.g. `jsdom`)

### Components
### Elements (hyperscript)
Components can be created with the functions el, elNS, svg, text, list, select and component
* `el(tagName [, attributes [,children]] ): HTMLElement`
* `svg(tagName [, attributes [,children]] ): SVGElement`
creating Element component
* `el(tagName): Component`
* `elNS(nsURI, tagName): Component`
* `svg(tagName): Component`
* `component(element): Component`
creating Node components (e.g. TextNode)
* `text(textContent): Component`
* `component(node): Component`
### Components
List (component with multiple or no nodes)
* `list(factory): Component`
* `select(components): Component`
* `co(Element, config, children): Component`
* `.node` the component's associated element
* `.update(value)` the function to trigger changes based on external data
* `.updateChildren(array)` to update all child components
Components have a number of chainable methods:
* component properties: `.c(key, val)`
* node properties: `.p(key, val)`
* element attributes: `.a(key, val)`
* element child: `.append(node | number | string | Array | null, ...)`
* element event listeners: `.on(name, callback)` to add, `on(name, falsy)` to remove
By default, update is set to `updateChildren` for `ParentNodes`, `setValue` form `HTMLInputElement` and `setText` for others.
To change the update function, specify it in the config object `{update: myUpdateFunction}`
### List and Select components
### Lists
`List` and `Select` are special components representing a group of multiple nodes.
* `list(componentFactory, getKey)`
List must be added as children to a component to be activated
`List` take a single factory that will be used to generate list of varying sizes and an optional argument to derive a unique key from individual records
* `list(factory)` to create dynamic indexed set of nodes based on the size of the array upon updates
* `list(factory, function(v) {return v.id}})` for a keyed list
* factory: `(key, val, index, array) => component`
Select lists have predefined components that are used to conditionally display subsets on updates. The optional select function returns the selected keys to show on each updates
* `list({a: componentA, b: componentB}, function(v) {return v ? [a] : [b]})`
lists can be stacked and nested with other components or lists.
#### DOM component properties and methods
* `component.node`: the associated DOM node or comment node anchor node for lists
* `.moveTo(parent [,before])`: to move a component
* `.remove()`: to remove a component from the DOM
#### Component update functions
* `.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 other components.
#### Lifecycle events and method wrappers
For additional lifecycle behaviours, component methods can be wrapped (`moveTo`, `remove`). If the arity (number of arguments) of the custom action is greater than the that of the component method, the method will be passed as an argument for async behaviours
* `co.wrap('moveTo', function() { console.log('about to move') })`
* `co.wrap('remove', function(cb) { setTimeout(cb) })`
Wrapper actions are launched before the native method.
### Other helpers
* `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 } )`
* `css(ruleText)` to insert a rule in the document for cases where an exported factory relies on a specific css rule that is not convenient or practical to include in a seperate css file
### Server use

@@ -158,15 +64,8 @@

```javascript
const config = require('attodom/config')
config.document = myDocumentObject
const root = require('attodom/root')
root.document = myDocumentObject
```
### Gotcha
* Components may include items that that are not clonable like event listeners and custom properties. As such, they can only be used once. Modules should either export plain nodes (`eg svgElements icons`) or component factory functions.
* `List` and `Select` can't be updated unless they have a parentNode or parent fragment to hold them together.
* e.g. `list(childFactory).moveTo(D.createDocumentFragment()).update()`
## License
[MIT](http://www.opensource.org/licenses/MIT) © [Hugo Villeneuve](https://github.com/hville)

@@ -1,12 +0,25 @@

var common = require('./config')
var CElement = require('./src/_c-element')
var root = require('./root'),
mount = require('./mount')
var svgURI = 'http://www.w3.org/2000/svg'
/**
* @function svg
* @param {!string} tag tagName
* @return {!Object} Component
* @param {string} tagName
* @return {Element}
*/
module.exports = function svg(tag) {
return new CElement(common.document.createElementNS(svgURI, tag))
module.exports = function(tagName) {
var node = root.document.createElementNS(svgURI, tagName)
for (var i=1; i<arguments.length; ++i) {
var arg = arguments[i]
if (arg != null) {
if (arg.constructor && arg.constructor !== Object) mount(node, arg)
else for (var j=0, ks=Object.keys(arg); j<ks.length; ++j) {
var key = ks[j],
val = arg[key]
if (typeof val !== 'string') node[key] = val
else node.setAttribute(key, val)
}
}
}
return node
}
var ct = require('cotest'),
css = require('../css'),
common = require('../config'),
root = require('../root'),
JSDOM = require('jsdom').JSDOM
common.document = (new JSDOM).window.document
root.document = (new JSDOM).window.document
ct('css - add rule', function() {
var sheets = common.document.styleSheets,
var sheets = root.document.styleSheets,
sheet = null,

@@ -11,0 +11,0 @@ match = /myClass/,

var ct = require('cotest'),
el = require('../el'),
list = require('../list'),
select = require('../select'),
text = require('../text'),
common = require('../config'),
co = require('../co'),
ls = require('../list'),
root = require('../root'),
JSDOM = require('jsdom').JSDOM
var window = (new JSDOM).window
common.document = window.document
root.document = window.document

@@ -19,131 +18,69 @@ function toString(nodes) {

ct('list static', function() {
var childFactory = function() { return el('p').append(text('x')) },
co = el('div').append(list(childFactory)),
elem = co.node
function setText(t) { this.node.textContent = t }
function childFactory() {
return co(el('p', 'x'), {update: setText})
}
var comp = co(el('div'), '^', ls(childFactory), '$'),
elem = comp.node
ct('===', toString(elem.childNodes), '^$')
co.update([1,2,3])
comp.update([1,2,3])
ct('===', toString(elem.childNodes), '^123$')
co.update([4,3,1,2])
comp.update([4,3,1,2])
ct('===', toString(elem.childNodes), '^4312$')
co.update([])
comp.update([])
ct('===', toString(elem.childNodes), '^$')
co.update([1,5,3])
comp.update([1,5,3])
ct('===', toString(elem.childNodes), '^153$')
})
ct('list stacked', function() {
var tFactory = function () { return text('') },
co = el('div').append(
list(tFactory),
list(tFactory),
list(tFactory)
)
var elem = co.node
ct('===', toString(elem.childNodes), '^$^$^$')
co.update([1,2,3])
ct('===', toString(elem.childNodes), '^123$^123$^123$')
ct('list keyed', function() {
var comp = co(el('h0'), ls(
function() {
return co(el('p'), 'x', {update: function(v) { this.node.textContent = v.v; this.update = null }})
},
v => v.k
))
var elem = comp.node
co.update([4,3,1,2])
ct('===', toString(elem.childNodes), '^4312$^4312$^4312$')
ct('===', toString(elem.childNodes), '')
co.update([])
ct('===', toString(elem.childNodes), '^$^$^$')
comp.update([{k: 1, v:1}, {k: 'b', v:'b'}])
ct('===', toString(elem.childNodes), '1b')
co.update([1,5,3])
ct('===', toString(elem.childNodes), '^153$^153$^153$')
})
comp.update([{ k: 'b', v: 'bb' }, { k: 1, v: 11 }])
ct('===', toString(elem.childNodes), 'b1', 'must use existing nodes')
ct('list stacked and grouped', function() {
var co = el('div').append(
select([
list(text),
list(text.bind(text,'x')),
list(function() { return text('y') })
])
)
comp.update([{k: 'c', v:'c'}])
ct('===', toString(elem.childNodes), 'c')
var elem = co.node
co.update([1,2,3])
ct('===', toString(elem.childNodes), '^^123$^123$^123$$')
co.update([4,3,1,2])
ct('===', toString(elem.childNodes), '^^4312$^4312$^4312$$')
co.update([])
ct('===', toString(elem.childNodes), '^^$^$^$$')
co.update([1,5,3])
ct('===', toString(elem.childNodes), '^^153$^153$^153$$')
comp.update([{ k: 'b', v: 'bbb' }, { k: 'c', v: 'ccc' }, { k: 1, v: 111 }])
ct('===', toString(elem.childNodes), 'bbbc111', 're-creates removed nodes')
})
ct('list nested', function() {
var childFactory = function() { return el('h0').append(text('')) },
co = el('div').append(
list(function() {
return list(childFactory)
})
)
var elem = co.node
ct('list - multiple', function() {
function childFactory() {
return co(el('p'))
}
var comp = co(el('div'), ls(childFactory), ls(childFactory)),
elem = comp.node
ct('===', toString(elem.childNodes), '^$')
ct('===', toString(elem.childNodes), '<>')
co.update([[1,2],[3,4]])
ct('===', toString(elem.childNodes), '^^12$^34$$')
comp.update([1,2,3])
ct('===', toString(elem.childNodes), '123<>123')
co.update([[1],[],[2,3,4]])
ct('===', toString(elem.childNodes), '^^1$^$^234$$')
comp.update([4,3,1,2])
ct('===', toString(elem.childNodes), '4312<>4312')
co.update([[1,2,3,4]])
ct('===', toString(elem.childNodes), '^^1234$$')
})
comp.update([])
ct('===', toString(elem.childNodes), '<>')
ct('list keyed', function() {
var co = el('h0').append(
list(function() {
return text('x').c('update', function(v) { this.node.textContent = v.v; this.update = null })
}).c('getKey', v => v.k)
)
var elem = co.node
ct('===', toString(elem.childNodes), '^$')
co.update([{k: 1, v:1}, {k: 'b', v:'b'}])
ct('===', toString(elem.childNodes), '^1b$')
co.update([{ k: 'b', v: 'bb' }, { k: 1, v: 11 }])
ct('===', toString(elem.childNodes), '^b1$', 'must use existing nodes')
co.update([{k: 'c', v:'c'}])
ct('===', toString(elem.childNodes), '^c$')
co.update([{ k: 'b', v: 'bbb' }, { k: 'c', v: 'ccc' }, { k: 1, v: 111 }])
ct('===', toString(elem.childNodes), '^bbbc111$', 're-creates removed nodes')
comp.update([1,5,3])
ct('===', toString(elem.childNodes), '153<>153')
})
ct('list select', function() {
var co = el('h0').append(
select({
a: text('').c('update', function(v) { this.node.textContent = 'a'+v }),
b: text('').c('update', function(v) { this.node.textContent = 'b'+v })
}).c('select', v => v)
)
var elem = co.node
ct('===', toString(elem.childNodes), '^$')
co.update('a')
ct('===', toString(elem.childNodes), '^aa$')
co.update('b')
ct('===', toString(elem.childNodes), '^bb$')
co.update('c')
ct('===', toString(elem.childNodes), '^$')
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc