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

piecesjs

v0.2.2

Published

Tiny framework based on native web components.

Downloads

320

Readme

Introduction

piecesjs is a tiny Javascript framework built on the top of native web components with a bunch of tools and utilities.

A Piece is a component. A component is a piece of your page, which can live anywhere in your website, with its own encapsulated styles and interactions.


piecesjs is a simple and lightweight front-end framework that aims to make native web components accessible, with several utilities and tools for website and app development. Like modern frameworks, it dynamically imports the JS and CSS that the page needs, for better optimization. Without being limited to a big headless infrastructure.

Compiled with vitejs.

Main features

  • Dynamic JS & CSS import.
  • Scoped event management.
  • Convenient access to scoped HTMLElements using this.$() or this.domAttr(slug).
  • Seamless communication between active pieces using this.call() or this.emit()
  • Efficient management of common and global CSS imports.
  • A PiecesManager for accessing all active pieces.

Nav

Installation

npm i piecesjs --save

Create your first Piece

With dynamic attributes (reactive)

<c-counter class="c-counter" value="0"></c-counter>
import { Piece } from 'piecesjs';

export class Counter extends Piece {
  constructor() {
    super('Counter', {
      stylesheets: [() => import('/assets/css/components/counter.css')],
    });
  }

  mount() {
    this.$button = this.$('button')[0];
    this.on('click', this.$button, this.click);
  }

  unmount() {
    this.off('click', this.$button[0], this.click);
  }

  render() {
    return `
      <h2>${this.name} component</h2>
      <p>Value: ${this.value}</p>
      <button class="c-button">Increment</button>
    `;
  }

  click() {
    this.value = parseInt(this.value) + 1;
  }

  set value(value) {
    return this.setAttribute('value', value);
  }

  get value() {
    return this.getAttribute('value');
  }

  // Important to automatically call the update function if attribute is changing
  static get observedAttributes() {
    return ['value'];
  }
}

// Register the custom element
customElements.define('c-counter', Counter);

With static content

<c-header class="c-header">
  <h1>Hello world</h1>
</c-header>
import { Piece } from 'piecesjs';

class Header extends Piece {
  constructor() {
    // Set the name of your component and stylesheets directly with the super();
    super('Header', {
      stylesheets: [() => import('/assets/css/components/header.css')],
    });
  }
}
// Register the custom element
customElements.define('c-header', Header);

Register and load dynamically your component

import { load } from 'piecesjs';

load('c-button', () => import('/assets/js/components/Button.js'));

Lifecycle

premount(firstHit = true){}
render(){} // if you want to do a Javascript rendering
mount(firstHit = true){} // firstHit parameter is set to false if the function is called after an update or if its content is changed.
update(){} //Called if an attribute is changed. Then it will call unmount(), premount() and mount().
unmount(update = false){} // update = true if this unmount() is called after an attribute is changed.

Query with this.$

Shortcut to query an element. this.dom(query, context) is also available.

/**
 * @param { String } query
 * @param { HTMLElement } context (this by default)
 */
this.$('button'); // return a NodeList

Get an element with a slug

<ul>
  <li data-dom="listItem">Item 1</li>
  <li data-dom="listItem">Item 2</li>
</ul>
/**
 * @param { String } slug
 * @param { HTMLElement } context (this by default)
 */
this.domAttr('listItem'); // return a NodeList

Events

Register an event listener with this.on()

/*
* Tips: call event listeners in the mount(), register event for an HTMLElement or an array of HTMLElements
* The called func is automatically binded to this
* @param { String } type
* @param { HTMLElement or HTMLElement[] } el
* @param { function } func
* @param { Object } params
*/
mount() {
  this.on('click', this.$button, this.click, {hello: 'world'});

  // You can also use this.on() to add an event listener on global elements
  // this.on('resize', window, this.resize);
}

// if you have set params, the eventObject will be available after
click(params, event) {}

Unregister an event listener with this.off()

/**
 * Tips: remove event listeners in the unmount(), unegister event for an HTMLElement or an array of HTMLElements
 * @param { String } type
 * @param { HTMLElement } el
 * @param { function } func
 */
unmount() {
  this.off('click', this.$button, this.click);
}

Communication between components

this.call()

Call a function of any components, from any components

/**
 * Call function of a component, from a component
 * @param { String } func
 * @param { Object } args
 * @param { String } pieceName
 * @param { String } pieceId
 */
this.call('increment', {}, 'Counter', 'myCounterComponentId');

If no pieceId are specified, all occurrences of the component will be called. A pieceId can be set directly with an attribute cid

<c-button cid="myButtonUId"></c-button>

this.emit() and custom events

You can also emit a custom event with this.emit()

/**
 * Emit a custom event
 * @param { String } eventName
 * @param { HTMLElement } el, by default the event is emit on document
 * @param { Object } params
 */
this.emit('buttonIsMounted', document, { value: 'A Button is mounted!' });

Then, in a Piece you can use this.on(), like the default events.

mount() {
  this.on('buttonIsMounted', document, this.customEventTrigger);
}

// You can get parameters with event.detail
customEventTrigger(event) {
  console.log(event.detail); // { value: 'A Button is mounted! }
}

unmount() {
  this.off('buttonIsMounted', document, this.customEventTrigger);
}

PiecesManager

PiecesManager manage all active components. Get access of all current components visible in the page:

// From anywhere
import { piecesManager } from 'piecesjs';
console.log(piecesManager.currentPieces);

// In a Piece
console.log(this.piecesManager);

class Header extends Piece {
  mount() {
    console.log(this.piecesManager.currentPieces);
  }
}

/*
{
  Counter: {
    c0: {
      name: 'Counter',
      id: 'c0',
      piece: HTMLElement
    },
    myCounterComponentId: {
      name: 'Counter',
      id: 'myCounterComponentId',
      piece: HTMLElement
    }
  }, 
  Button: {
    c2: {
      name: 'Button',
      id: 'c2',
      piece: HTMLElement
    }
  }, 
  Header: {
    c1: {
      name: 'Header',
      id: 'c1',
      piece: HTMLElement
    }
  }
}
*/

Memo

HTML attributes

| Attribute | Description | | --------- | ------------------------------------------------------------------------------------------- | | log | You can log the lifecycle of your Piece with an attribute <c-header log>Hello</c-header> | | cid | To override the generated id of your Piece. Usefull to communicate with this specific Piece |

Piece instance props

| Attribute | Description | | ----------- | ---------------------------------------------------------------- | | this.cid | A generated id of the Piece, override if you set a cid attribute | | this.name | Return the name of the Piece |

Piece instance methods

| Method | Description | Arguments | | -------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | this.$ | Query an HTMLElement | query: String context: HTMLElement, this by default | | this.dom | this.$ clone | query: String context: HTMLElement, this by default | | this.domAttr | Query with a slug. If you have an element like <li> data-dom="mySlug"></li> | slug: String |

Piece events methods

| Method | Description | Arguments | | ----------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | this.on | Event listener for scoped and binded (this) events | type: String (example: mouseenter, resize..)el: HTMLElement or HTMLElement[]func: Functionparams: {} (optional) | | this.off | Remove event listener, the better way is to put it in the unmount(). | type: String (example: mouseenter, resize..)el: HTMLElement or HTMLElement[]func: Function | | this.call | Call of a function of a Piece or a specific Piece based on its cid | func: String, the function nameargs: ObjectpieceName: StringpieceId: String (optional), linked to a cid attribute | | this.emit | Emit a custom event. Can be listened by the other Pieces with a this.on() | eventName: Stringel: HTMLElement, document by default (optional)params: Object (optional) |

You want to collaborate ?

Clone the repo and at the root /

npm i

Link your local piecesjs to use it as an npm package

npm link piecesjs

Build piecesjs

npm run build

Test environment : In the folder /test

npm i
npm run dev

Enjoy and feel free to create a pull request!

Support

If you want to support me, and follow the journey of the creation of pieces 👀

Support me on github