@petit-kit/magasin
v0.0.2
Published
A lightweight, reactive state management library with plugin support and automatic dependency tracking.
Downloads
17
Readme
@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/magasinQuick 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 storemagasin.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 valuemagasin.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 storemagasin.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 keysPlugin 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 initPlugin options:
id- Storage key for localStorageautoSave- 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 16Promise 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
