GithubHelp home page GithubHelp logo

skatejs / skatejs Goto Github PK

View Code? Open in Web Editor NEW
3.3K 66.0 139.0 11.48 MB

Effortless custom elements powered by modern view libraries.

Home Page: http://skatejs.netlify.com/

License: MIT License

JavaScript 62.90% HTML 1.78% TypeScript 35.32%
web-components reactiveui javascript

skatejs's Introduction

Skate

Build Status Downloads per month Join the chat at https://gitter.im/skatejs/skatejs Follow @skate_js on Twitter

Skate is a functional reactive abstraction over the web component standards as a set of packages that enables you to write small, fast and scalable web components using popular view libraries such as React, Preact and LitHTML.

  • ๐ŸŒ Cross-framework compatible components.
  • โš›๏ธ Render components using your favourite view library, or none at all.
  • ๐Ÿ‘‘ Guided conventions for best-practices when reflecting between, and reacting to attributes, properties and events.
  • ๐ŸŒŸ Full TypeScript support.
  • ๐Ÿ“š Docs https://skatejs.netlify.com.

Getting started

The simplest way to get up and running is to start with a pre-configured element such as @skatejs/element-lit-html.

npm i @skatejs/element-lit-html

Simple example

import Element, { html } from '@skatejs/element-lit-html';

export default class extends Element {
  static get props() {
    return {
      name: String
    };
  }
  render() {
    return html`
      Hello, ${this.name}!
    `;
  }
}

Other examples

  1. Todo list

Cli

There's a CLI to get you up and running: https://skatejs.netlify.com/packages/cli.

$ npm i -g @skatejs/cli
$ skatejs

Polyfills

Skate builds upon the Custom Elements and the Shadow DOM standards. It is capable of operating without the Shadow DOM โ€” it just means you don't get any encapsulation of your component's HTML or styles. It also means that it's up to you to provide a way to project content (i.e. <slot>). It's highly recommended you use Shadow DOM whenever possible.

Though most modern browsers support these standards, some still need polyfills to implement missing or inconsistent behaviours for them.

For more information on the polyfills, see the web components polyfill documentation, emphasis on the caveats.

Browser Support

Skate supports all evergreens and IE11, and is subject to the browser support matrix of the polyfills.

Backers

Support us with a monthly donation and help us continue our activities. Become a backer!

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site. Become a sponsor!

skatejs's People

Contributors

adevnadia avatar andreawyss avatar bedeoverend avatar bengummer avatar blikblum avatar bqx avatar bradleyayers avatar cary-smith avatar chrisdarroch avatar deini avatar freeman avatar greenkeeperio-bot avatar hotell avatar joscha avatar jpnelson avatar juicelink avatar klipstein avatar lukebatchelor avatar majo44 avatar matiasatlassian avatar matthewp avatar nminhnguyen avatar nvenegas avatar renovate-bot avatar trescenzi avatar treshugart avatar trusktr avatar vvakame avatar wangersnmash avatar zzarcon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

skatejs's Issues

Support document.registerElement().

Underneath the hood, skate should use the native DOM methods for registering custom elements if they are supported, otherwise just fallback to normal operation.

It should use native when:

  1. Native is supported, otherwise fallback.
  2. The tag name has a dash in it, otherwise fallback.
  3. The component is compatible with tag bindings. If it supports other bindings then use native for the custom element and fallback for the others.

Destroy all instances.

Need a way to destroy all skate instances.

skate.destroy();

All instances will stop listening.

Second argument, if a function, should instead dynamically resolve a component.

Currently, if the second argument is a function, it is used as the insert callback. A better usage for this is to be dynamic - possibly async - component resolver.

// Sync. Returns the component to use.
skate(fnOrSelector, function (element) {
  var tag = element.tagName.toLowerCase().substring(0, 2);
  return window.components[tag];
});

// Async. Uses RequireJS to dynamically resolve the component and
// pass to done() to continue execution with the passed component.
skate(fnOrSelector, function (element, done) {
  var tag = element.tagName.toLowerCase().substring(0, 2);
  require(['components/' + tag], function(component) {
    done(component);
  });
});

Add ability to auto-bind/unbind events.

Component definition should accept an events object that will bind them when ready and unbind them when removed.

Each key in the events object is the event name and the value is the handler function. The only parameter passed to the handler should be the event object.

Deprecate skate.init and use skate.when instead.

skate.init() is meant to synchronously initialise an element against all it's possible components. Internally, we still need a way to initialise elements against their possible ids, but publicly, the developer should only need to know about the async promise-like way to wait for the init of a particular component.

Skate should add methods and properties to DOM elements.

In order to move more towards web components, it would be good for methods and properties to be applied to the DOM elements when the component is initialised so that they can be called anytime after initialisation on the element directly.

skate('div', {
  insert: initialiseElement,
  show: showDiv
});

Some HTML:

<div id="my-div">...</div>

And somewhere else:

document.getElementById('my-div').show();

Add a way to do simple templating.

Rules:

  • Templates are not used by default.
  • A template can be specified using a string.
  • A template can be a function that should modify the passed element.

String:

...
template: 'some string'
...

Function:

...
template: function (element) {
  element.innerHTML = 'some string';
}
...

A template should be able to contain a single <content> element which is replaced with the content that the template subsequently replaces.

Sample template:

<span><content></content></span>

Add an init() method to the element constructor.

The constructor is the result of a call to skate(id, opts). It should have the following signature:

ElementConstructor.init = function (element) { ... };

It should take an element, and initialise it as the element in which the constructor represents regardless of if it can, or cannot, be constructed using the constructor itself.

This method must ensure that the element that is passed in, in fact can be augmented by this particular component. If not, then consider warn / throw / no-op.

Add ability to pass a matching function instead of just a selector.

This allows components to be dynamically resolved based on information from the matched element.

// Matches all tags starting with "x-".
// e.g. <x-component>...</x-component>
function matcher (element) {
  return element.tagName.substring(0, 2) === 'X-';
}

skate(matcher, {
  insert: function() {
    // do something
  }
});

Race condition when calling methods on uninitialised components

If you skate 2 components, A and B, and in B you call a method from A it will throw an error if A hasn't been initialised yet.

Possible fixes:

  • some kind of promise/when system
  • init component A from within component B - eg
skate(A, {
    insert: function() { // do stuff },
    extend: {
        foo: function() { // do stuff }
    }
});
skate(B, {
    insert: function() {
        skate.init(A).foo();
    }
});

An element should only be initialised once.

When skate.init() is called on an element, it should only allow initialisation once for that element. This will not work:

var element = document.createElement('div');

// first binding
element.setAttribute('data-binding-1', '');

// initialise
skate.init(element);

// second binding
element.setAttribute('data-binding-2');

// does not initialise second binding
skate.init(element);

Need a way to manually initialise an element synchronously in the DOM.

Use case:

skate('div', {
  ready: initDiv,
  show: showDiv
});

var div = document.createElement('div');
document.body.appendChild(div);

// This may or may not be available since Skate operates async.
div.show();

Implementations:

// Immediately initialise the div against any matching components.
var div = document.createElement('div');
document.body.appendChild(div);
skate(div);

// Throws an exception because the element is not in the DOM yet.
skate(document.createElement('div'));

// Select all matching elements and initialise them if they have not been initialised yet.
skate('div');

Note, if initialising an element directly, that element should be returned. If initialising a selection of elements, then an array of elements should be returned.

skate(div).customMethod();
skate('div').forEach(function(div) { ... });

Consider adding the ability to bind delegate events to a component.

This would be similar to Backbone's events:

skate('my-element', {
  events: {
    'click': function (element, e) {},
    'click .menu-item': function (element, e) {}
  }
});

Or don't impose a syntax and be more like the attributes object:

skate('my-element', {
  events: {
    click: {
      '&': function (element, e) {},
      '.menu-item': function (element, e) {}
    }
  }
});

Add a MutationObserver adapter

As per this JSPerf http://jsperf.com/skate/5 it would seem that animation events are throttled due to some internal throttling of animations. This makes the deprecated mutation events in IE9 much faster than Chrome using the animationStart event. That said, Chrome still performs fast when a lot of elements are inserted in a real world scenario (not noticeable under large DOM insertions), however MutationObservers would give us a modern solution without relying on animations which is sort of a hack.

Do not skate items within a <template> tag.

This may not happen in browsers that support templating, but it definitely happens in older browsers that do not which may have polyfills associated with them. In order to keep the dom as inert as possible it'd be good to not touch the content within them.

Call to skate() should return a constructor that extends HTMLElement.

Currently, skate() returns a constructor that when invoked returns the skated element. It would be better if what is returned is a constructor returned from the call actually extends a native DOM HTMLElement, prototype and all so this then would work:

var El = skate('my-el', { ... });

El.prototype.someFunc = function () { ... };

var el = new El();
el.someFunc();

The implementation would have to change internally to where the prototype option would be applied to this prototype rather than applied to the element post-construction.

Investigate listening to attribute changes.

We must:

  1. Prove there isn't a significant performance hit using http://jsperf.com/skate/6 as a baseline.
  2. Ensure that anything using the deprecated mutation events behave predictably.
  3. Ensure that animation events are in fact triggered.
  4. Ensure browsers that support mutation observers also support this feature.

Expand on simple templating.

Simple templating should follow more of the ShadowDOM spec. In particular:

  • It should replace all <content> tags.
  • Content tags should be able to select which nodes they want to represent.

Replacing all content tags:

<my-template>
  <content></content>
  <content></content>
</my-template>

Selecting what they want to represent using a selector passed into the select attribute:

<my-template>
  <content select="one:first-of-type"></content>
  <content select="two:first-of-type"></content>
</my-template>

Add a skate.version property.

Will also need to make this a placeholder that gets changed when releasing. Would be good to just make that a task.

Add ability to blacklist an element (and children) from being initialised.

Use an attribute called data-skate-ignore. This should flag the element and its children from being initialised.

The use case for this is avoiding needless performance issues in extremely large DOMs (50k+ elements) in browsers like Internet Explorer. It also allows you to opt-out of skate. Due to this being an edge-case, and given the nature of web components, this should be opt-out rather than opt-in.

Attributes should accept a function that gets called for all attribute mutations.

Calling a single callback for all attributes:

skate('my-component', {
  attributes: function (element, data) {
    data.type; // type of mutation
    data.name; // name of attribute mutated
    data.newValue; // new value after mutation
    data.oldValue; // old value before mutation
  }
});

Calling a single callback for a specific attribute:

skate('my-component', {
  attributes: {
    name: function (element, data) {
      ...
    }
  }
});

All callbacks should receive a data object instead of specific arguments in order to make the attribute mutation API more consistent:

skate('my-component', {
  attributes: {
    name: {
      insert: function (element, data) {
        ...
      },
      update: function (element, data) {
        ...
      },
      remove: function (element, data) {
        ...
      }
    }
  }
});

Method on a component instance to directly register an element.

Use cases:

  1. If you have a component that modifies an element which, when modified, matches a component selector, it will not be picked up by the registered components as attribute listening is not enabled.
  2. If you want one component to proxy another component for whatever reason.

Example code:

var instance = skate('div', function(){});

// Should allow anything that can be passed to skate() with a single argument.
instance.init(div1);
instance.init([div1, div2]);
instance.init(div1.childNodes);
instance.init('div');
// ...

All synchronous initialisation code should be modified to utilise this as much as possible.

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.