npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@lamplightdev/compost

v1.1.12

Published

A collection of Web Component mixins

Downloads

21

Readme

compost

A collection of small Web Component mixins to add commonly required functionality without the bloat

  • No dependencies - just mixin and go
  • Plain JavaScript - no build tools required, compatible by default, debug in the browser with standard dev tools
  • No magic - straight forward to understand
  • Small & efficient - low overhead to keep your components lean
  • Include only what you need - take it or leave it
  • Cross browser - works on all modern browsers and IE11

Example Hacker News progressive web app - https://github.com/lamplightdev/compost-hn

Table of Contents

Install

Install using npm:

npm install --save @lamplightdev/compost

Mixins

CompostShadowMixin

Adds a shadow DOM to your component. Takes a string returned from a render() method to set up the shadow DOM, and adds ShadyCSS support if the polyfill is included for browsers that don't natively support shadow DOM. Also adds some convenience accessors for querying shadow DOM elements.

CompostPropertiesMixin

Lets you specify your component's properties upfront, their types, whether their value should be reflected in an attribute, and an observer function to run when the property changes.

CompostEventsMixin

Let's you add declarative event binding in your templates. Also adds some convenience methods for manual event binding and firing.

CompostRepeatMixin

Experimental - Stamps out a template for each object in the items array property

CompostMixin

A convenience mixin that includes CompostShadowMixin, CompostPropertiesMixin, and CompostEventsMixin:

const CompostMixin = (parent) => {
  return class extends
    CompostEventsMixin(
      CompostPropertiesMixin(
        CompostShadowMixin(parent))) {}
};

Where's the data binding?

There is none. For simple, well structured components you may not need data binding - turns out you can get a lot done with the standard DOM APIs (and it's the most efficient way to update the DOM too). But if data binding is your thing you can simply extend CompostShadowBaseMixin to include your data binding library of choice (I like lit-html.)

Usage

CompostShadowMixin

<x-app></x-app>

<script>
  class App extends CompostShadowMixin(HTMLElement) {
    render() {
      return `
        <style>
          :host {
            display: flex;
            flex-direction: column;
            max-width: 1280px;
            margin: 0 auto;
          }
        </style>

        <button class="button" id="buttonEat">Eat me</button>
        <button class="button" id="buttonDrink">Drink me</button>
        <button class="button" id="buttonClick">Click me</button>
      `;
    }
  }

  customElements.define('x-app', App);
</script>

Implement a render method that returns a string - your x-app component now has a shadow DOM with encapsulated CSS.

In addition the following convenience properties are added:

this.$s is a reference to the shadow DOM

this.$ is equivalent to app.shadowRoot.querySelector

this.$$ is equivalent to app.shadowRoot.querySelectorAll

this.$id is an object containing a mapping of all elements with their id

CompostPropertiesMixin

<x-app></x-app>

<script>
  class App extends CompostPropertiesMixin(HTMLElement) {
    static get properties() {
      return {
        siteUsername: {
          type: String,
          value: 'lovelace',
          reflectToAttribute: true,
          observer: 'observeSiteUsername',
        },
      };
    }

    observeUser(oldValue, newValue) {
      console.log(oldValue, newValue);
    }
  }
</script>

Implement a static getter for properties, returning an object with the property name as the key, and the value an object containing:

|Key|Type|Default|Required| |:--:|:--:|:--:|:--:| |type|{String\|Number\|Boolean\|Array\|Object}|String|No| |value|{String\|Number\|Boolean\|Array\|Object\|null}|undefined|No| |reflectToAttribute|{true\|false}|false|No| |observer|{String}|undefined|No|

type

The type of the property. Used when converting a property to an attribute, and vice-versa.

For boolean properties, true is converted to an empty attribute, while false removes the attribute. The presence of an attribute sets the property to true.

For array and object properties, the property is JSON stringified (JSON.stringify) when converting to an attribute, and JSON parsed (JSON.parse) when converting to a property.

value

The default value of the property if the property has not been initialised from an attribute, or the property was not set before the element was added to the DOM. If an attribute with a name matching the property name (converted to kebab-case) is present on the element this will always override the default.

reflectToAttribute

Whether the property should be reflected to an attribute with the same name. Camel cased property names (e.g. siteUsername) are converted to kebab cased attribute names (e.g. site-username) automatically.

observer

If defined, this is the name of a method in your class that will be called when the property changes with arguments containing the previous and new values. Strict equality is used when comparing old and new values, so changes in object sub properties or array elements won't trigger an observer - use of immutable data is advised.

The observer will also be called on initialisation - either from a matching attribute or a default value.

Observer calls are batched and dispatched asynchronously. This means that when the observers are called all properties will have their most recent values - so the order in which the observers are called should not be important.

CompostEventsMixin

<x-app></x-app>

<script>
  class App extends CompostEventsMixin(CompostShadowMixin(HTMLElement)) {
    render() {
      return `
        <button on-click="test">Click me</button>
      `;
    }

    test(event) {
      console.log(this, event);
    }
  }

  customElements.define('x-app', App);
</script>

Any attribute beginning on-{eventName} (where eventName is one of these standard DOM events) will bind that event to the method specified in the attribute value (test in the example above.) The method is automatically bound to the current class, so this in the method will always refer to the class itself.

Event listeners are added in connectedCallback and removed in disconnectedCallback.

In addition the following convenience methods are added:

this.on(el, type, func) is equivalent to el.addEventListener(type, func)

this.off(el, type, func) is equivalent to el.removeEventListener(type, func)

this.fire(type, detail, bubbles = true, composed = true) is equivalent to

this.dispatchEvent(new CustomEvent(type, {
  bubbles,
  composed,
  detail,
}));

CompostRepeatMixin

<x-app></x-app>

<script>
  class App extends CompostRepeatMixin(CompostShadowMixin(HTMLElement)) {
    render() {
      return super.render(`
        <h1>Repeater<h1>
      `);
    }

    getTemplateString(value, index) {
      return `
        <button></button>
      `;
    }

    getKey(value, index) {
      return value;
    }

    updateItem(el, value, index) {
      el.textContent = value;
    }
  }

  customElements.define('x-app', App);

  const app = document.querySelector('x-app');
  app.items = ['one', 'two', 'three'];
</script>

The call to render returns a template string for anything that needs to appear above the repeated template and will be added to the element's shadow DOM. The call to getTemplateString returns a template string that contains the DOM that needs to be repeated and is combined with the items array property to stamp out new elements in the light DOM. So the above will output a custom element with <h1>Repeater</h1> in the shadow DOM, and the following in a slot:

<button>one</button>
<button>two</button>
<button>three</button>

this.getKey(value, index) must return a unique key for each value in items so that items can be efficiently added/removed/reordered when the items array changes.

updateItem(el, value, index) is used to update the repeated element when the value in items[index] changes.

Browser support

Works with no polyfills or build step for browsers that support ES2015, Shadow DOM v1, Custom Elements v1 and HTML Templates. This is currently the latest versions of Chrome and Safari.

Works with other browsers down to IE11 when using the web components polyfills and a transpilation step (e.g. Babel) as needed.

Examples

HackerNew Progressive Web App - built using compost

Coming soon - an example using lit-html.

Coming soon - an example that works on all browsers down to IE11.

License

MIT License © Chris Haynes