Comparing version 1.0.0 to 2.0.0
109
index.js
var document = require('global/document') | ||
var parseTag = require('./parse-tag.js') | ||
var hyperx = require('hyperx') | ||
var morphdom = require('morphdom') | ||
module.exports = function bel (tag, props) { | ||
tag = tag || 'div' | ||
if (typeof tag !== 'string') { | ||
props = tag | ||
tag = 'div' | ||
} | ||
props = props || {} | ||
tag = parseTag(tag, props) | ||
var SET_ATTR_PROPS = { | ||
class: 1, | ||
value: 1 | ||
} | ||
var BOOL_PROPS = { | ||
autofocus: 1, | ||
checked: 1, | ||
defaultChecked: 1, | ||
disabled: 1, | ||
formNoValidate: 1, | ||
indeterminate: 1, | ||
readOnly: 1, | ||
required: 1, | ||
willValidate: 1 | ||
} | ||
var hx = hyperx(function createElement (tag, props, children) { | ||
var el = document.createElement(tag) | ||
var propKeys = Object.keys(props) | ||
propKeys.forEach(function (name) { | ||
var prop = props[name] | ||
if (name.slice(0, 2) === 'on') { | ||
el.addEventListener(name.slice(2), function () { | ||
return prop.call(this, Array.prototype.slice.call(arguments)) | ||
}, false) | ||
} else { | ||
el[name] = prop | ||
for (var p in props) { | ||
if (props.hasOwnProperty(p)) { | ||
var val = props[p] | ||
// If a property is boolean, set itself to the key | ||
if (BOOL_PROPS[p]) { | ||
if (val === 'true') val = p | ||
else if (val === 'false') continue | ||
} | ||
// If a property prefers setAttribute instead | ||
if (SET_ATTR_PROPS[p] || BOOL_PROPS[p]) { | ||
el.setAttribute(p, val) | ||
} else { | ||
el[p] = val | ||
} | ||
} | ||
}) | ||
} | ||
function appendChild (childs) { | ||
if (!Array.isArray(childs)) return | ||
for (var i = 0; i < childs.length; i++) { | ||
var node = childs[i] | ||
if (Array.isArray(node)) { | ||
appendChild(node) | ||
continue | ||
} | ||
// TODO: Escaping? | ||
if (typeof node === 'number' || | ||
typeof node === 'boolean' || | ||
node instanceof Date || | ||
node instanceof RegExp) { | ||
node = node.toString() | ||
} | ||
if (typeof node === 'string') { | ||
node = document.createTextNode(node) | ||
} | ||
if (node && node.nodeName && node.nodeType) { | ||
el.appendChild(node) | ||
} | ||
} | ||
} | ||
appendChild(children) | ||
// TODO: Validation checks | ||
// TODO: Check for a11y things | ||
return el | ||
}) | ||
// TODO: SVG Support | ||
var id = 0 | ||
module.exports = function bel () { | ||
var el = hx.apply(this, arguments) | ||
if (!el.id) { | ||
el.id = 'e' + id | ||
id += 1 | ||
} | ||
el.update = function (newel) { | ||
if (typeof newel === 'function') { | ||
newel = newel() | ||
} | ||
// TODO: Someday eliminate the need for this | ||
// We need to look up the actual element in the DOM because a parent element | ||
// could have called .update() and replaced the child node | ||
el = document.getElementById(el.id) | ||
newel.id = el.id | ||
morphdom(el, newel) | ||
} | ||
return el | ||
} |
{ | ||
"name": "bel", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "A simple extension to native elements", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "wzrd test.js:bundle.js", | ||
"test": "standard && browserify test.js | testron" | ||
@@ -25,4 +26,5 @@ }, | ||
"dependencies": { | ||
"browser-split": "0.0.1", | ||
"global": "^4.3.0" | ||
"global": "^4.3.0", | ||
"hyperx": "^1.3.1", | ||
"morphdom": "^1.1.2" | ||
}, | ||
@@ -34,9 +36,5 @@ "devDependencies": { | ||
"tape": "^4.4.0", | ||
"testron": "^1.2.0" | ||
}, | ||
"standard": { | ||
"ignore": [ | ||
"parse-tag.js" | ||
] | ||
"testron": "^1.2.0", | ||
"wzrd": "^1.3.1" | ||
} | ||
} |
146
README.md
# [bel](https://en.wikipedia.org/wiki/Bel_(mythology)) | ||
A simple convenience helper for creating native DOM elements. | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![Downloads][downloads-image]][downloads-url] | ||
[![js-standard-style][standard-image]][standard-url] | ||
![experimental][experimental-image] | ||
[![build status](https://secure.travis-ci.org/shama/bel.svg)](https://travis-ci.org/shama/bel) | ||
A simple library for composable DOM elements using [tagged template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). | ||
## usage | ||
### A Simple Element | ||
Create an element: | ||
```js | ||
var bel = require('bel') | ||
var element = bel('button.clicker', { | ||
onclick: function () { | ||
element.innerHTML = 'I have been clicked!' | ||
}, | ||
innerHTML: 'Click me' | ||
}) | ||
document.body.appendChild(element) | ||
// list.js | ||
var $ = require('bel') | ||
module.exports = function (items) { | ||
return $`<ul> | ||
${items.map(function (item) { | ||
return $`<li>${item}</li>` | ||
})} | ||
</ul>` | ||
} | ||
``` | ||
Where natively you would do: | ||
Then pass data to it and add to the DOM: | ||
```js | ||
var element = document.createElement('button') | ||
element.className = 'clicker' | ||
element.addEventListener('click', function () { | ||
element.innerHTML = 'I have been clicked!' | ||
}, false) | ||
element.innerHTML = 'Click me' | ||
document.body.appendChild(element) | ||
// app.js | ||
var createList = require('./list.js') | ||
var list = createList([ | ||
'grizzly', | ||
'polar', | ||
'brown' | ||
]) | ||
document.body.appendChild(list) | ||
``` | ||
### custom events | ||
### Data Down, Actions Up | ||
Also includes a convenience helper for custom events: | ||
```js | ||
var send = require('bel/send') | ||
var element = bel('button.clicker', { | ||
onclick: function () { | ||
send(element, 'selected', 'I have been clicked!') | ||
}, | ||
innerHTML: 'Click me' | ||
}) | ||
// list.js | ||
var $ = require('bel') | ||
// ... | ||
element.addEventListener('selected', function (e) { | ||
element.innerHTML = e.detail | ||
}) | ||
// The DOM is built by the data passed in | ||
module.exports = function (items, onselected) { | ||
function render () { | ||
return $`<ul> | ||
${items.map(function (item) { | ||
return $`<li>${button(item.id, item.label)}</li>` | ||
})} | ||
</ul>` | ||
} | ||
function button (id, label) { | ||
return $`<button onclick=${function () { | ||
// Then action gets sent up | ||
onselected(id) | ||
}}>${label}</button>` | ||
} | ||
var element = render() | ||
return element | ||
} | ||
``` | ||
### usage with [diffhtml](https://github.com/tbranyen/diffhtml) | ||
This creates native elements so if you're using a DOM diffing library that works | ||
with native elements, like `diffhtml`, you can do the following: | ||
```js | ||
var bel = require('bel') | ||
var send = require('bel/send') | ||
var diff = require('diffhtml') | ||
// app.js | ||
var $ = require('bel') | ||
var list = require('./list.js') | ||
var ul = bel('ul') | ||
function render (items) { | ||
items.forEach(function (item) { | ||
var li = bel('li', { | ||
onclick: function () { | ||
send(ul, 'selected', item.id) | ||
}, | ||
innerHTML: item.name | ||
}) | ||
// Add each li to the parent ul | ||
diff.element(ul, li, { inner: true }) | ||
}) | ||
// Add ul to document.body | ||
diff.element(document.body, ul) | ||
module.exports = function (bears) { | ||
function onselected (id) { | ||
// When a bear is selected, rerender with the newly selected item | ||
// This will use DOM diffing to render, sending the data back down again | ||
element.update(render(id)) | ||
} | ||
function render (selected) { | ||
return $`<div className="app"> | ||
<h1>Selected: ${selected}</h1> | ||
${list(bears, onselected)} | ||
</div>` | ||
} | ||
// On first render, we haven't selected anything | ||
var element = render('none') | ||
return element | ||
} | ||
// Render to the DOM | ||
render([ | ||
{ id: 1, name: 'Grizzly' }, | ||
{ id: 2, name: 'Polar' } | ||
{ id: 3, name: 'Brown' } | ||
]) | ||
// Listen for the selected event | ||
ul.addEventListener('selected', function (e) { | ||
console.log(e.detail + ' has been selected') | ||
}) | ||
``` | ||
@@ -103,1 +103,11 @@ | ||
(c) 2016 Kyle Robinson Young. MIT License | ||
[npm-image]: https://img.shields.io/npm/v/bel.svg?style=flat-square | ||
[npm-url]: https://npmjs.org/package/bel | ||
[travis-image]: https://img.shields.io/travis/shama/bel/master.svg?style=flat-square | ||
[travis-url]: https://travis-ci.org/shama/bel | ||
[downloads-image]: http://img.shields.io/npm/dm/vel.svg?style=flat-square | ||
[downloads-url]: https://npmjs.org/package/bel | ||
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square | ||
[standard-url]: https://github.com/feross/standard | ||
[experimental-image]: https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square |
49
test.js
var test = require('tape') | ||
var bel = require('./') | ||
var $ = require('./') | ||
test('creates an element', function (t) { | ||
t.plan(2) | ||
var button = bel('button.clicker', { | ||
onclick: function () { | ||
t.ok(true, 'was clicked') | ||
t.end() | ||
}, | ||
innerHTML: 'click me' | ||
}) | ||
t.equal(button.outerHTML, '<button class="clicker">click me</button>') | ||
t.plan(3) | ||
var button = $`<button onclick=${function () { | ||
onselected('success') | ||
}}>click me</button>` | ||
var result = $`<ul> | ||
<li>${button}</li> | ||
</ul>` | ||
function onselected (result) { | ||
t.equal(result, 'success') | ||
t.end() | ||
} | ||
t.equal(result.tagName, 'UL') | ||
t.equal(result.querySelector('button').textContent, 'click me') | ||
button.click() | ||
}) | ||
test('using class and className', function (t) { | ||
t.plan(2) | ||
var result = $`<div className="test1"></div>` | ||
t.equal(result.className, 'test1') | ||
result = $`<div class="test2 another"></div>` | ||
t.equal(result.className, 'test2 another') | ||
t.end() | ||
}) | ||
test('create inputs', function (t) { | ||
t.plan(5) | ||
var expected = 'testing' | ||
var result = $`<input type="text" value="${expected}" />` | ||
t.equal(result.tagName, 'INPUT', 'created an input') | ||
t.equal(result.value, expected, 'set the value of an input') | ||
result = $`<input type="checkbox" checked="${true}" disabled="${false}" />` | ||
t.equal(result.getAttribute('type'), 'checkbox', 'created a checkbox') | ||
t.equal(result.getAttribute('checked'), 'checked', 'set the checked attribute') | ||
t.equal(result.getAttribute('disabled'), null, 'should not have set the disabled attribute') | ||
t.end() | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7443
123
113
3
6
6
1
+ Addedhyperx@^1.3.1
+ Addedmorphdom@^1.1.2
+ Addedhyperx@1.4.1(transitive)
+ Addedmorphdom@1.4.6(transitive)
- Removedbrowser-split@0.0.1
- Removedbrowser-split@0.0.1(transitive)