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

@rebelstack-io/metaflux

v2.0.2

Published

Library supporting flux pattern without react

Downloads

7

Readme

metaflux logo metaflux

Build Status codecov.io

Simplifying the flux/redux pattern for vanilla (es6) javascript

Metaflux is a lightweight library that provides a store to your application.

Getting Started

Installation:

npm install @rebelstack-io/metaflux

Usage:

Step 1 (Require/Import).

const { Store } = require('@rebelstack-io/metaflux');

Or when import is enabled:

import { Store } from '@rebelstack-io/metaflux';

Or with CDN

<script src="https://cdn.jsdelivr.net/npm/@rebelstack-io/metaflux@2/dist/metaflux.min.js"></script>

Step 2 (Initialize).

const storage = new Store(
	{Counter: 1},
	{INCREMENT: (action, state) => {
		state.Counter = state.Counter + 1;
		return {newState: state};
	}
});

Step 3 (Dispatch actions).

The Store object is also an event emitter, when an action is dispatched an event is emitted.

storage.dispatch({
	type: 'INCREMENT'
});

Step 4 (Listen for changes).

storage.on('INCREMENT', action => {
	// GET THE UPDATED VALUE
	const newValue = storage.getState().Counter;
	// UPDATE DOM.
});

MetaComponents

MetaComponents are WebComponents that support Metaflux's storage.

Usage

import { MetaComponent, Div, H1 } from '@rebelstack-io/metaflux';

class MyComponent extends MetaComponent {
	render () {
		// See Custom Elements
		this.content = Div().Div().H1({}, 'Hello World').baseNode();
		return this.content;
	}
}

window.customElements.define('my-component', MyComponent);

Bind MetaComponents to Metaflux Storage

Althought Storage is an event emitter by itself it is more organize to use Metaflux's handleStoreEvents method to bind itself to the actions dispatched.

import { MetaComponent, Store } from '@rebelstack-io/metaflux';

const storage = new Store(
	{Counter: 1},
	{INCREMENT: (action, state) => {
		state.Counter = state.Counter + 1;
		return {newState: state};
	}
});

class MyComponent extends MetaComponent {
	// Pass storage to MetaComponent parent
	constructor () {
		super(storage);
	}
	render () {
		const content = Div().Button({
				onclick: () => {
					// Dispatch Increment action when button is clicked.
					this.storage.dispatch({type: 'INCREMENT'});
				}
		}, 'Increase').baseNode()
		// Here we get the initial state of Counter and assign it to the counter element.
		this.text = content.Div({}, this.storage.getState().Main.value)
		return content;
	}
	// Handle Metaflux Storage events
	handleStoreEvents () {
		return {
			'INCREMENT': action => {
				// When INCREMENT action is dispatch we update the counter element
				this.text.textContent = this.storage.getState().Counter;
			}
		}
	}
}

window.customElements.define('my-component', MyComponent);

Using MetaComponent inside a MetaContainer

A MetaContainer is a webcomponent with a render method that works like the MetaComponent's render method but instead you're not supposed to bind it to the storage, it doesn't have a handleStoreEvents method in order to avoid that, you can however put MetaComponents inside it.

This object was tought like a not complex element where developers can import stylesheets and organize their layout.

import { MetaContainer } from '@rebelstack-io/metaflux';
import '../components/my-component'; // Here we import our previously defined MetaComponent.

class MyContainer extends MetaContainer {
	render () {
		return `
			<h2>Simple Counter</h2>
			<my-component></my-component>
		`;
	}
}

window.customElements.define('my-container', MyContainer);

The MetaContainer is also a good place to declare global variables like the storage.

Custom Elements

The custom elements are instances of HTMLElement which means that we have all the prototypes such as querySelector or innerText. In addition, we created an easy way to use it as you been doing in vanilla Javascript but with a better element constructor.

Chaining

Every Custom element can be chain with other elements or it self, Notice that it will return the last element in the chain. We can also obtain the parent of the chain using baseNode method

const span = Div().Div().Span(false, 'Hello world');
const base = span.baseNode();
  • the constant span:
<span>Hello world</span>
  • the constant base:
<div>
	<div>
		<span>Hello world</span>
	</div>
</div>

Parameters

All the custom elements recive 2 non-mandatory parameters (props, content).

  • props is an object where you can define basic propperties such as onclick, className, id ... you name it, if exits the property for HTMLElement can be set in that object, also we have custom props as classList which you can pass an array of classes.
  • content can be a String, HTMLElement, Array containing any of the previous, function returnin any of the previous and Object

Examples:

  • props
Div({
	id: 'element',
	classList: ['class-1', 'class-2'],
	onclick: (ev) => {
		// Logic
	},
	...
})
  • content
// as a string
Select(false, `
	<option>option Default</option>
	<option>option 1</option>
	<option>option 2</option>
`);

// as HTMLElement
Select(false, Option(false, 'default'));

// as an array
Select(false, [
	Option({},'option Default'),
	Option({onclick: () => { console.log('option 1') }},'option 1'),
	Option({onclick: () => { console.log('option 2') }},'option 2')
])

// as a function
Select(false, () => {
	return ['1', '2'].map(_n => {
		return Option(
			{ onclick: () => { console.log(`option ${_n}`) } },
			`option ${_n}`
		)
	})
})

Handle Store events

with the custom element there are two ways to listen to store events:

  • onStoreEvent method (notice that all HTMLElement this method in their prototype):
Div()
.Button({attributes: { disabled: '' }}, 'click me')
.onStoreEvenet('LOADING_FINISH', (state, element) => {
	// element is the Button who is listening the event
	element.removeAttribute('disabled')
})
  • events property in the Object content (notice that here you can listen to as many events as you want)
Div({}, {
	content: Div().Div().H1({}, 'Hello world').baseNode(),
	events: {
		'EVENT_NAME': (action, state) => { /* logic */ },
		'OTHER_EVENT': (action, state) => { /* logic */ }
	}
});

More Examples

Form({}, () => (
    [
        Label({}, 'Email'),
        Input({type:'email', placeholder:'example@dom'}),
        Label({}, 'Password'),
        Input({type:'password', placeholder:'Password'}),
        Button({id: 'btn-from'}, 'Login')
    ]
));
<form>
  <label>Email</label>
  <input type="email" placeholder="example@dom">
  <label>Password</label>
  <input type="password" placeholder="Password">
  <button id="btn-from">Login</button>
</form>
A({href: '#metaflux'}, 'Click me');
<a href="#metaflux">Click me</a>

Complete List of elements helpers:

  • 'H1',
  • 'H2',
  • 'H3',
  • 'H4',
  • 'H5',
  • 'H6',
  • 'Div',
  • 'Span',
  • 'Ol',
  • 'Ul',
  • 'Li',
  • 'Table',
  • 'Thead',
  • 'Tbody',
  • 'Tfoot',
  • 'Tr',
  • 'Td',
  • 'Th',
  • 'Form',
  • 'Label',
  • 'Input',
  • 'TextArea',
  • 'Button',
  • 'Img',
  • 'Picture',
  • 'Source',
  • 'Select',
  • 'Option',
  • 'P',
  • 'A',
  • 'Section',
  • 'Video'

Can i create a custom tag with the custom elements?

  • Yes you can, all the custom elements are a child of one central function HTMLElementCreator which receive the tagName and their props, the content of the element if wants to define needs to be as a property of the props parameter:
const myElement = HTMLElementCreator('my-element', {
	content: <'String' | Element() | function () {} | Array()>
})