Code Monkey home page Code Monkey logo

excise's Introduction

excise

a toolkit for writing functional-style (react-like) web components, based on diffhtml

install

npm install excise

Or give it a try using this JSBin in Chrome.

usage

basic

you'll need a browser that supports custom elements v1 and shadow dom v1. chrome 55 will work.

const {define, html} = require('excise');

define('x-hello-world', () => html`<h1>it works!</h1>`);

document.body.innerHTML = '<x-hello-world></x-hello-world>';

polyfills

the only polyfills i've found that work are custom-elements and shadydom. they're not fully on npm yet but they can be installed with:

npm install --save webcomponents/shadydom webcomponents/custom-elements

and then include them with

require('@webcomponents/shadydom');
require('@webcomponents/custom-elements');

or as entry points to your bundle

bundling

i've found it difficult to get this working with webpack because it thinks define means AMD and even if you disable that plugin it breaks. just use browserify, and don't bother with babel because we need to natively extend HTMLElement.

props

element attributes are passed as an object to the render function

const {define, html} = require('excise');

define('x-count', ({count}) => html`<h1>${count}</h1>`);

document.body.innerHTML = '<x-count count="5"></x-count>';

pass a third argument to define to specify the types of the props, for coercion:

const {define, html, types} = require('excise');

define('x-increment', ({count}) => html`<h1>${count + 1}</h1>`, {count: types.number});

document.body.innerHTML = '<x-increment count="5"></x-increment>';

server rendering

call renderToString with an html block:

const {define, html, renderToString} = require('excise');

define('x-foo', () => html`<h1>hello</h1>`);

renderToString(html`<x-foo></x-foo>`); //⇒ <x-foo><span slot="__excise_rendered"><h1>hello</h1></span></x-foo>

the extra span allows you to reuse the server-rendered markup on the client. when your elements are defined, the __excise_rendered slot is ignored.

events

on* attributes are attached to elements as event handlers:

const {define, html} = require('excise');

define('x-button', () => html`<button onclick=${() => alert('hello!')}>click me</button>`);

document.body.innerHTML = '<x-button></x-button>';

state

StatefulComponent watches its attributes and rerenders when they change:

const {StatefulComponent, html, types} = require('excise');

StatefulComponent.define('x-counter',
	(props, el) => html`<b>${props.count}</b> <button onclick=${() => el.setAttribute('count', props.count + 1)}>click me}</button>`,
	{count: types.number}
);

document.body.innerHTML = '<x-counter count="1"></x-counter>';

there's a little bit of oddness here. we can't destructure count here like in previous examples, because of how diffhtml renders the button. the actual dom of the button never changes (it's the same structure) so diffhtml leaves it alone when count updates. this means the onclick handler still closes over count from the first run of the render function, and the button only works once.

shadow dom/slots

const {define, html} = require('excise');

define('x-shadow', () => html`<slot name="title" /> <h2>slots work</h2>`);

document.body.innerHTML = '<x-shadow><h1 slot="title">it works!</h1></x-shadow>';

classes

const {Component, html, types} = require('excise');

define(class XClassComponent extends Component {
	static get propTypes() {
		return {
			greeting: types.string,
		};
	}

	render() {
		return html`<h1>it works! ${this.props.greeting}</h1>`;
	}
});

document.body.innerHTML = '<x-class-component greeting="hello!"></x-class-component>'

licence

ISC. © kara brightwell

excise's People

Contributors

apaleslimghost avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

bjfletcher

excise's Issues

Implementing setState

Have you considered adding in setState-like functionality?

Maybe something like this:

import { outerHTML } from 'diffhtml';

class StatefulComponent extends Component {
  setState(newState) {
    this.state = Object.assign({}, this.state, newState);

    // Patch the previously rendered node with the new VTree.
    outerHTML(this, this.render());
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.