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

storxy

v0.2.3

Published

Tiny simple state manager based on proxies

Downloads

68

Readme

Tiny simple state manager based on proxies. Just 800 bytes* of non-zipped code, but looks like a magic.

* For {store} import only

Inspiration

This state manager provides a store which was inspired by writable store from Svelte and reactive() function from Vue3. Store has $ property, which you can read and write. Whenever you change the value of this property, all subscribers will get updated state value.

Usage

import {store} from 'storxy';

// Create a store with initial state value 'Hello'
const myStore = store('Hello');

// Subscribe for updates
const un = myStore.subscribe( value => console.log('Subscriber:',value));

// Change state value
myStore.$ = myStore.$.toUpperCase();

// Now in console you will see 'Subscriber: HELLO'

// Unsubscribe
un();

Subscriptions

Store's instance provides subscribe method where you should pass a callback-function which will get current store's state value. This function will be called each time state changes. Also there is short alias for this method $$. You may add any number of subscribers.

myStore.subscribe( newStoreValue => console.log(newStoreValue) );

The subscribe method (and $$) returns function which you may call when need to cancel subscription.

When second argument of subscribe method has value true, this will prevent calling callback right on subscription, only when value will change.

myStore.subscribe( newStoreValue => console.log(newStoreValue), true );

Custom stores

By default store is very simple, but you may implement any additional methods to handle business logic in the store:


import {store} from 'storxy';

// Create a store
const myStore = store(0);
myStore.increment = ()=>myStore.$++;
myStore.decrement = ()=>myStore.$--;
...
// Subscribe for updates
myStore.subscribe(value => console.log('Count:',value));

// Use your custom methods
myStore.increment(); // Count: 1
myStore.increment(); // Count: 2
myStore.decrement(); // Count: 1

Don't rewrite subscribe,$$ and $ methods – store will be broken in this case.

First and last subscribers

There a two hooks which will be run when first subscriber will be registered and when all subscribers will be removed. Each hook gets store's instance as a parameter, so you can change its value inside theese functions.

import {store} from 'storxy';

// Create a store with callback in second argument
const myStore = store(0, st =>{

    console.log("I will run before number of subscribers will change from 0 to 1");

    st.$ = 100; // Set store's value to 100

    return st => {
      console.log("I will run after number of subscribers changed from 1 to 0");
    }
});

Computed stores

You can create a computed store which will use a values of other stores and will be updated each time one of these stores updates.

import {store,computed} from 'storxy';

const number1 = store(5);
const number2 = store(10);

const doubleFirst = computed(number1, value => value*2);

const multipleBoth = computed([number1,number2], ([value1,value2])=>{
  return value1*value2;
});

It has same API as a store. So you can subscribe for updates and get current store value from $ property.

Motion store

In this store when you set new value it will not be setted immideatly in the store. Instead store's value will reach target value some specified time and subscribers will be called many times with intermedial values during this period.

In example below, progress element will be animated when you set its new value:

<body>
    <progress value="0" max="100" id="progress_motion"></progress>
    <div>
        <button onclick="setValue(25)">25%</button>
        <button onclick="setValue(50)">50%</button>
        <button onclick="setValue(75)">75%</button>
        <button onclick="setValue(100)">100%</button>
    </div>
</body>

<script src='https://unpkg.com/storxy'></script>
<script>
    const motion = Storxy.motion(0,{duration:1000});

    motion.subscribe( value => {
        document.getElementById('progress_motion').value = value;
    })

    function setValue(value){
        motion.$ = value;
    }
</script>

A motion store may accept options object as a second parameter.

  • duration - time in milliseconds to reach new value.
  • easing - easing function (default is easeInOutCubic). Learn more about easing functions here. You should implement or imort this function, there no any builtin functions except default.
  • interpolation - function like (from,to) => t => value which return intermedial values for any t(0 to 1) parameter. By default motion store can interpolate only numbers ((from,to) => t => from+(to-from)*t) but you can interpolator for any kind of values.

You may set new value for store even when motion in progress. Motion will start from curent intermedial value.

Using with frameworks

Let's create a simple custom store which we can use in any framework:

// stores.js
import {store} from 'storxy';

export const counter = store(0);
counter.increment = () => counter.$++;
counter.decrement = () => counter.$--;

Svelte

Just use as internal Svelte's store or any Observable-like object, to get a value of the store. But set and update store's value using storxy API:

<!-- App.svelte -->
<script>
    import {counter} from './stores.js';
</script>

<h1>Count: {$counter}</h1>

<button on:click={counter.increment}>+</button>
<button on:click={counter.decrement}>-</button>
<button on:click={() => counter.$ = 0}>Reset</button>

See live example here

Malina.js

The Malina framework works smoothly with storxy API:

<!-- App.xht -->
<script>
    import {counter} from './stores.js';
</script>

<h1>Count: {counter.$}</h1>

<button on:click={counter.increment}>+</button>
<button on:click={counter.decrement}>-</button>
<button on:click={() => counter.$ = 0}>Reset</button>

See live example here

Vue

You should manually handle subscription. To change store's value just use store.$.

<template>
  <div>
    <h1>Count: {{ count }}</h1>

    <button @click="increment()">+</button>
    <button @click="decrement()">-</button>

    <button @click="reset()">Reset</button>
  </div>
</template>

<script>
import { counter } from "./stores.js";

export default {
  name: "App",

  data() {
    return {
      count: counter.$,
    }
  },

  created() {
    this.un = counter.$$( $ => this.count = $ );
  },

  beforeDestroy() {
    this.un();
  },

  methods: {
    increment: counter.increment,
    decrement: counter.decrement,
    reset() {
      counter.$ = 0;
    }
  }
}
</script>

See live example here

Also you may use Vue's object watcher with storxy, but in this case component will not subscribe for store changes. This means on-first and on-last hooks will not be called when the component will be rendered.

<template>
  <div>
    <h1>Count: {{ counter.$ }}</h1>

    <button @click="counter.increment()">+</button>
    <button @click="counter.decrement()">-</button>

    <button @click="reset()">Reset</button>
  </div>
</template>

<script>
import { counter } from "./stores.js";

export default {
  name: "App",

  data() {
    return {
      counter
    }
  },

  methods: {
    reset() {
      counter.$ = 0;
    }
  }
}
</script>