Package Exports
- rwc
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (rwc) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
rwc (BETA)
RWC is a unique mix of Shadow DOM + Virtual DOM + Redux to create web-components. This approach is an attempt to find a balance between a scalable paradigm and performance.
Installation
npm install rwc --saveParadigm
Components are composed of three functions —
init(component): The function takes in the current instance of the component and returns the initial state.update(state, action): A reducer function like that in Redux that takes an inputstateand based on theactionreturns a new output state. Additionally it can return a tuple (an array) of two elements containing both thestateand an object of CustomEvent type, which is dispatched as a DOM event.view(state, dispatch): The view function converts thestateinto a virtual DOM tree. Additionally it also gets adispatch()function which can dispatch actions on DOM events.
All these three functions are essentially pure functions, ie. they have no side effects and should remain referentially transparent for all practical purposes.
Create Component
// CounterComponent.js
import h from 'snabbdom/h'
// Creates an initial state
const init = () => {
return {count: 0}
}
// Reducer function for redux
const update = (state, {type, params}) => {
switch (type) {
case 'INC': return {count: state.count + 1}
case 'DEC': return {count: state.count - 1}
default: return state
}
}
// Creates virtual DOM elements
const view = ({count}, dispatch) => {
return h('div', [
h('h1', [count]),
h('button', {on: {click: dispatch('INC')}}, ['Increment']),
h('button', {on: {click: dispatch('DEC')}}, ['Decrement'])
])
}
export default {init, view, update}Register Web Component
import rwc from 'rwc'
import CounterComponent from './CounterComponent'
function virtualDOMPatcher (shadowRoot) {
return (vnode) => /* patches the shadowRoot with vNode */
}
// create prototype object
const proto = rwc.createWCProto(virtualDOMPatcher, CounterComponent)
// create an HTMLElement instance
const html = Object.create(HTMLElement.prototype)
// extend html element with the created prototype
const CounterHTMLComponent = Object.assign(html, proto)
// register as usual
document.registerElement('x-counter', {prototype: CounterHTMLComponent})Virtual DOM Patcher
The virtualDOMPatcher function argument gives the to ability to customize how the shadow DOM is updated.
Examples:
import snabbdom from 'snabbdom'
function virtualDOMPatcher (shadowRoot) {
const patch = snabbdom.init()
let __vNode = shadowRoot.appendChild(document.createElement('div'))
return function (vNode) {
__vNode = patch(__vNode, vNode)
}
}import { render } from 'preact'
import { createElement as h } from 'preact-hyperscript'
function virtualDOMPatcher (shadowRoot) {
let __vNode
return function (vNode) {
__vNode =render(vNode, shadowRoot, __vNode)
}
}import {h, createProjector} from 'maquette'
function virtualDOMPatcher (root) {
let __vNode
const projector = createProjector()
const render = () => projector.append(root, () => __vNode)
return function (vNode) {
if(!__vNode) {
__vNode = vNode
render()
}
__vNode = vNode
}
}Dispatching Custom Events
For components to communicate with the outside world the component can dispatch a CustomEvent via the update() function.
export const update = (state, {type, params}) => {
switch (type) {
case 'INC':
{count: state.count + 1},
return [
{count: state.count + 1},
new CustomEvent('changed', {detail: _state.count})
]
case 'DEC':
const _state = {count: state.count - 1}
return [
_state,
new CustomEvent('changed', {detail: _state.count})
]
default: return state
}
}Listening to attribute changes
Attribute changes are fired as actions and are namspaced with @@attr. For example —
<x-counter some-custom-attribute="100" />The changes can be observed inside the update function using @@attr/some-custom-attribute —
update (state, {type, params}) {
switch (type) {
case '@@attr/some-custom-attribute':
return {count: state.count + parseInt(params)}
default: return state
}
}Listening to the attached event
A special action @@attached is fired when the component is attached into the DOM.
The param for this action is the instance of the web component.
update (state, {type, params}) {
switch (type) {
case '@@attached':
return {width: params.getBoundingClientRect().width}
default: return state
}
}raf
raf~createWCProto ⇒ Object
Creates the prototype for the web component element.
Kind: inner property of raf
Returns: Object - prototype object for creating HTMLElements
| Param | Type | Description |
|---|---|---|
| virtualDOMPatcher | function |
patches the virtual dom on shadowRoot. |
| component | Object |
|
| component.init | function |
returns the initial state of the component. |
| component.update | function |
a redux reducer for updating component state. |
| component.view | function |
takes in the state and returns a dom tree. |