1.0.2 • Published 8 years ago

cycle-custom-elementify v1.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
8 years ago

Cycle.js customElementify

Experimental

Helper function that takes a Cycle.js component ((sources: Sources) => Sinks) and returns a JavaScript class that can be registered as a Web Component custom element with document.registerElement:

import customElementify from 'cycle-custom-elementify';

function main(sources) {
  // ...
}

const customElementClass = customElementify(main);
document.registerElement('my-web-component', { prototype: customElementClass });
<my-web-component></my-web-component>

Installation

npm install cycle-custom-elementify

Required!

Your target browser must support Custom Elements v0. To install the polyfill:

  • npm install webcomponents.js
  • Include <script src="./node_modules/webcomponents.js/webcomponents.js"></script> in your page

This library is experimental and so far only supports Cycle.js apps written with xstream. You can only customElementify a function that expects xstream sources and sinks.

Usage

Your Cycle.js component function can expect sources to have DOM and props:

// TypeScript signature:
type Sources = {
  DOM: DOMSource,
  props: Stream<Object>
}

Your component's sinks should have DOM and any other sink will be converted to DOM events on the custom element:

// TypeScript signature:
type Sinks = {
  DOM: Stream<VNode>,
  bark: Stream<string>,
  // `bark` sink stream will be converted to DOM Events emitted on the resulting custom element
}

Write your function MyButton: (sources: Sources) => Sinks like you would do with any typical Cycle.js app. sources.props is a Stream of objects that contain attributes given to the custom element.

Then convert it to a custom element class:

import customElementify from 'cycle-custom-elementify';

const customElementClass = customElementify(MyButton);

Then, register your custom element on the DOM with a tagName of your choice:

document.registerElement('my-button', customElementClass);

If you want to use this my-button inside another Cycle.js app, be careful to wait for the WebComponentsReady event first:

window.addEventListener('WebComponentsReady', () => {
  document.registerElement('my-button', { prototype: customElementify(MyButton) });
  Cycle.run(main, {
    DOM: makeDOMDriver('#app-container')
  });
});

If your parent Cycle.js app passes attributes to the custom element, then they will be available as sources.props in the child Cycle.js app (inside the custom element):

function main(sources) {
  // ...

  const vnode$ = xs.of(
    div([
      h('my-button', {attrs: {color: 'red'}})
    ])
  );

  // ...
}
function MyButton(sources) {
  const color$ = sources.props.map(p => p.color);

  // ...
}

Known issues

  • This is an experimental library :)
  • We're following the Custom Elements V0 spec, not yet V1
  • The custom elements generated by this helper do not support children yet, only attributes
  • Using this library might confuse the Cycle.js DevTool