Skip to content

petit-kit/magasin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@petit-kit/magasin

A lightweight, reactive state management library with plugin support and automatic dependency tracking.

Features

  • 🚀 Lightweight - Minimal footprint with zero external dependencies
  • 🔄 Reactive - Automatic updates when state changes
  • 🔌 Plugin System - Extensible with custom plugins
  • 📦 Persistence - Built-in localStorage plugin
  • 🎯 Dependency Tracking - Automatic updates based on dependencies
  • 🎨 TypeScript - Full TypeScript support
  • 🌐 Universal - Works in browser and Node.js environments

Installation

npm install @petit-kit/magasin

Quick Start

import magasin from '@petit-kit/magasin';

// Set a value
magasin.set('user', { name: 'John', age: 30 });

// Get a value
const user = magasin.get('user');

// Subscribe to changes
const unsubscribe = magasin.subscribe('user', (user) => {
  console.log('User updated:', user);
});

// Create a reactive reference
const userRef = magasin.ref('user');
userRef.set({ name: 'Jane', age: 25 });

API Reference

Core Methods

magasin.set(key, value, deps?)

Sets a value in the store. Supports functions, promises, and dependency tracking.

// Simple value
magasin.set('count', 42);

// Function value
magasin.set('doubleCount', (current) => current * 2);

// With dependencies
magasin.set('fullName', (current) => `${firstName} ${lastName}`, ['firstName', 'lastName']);

// Promise support
magasin.set('userData', fetch('/api/user').then(r => r.json()));

magasin.get(key)

Retrieves a value from the store.

const value = magasin.get('count');
const allStore = magasin.get(); // Returns entire store

magasin.ref(key)

Creates a reactive reference object with get, set, and subscribe methods.

const countRef = magasin.ref('count');

// Get current value
const current = countRef.get();

// Set new value
countRef.set(100);

// Subscribe to changes
const unsubscribe = countRef.subscribe((value) => {
  console.log('Count changed:', value);
});

magasin.subscribe(key, callback, broadcast?)

Subscribes to changes for a specific key.

const unsubscribe = magasin.subscribe('user', (user) => {
  console.log('User changed:', user);
}, true); // broadcast = true (default) calls callback immediately with current value

magasin.default(key, value)

Sets a default value that will be used when the key doesn't exist.

magasin.default('theme', 'dark');
magasin.default('language', 'en');

magasin.clear(key?)

Clears specific key or entire store.

magasin.clear('user'); // Clear specific key
magasin.clear(); // Clear entire store

magasin.reset()

Resets the store to default values.

magasin.reset();

magasin.broadcast(key?)

Manually triggers subscriptions for a key or all keys.

magasin.broadcast('user'); // Broadcast specific key
magasin.broadcast(); // Broadcast all keys

Plugin System

Magasin supports plugins for extending functionality. Plugins are initialized when creating a new Magasin instance.

import { Magasin } from '@petit-kit/magasin';
import localStoragePlugin from '@petit-kit/magasin/localStorage';

const store = new Magasin({
  id: 'my-app',
  plugins: [localStoragePlugin]
});

Built-in Plugins

localStorage Plugin

Automatically persists store data to localStorage.

import { Magasin, localStorage } from '@petit-kit/magasin';

const store = new Magasin({
  id: 'my-app',
  plugins: [localStorage]
});

// Data is automatically saved to localStorage
store.set('user', { name: 'John' });

// Data is automatically loaded from localStorage on init

Plugin options:

  • id - Storage key for localStorage
  • autoSave - Automatically save on every set (default: true)

Advanced Usage

Dependency Tracking

Magasin automatically tracks dependencies and updates computed values when dependencies change.

// Set base values
magasin.set('firstName', 'John');
magasin.set('lastName', 'Doe');

// Set computed value with dependencies
magasin.set('fullName', (current) => {
  const firstName = magasin.get('firstName');
  const lastName = magasin.get('lastName');
  return `${firstName} ${lastName}`;
}, ['firstName', 'lastName']);

// When firstName changes, fullName automatically updates
magasin.set('firstName', 'Jane');
// fullName is now "Jane Doe"

Function Values

You can use functions as values, which will be executed with the current value.

magasin.set('count', 5);
magasin.set('doubleCount', (current) => current * 2);
// doubleCount is now 10

magasin.set('count', 8);
// doubleCount automatically becomes 16

Promise Support

Magasin handles promises automatically.

magasin.set('userData', fetch('/api/user').then(r => r.json()));

// Subscribe to get the resolved value
magasin.subscribe('userData', (data) => {
  console.log('User data loaded:', data);
});

Custom Plugins

Create custom plugins by implementing the plugin interface.

const customPlugin = (magasin, settings) => {
  return {
    init: () => {
      // Initialize plugin
      console.log('Plugin initialized');
    },
    set: (key, value) => {
      // Called when a value is set
      console.log(`Setting ${key}:`, value);
    },
    clear: () => {
      // Called when store is cleared
      console.log('Store cleared');
    },
    reset: () => {
      // Called when store is reset
      console.log('Store reset');
    }
  };
};

const store = new Magasin({
  plugins: [customPlugin]
});

Examples

Todo App

import magasin from '@petit-kit/magasin';

// Initialize with defaults
magasin.default('todos', []);
magasin.default('filter', 'all');

// Add todo
magasin.set('todos', (current) => [
  ...current,
  { id: Date.now(), text: 'New todo', completed: false }
]);

// Toggle todo
magasin.set('todos', (current) =>
  current.map(todo =>
    todo.id === id ? { ...todo, completed: !todo.completed } : todo
  )
);

// Computed filtered todos
magasin.set('filteredTodos', (current) => {
  const todos = magasin.get('todos');
  const filter = magasin.get('filter');
  
  switch (filter) {
    case 'completed':
      return todos.filter(todo => todo.completed);
    case 'active':
      return todos.filter(todo => !todo.completed);
    default:
      return todos;
  }
}, ['todos', 'filter']);

// Subscribe to changes
magasin.subscribe('filteredTodos', (todos) => {
  renderTodos(todos);
});

Form State Management

import magasin from '@petit-kit/magasin';

// Form fields
magasin.set('form.email', '');
magasin.set('form.password', '');
magasin.set('form.confirmPassword', '');

// Validation
magasin.set('form.isValid', (current) => {
  const email = magasin.get('form.email');
  const password = magasin.get('form.password');
  const confirmPassword = magasin.get('form.confirmPassword');
  
  return email.includes('@') && 
         password.length >= 8 && 
         password === confirmPassword;
}, ['form.email', 'form.password', 'form.confirmPassword']);

// Subscribe to validation changes
magasin.subscribe('form.isValid', (isValid) => {
  submitButton.disabled = !isValid;
});

License

MIT © @petitssoldats

About

A lightweight, reactive state management library with plugin support and automatic dependency tracking.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors