Piecesjs Save

Front-end framework for a versatile and native web components management.

Project README
piecesjs

[alpha] - [1.1kb] - Tiny framework, using native web components.

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.$().
  • Seamless communication between active components.
  • Efficient management of common and global CSS imports.
  • A PiecesManager for accessing all active components.

Installation

npm i piecesjs --save

Create your first component

With dynamic attributes (reactive)

<c-counter class="c-counter" value="0"></c-counter>
import { default as 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 { default as 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){}
mount(firstHit = true){} // firstHit parameter is available, set to false if the function is called with an update or if its content is changed.
update(){} //Called if an attribute is changed, relaunch: unmount(update = true), premount(firstHit = false), mount(firstHit = false)
unmount(update = false){}

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');

Events

Register an event listener with this.on()

/*
* Tips: call 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, ev) {}

Unregister an event listener with this.off()

/*
* Tips: remove listeners in the unmount(), 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
*/
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
    }
  }
}
*/

Utils

Logs

You can log the lifecycle of your component with an attribute log

<c-header log>Hello</c-header>

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 👀

Subscribe on Polar

Open Source Agenda is not affiliated with "Piecesjs" Project. README Source: piecesjs/piecesjs
Stars
54
Open Issues
0
Last Commit
3 weeks ago
Repository
License
MIT

Open Source Agenda Badge

Open Source Agenda Rating