### Nanostores Immer Complete Example Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Demonstrates the full lifecycle of a nanostores-immer store, from creation and subscription to direct updates and Immer mutations. Use this as a guide for integrating nanostores-immer into your application. ```typescript import { atom } from '@illuxiza/nanostores-immer' // Create store const $app = atom({ user: { id: 1, name: 'John' }, loading: false, items: [] }) // Get current value const current = $app.get() // Subscribe (with immediate call) const unsubscribe1 = $app.subscribe((value, oldValue) => { console.log('State changed:', { from: oldValue, to: value }) }) // Listen (without immediate call) const unsubscribe2 = $app.listen((value, oldValue) => { console.log('Update:', { from: oldValue, to: value }) }) // Direct set $app.set({ user: { id: 2, name: 'Jane' }, loading: false, items: [] }) // Immer mutations $app.mut(draft => { draft.loading = true }) // Manual notification $app.notify({ loading: false }) // Check listener count console.log($app.lc) // 2 (two active listeners) // Remove listeners unsubscribe1() unsubscribe2() console.log($app.lc) // 0 // Off removes all listeners const unsubscribe3 = $app.subscribe(() => {}) $app.off() console.log($app.lc) // 0 // Value property console.log($app.value) // Current value object ``` -------------------------------- ### Install Nanostores Immer Package Source: https://github.com/illuxiza/nanostores-immer/blob/main/README.md Command to install the @illuxiza/nanostores-immer package using npm. ```sh npm install @illuxiza/nanostores-immer ``` -------------------------------- ### Store Creation and Basic Operations Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Demonstrates how to create a store, get its current value, and subscribe to changes. It also shows direct state setting. ```APIDOC ## Store Creation and Basic Operations ### Description This section covers the initialization of a store and fundamental operations like retrieving the current state and subscribing to state updates. ### Methods - **`atom(initialState)`**: Creates a new store with the provided initial state. - **`store.get()`**: Returns the current value of the store. - **`store.subscribe(callback, runImmediately)`**: Subscribes a callback function to state changes. If `runImmediately` is true (or omitted), the callback is invoked immediately with the current state. - **`store.listen(callback, runImmediately)`**: Similar to `subscribe`, but the callback is not invoked immediately by default. It's invoked only on subsequent state changes. - **`store.set(newState)`**: Replaces the entire state of the store with `newState`. ### Example Usage ```typescript import { atom } from '@illuxiza/nanostores-immer'; // Create store const $app = atom({ user: { id: 1, name: 'John' }, loading: false, items: [] }); // Get current value const current = $app.get(); // Subscribe (with immediate call) const unsubscribe1 = $app.subscribe((value, oldValue) => { console.log('State changed:', { from: oldValue, to: value }); }); // Listen (without immediate call) const unsubscribe2 = $app.listen((value, oldValue) => { console.log('Update:', { from: oldValue, to: value }); }); // Direct set $app.set({ user: { id: 2, name: 'Jane' }, loading: false, items: [] }); ``` ``` -------------------------------- ### Create a Basic Store Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Use the `atom` function to create a new store with an initial value. This example shows creating a counter store. ```typescript import { atom } from '@illuxiza/nanostores-immer' const $counter = atom({ count: 0 }) ``` -------------------------------- ### get() Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Retrieve the current store value. ```APIDOC ## get() ### Description Retrieve the current store value. ### Method ```typescript get(): Value ``` ### Returns The current store value, guaranteed to be initialized. ### Example ```typescript const $store = atom({ count: 0 }) const value = $store.get() // { count: 0 } ``` ``` -------------------------------- ### Quick Start: Initialize and Update Store Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Demonstrates how to initialize a nanostore with Immer integration and perform updates using both direct immutable syntax and mutable Immer syntax. Includes subscribing to store changes. ```typescript import { atom } from '@illuxiza/nanostores-immer' const $store = atom({ count: 0, items: [] }) // Update with immutable syntax (direct set) $store.set({ count: 1, items: [] }) // Update with mutable syntax (Immer) $store.mut(draft => { draft.count++ draft.items.push({ id: 1 }) }) // Subscribe to changes $store.subscribe(value => { console.log('Store:', value) }) ``` -------------------------------- ### Complete Atom Example Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Demonstrates creating an atom store with an initial value, retrieving its current state, subscribing to changes with immediate and delayed notifications, and performing direct and mutable updates using Immer. ```typescript import { atom } from '@illuxiza/nanostores-immer' // Create a store with initial value const $user = atom({ id: 1, name: 'John', settings: { theme: 'light', notifications: true } }) // Get current value console.log($user.get()) // { id: 1, name: 'John', settings: { theme: 'light', notifications: true } } // Subscribe to changes (immediate call + future changes) const unsubscribe1 = $user.subscribe((user, oldUser) => { console.log('User changed:', user) }) // Listen for changes only (no immediate call) const unsubscribe2 = $user.listen((user, oldUser) => { console.log('User was:', oldUser, 'Now is:', user) }) // Direct set $user.set({ id: 2, name: 'Jane', settings: { theme: 'dark', notifications: false } }) // Immer mutable updates $user.mut(draft => { draft.name = 'Jane Doe' draft.settings.theme = 'light' }) unsubscribe1() unsubscribe2() ``` -------------------------------- ### Complete Type Example Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/types.md Illustrates creating stores with initial values, inferring types, and performing type-safe mutations. Also shows creating stores without initial values and handling optional types. ```typescript import { atom, WritableAtom, ReadableAtom, PreinitializedWritableAtom } from '@illuxiza/nanostores-immer' // Create a store with an initial value // Type is PreinitializedWritableAtom const $user = atom({ id: 1, name: 'John' }) // $user.value has type: { id: number; name: string } // (guaranteed to be initialized because of PreinitializedWritableAtom) // Type-safe store operations $user.mut(draft => { draft.name = 'Jane' // OK draft.id = 2 // OK }) // Listener values are readonly const unsubscribe = $user.subscribe((value) => { // value has type: Readonly<{ id: number; name: string }> console.log(value.name) // OK // value.name = 'Bob' // ERROR: Cannot assign to readonly property }) // Create a store without initial value const $optional = atom() // Type is PreinitializedWritableAtom // $optional.value has type: string | undefined $optional.set('hello') $optional.set(undefined) ``` -------------------------------- ### React Integration Example Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt Demonstrates how to use nanostores with React components. The `useStore` hook (assumed to be provided by a related library or custom implementation) allows components to reactively subscribe to store updates. ```typescript import React from 'react'; import { useStore } from './useStore'; // Assuming a custom hook import { count } from './stores'; // Assuming count store is exported function CounterDisplay() { const currentCount = useStore(count); return (
Current Count: {currentCount}
); } ``` -------------------------------- ### Basic Example Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/readonlytype.md Demonstrates how to use readonlyType to export an internal writable store as a read-only store, preventing mutation attempts in consumer code. ```APIDOC ## Basic Example ```typescript import { atom, readonlyType } from '@illuxiza/nanostores-immer' // Internal writable store const $counterPrivate = atom({ count: 0 }) // Export as read-only export const $counter = readonlyType($counterPrivate) // In consumer code: // const value = $counter.get() // OK // const unsubscribe = $counter.subscribe(v => {}) // OK // $counter.set({ count: 1 }) // ERROR: Property 'set' does not exist on type 'ReadableAtom<...>' // $counter.mut(d => {}) // ERROR: Property 'mut' does not exist on type 'ReadableAtom<...>' ``` ``` -------------------------------- ### Atom Methods Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Provides methods for getting, subscribing to, and updating the Atom store's state. ```APIDOC ## Atom Methods ### get() Retrieves the current value of the Atom store. #### Returns - `Value`: The current value stored in the Atom. ### subscribe(callback: (value: Value, oldValue: Value) => void) Subscribes a callback function to changes in the Atom's value. The callback is invoked immediately with the current value and then again whenever the value changes. #### Parameters - **callback** (`(value: Value, oldValue: Value) => void`) - Required - The function to call when the value changes. #### Returns - `() => void`: A function to unsubscribe the callback. ### listen(callback: (value: Value, oldValue: Value) => void) Subscribes a callback function to changes in the Atom's value. The callback is invoked only when the value changes, not immediately. #### Parameters - **callback** (`(value: Value, oldValue: Value) => void`) - Required - The function to call when the value changes. #### Returns - `() => void`: A function to unsubscribe the callback. ### set(value: Value) Sets the Atom's value to a new value. This will trigger subscriptions. #### Parameters - **value** (`Value`) - Required - The new value to set. ### mut(callback: (draft: Draft) => void) Performs a mutable update on the Atom's value using Immer. The callback receives a draft of the current value, which can be mutated directly. #### Parameters - **callback** (`(draft: Draft) => void`) - Required - A function that mutates the draft value. ``` -------------------------------- ### get() Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Retrieves the current value of the store. This method is synchronous and always returns an initialized value without triggering any callbacks or listeners. ```APIDOC ## get() ### Description Get the current store value. This method is guaranteed to return an initialized value. ### Method `get(): Value` ### Returns The current store value. ### Behavior - Always returns initialized value (never lazy) - Does not trigger `onMount` callback - Does not call listeners - Thread-safe and synchronous ### Example ```typescript const $store = atom({ count: 0 }) const value = $store.get() console.log(value.count) // 0 ``` ``` -------------------------------- ### Get Store Value Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Use `get()` to retrieve the current value of a store. This method is synchronous and always returns an initialized value without triggering mount callbacks or listeners. ```typescript const $store = atom({ count: 0 }) const value = $store.get() console.log(value.count) // 0 ``` -------------------------------- ### Manage Form State with Validation Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/examples.md This example demonstrates managing complex form state, including fields, submission status, and errors, using `atom.mut` for updates. It includes form validation logic. ```typescript import { atom } from '@illuxiza/nanostores-immer' interface FormField { value: string error: string | null touched: boolean } interface FormState { fields: Record isSubmitting: boolean submitError: string | null } const $form = atom({ fields: { email: { value: '', error: null, touched: false }, password: { value: '', error: null, touched: false } }, isSubmitting: false, submitError: null }) function setFieldValue(name: string, value: string) { $form.mut(draft => { if (draft.fields[name]) { draft.fields[name].value = value } }) } function setFieldTouched(name: string) { $form.mut(draft => { if (draft.fields[name]) { draft.fields[name].touched = true } }) } function setFieldError(name: string, error: string | null) { $form.mut(draft => { if (draft.fields[name]) { draft.fields[name].error = error } }) } function validateForm(): boolean { const form = $form.get() const errors: Record = {} if (!form.fields.email.value) { errors.email = 'Email is required' } if (!form.fields.password.value) { errors.password = 'Password is required' } $form.mut(draft => { for (const [name, error] of Object.entries(errors)) { if (draft.fields[name]) { draft.fields[name].error = error } } }) return Object.keys(errors).length === 0 } async function submitForm() { if (!validateForm()) return $form.mut(draft => { draft.isSubmitting = true draft.submitError = null }) try { const form = $form.get() const data = Object.entries(form.fields).reduce((acc, [name, field]) => { acc[name] = field.value return acc }, {} as Record) await fetch('/api/submit', { method: 'POST', body: JSON.stringify(data) }) $form.mut(draft => { draft.isSubmitting = false }) } catch (error) { $form.mut(draft => { draft.isSubmitting = false draft.submitError = error instanceof Error ? error.message : 'Submit failed' }) } } // Usage setFieldValue('email', 'john@example.com') setFieldTouched('email') setFieldValue('password', 'secret123') setFieldTouched('password') await submitForm() ``` -------------------------------- ### Store Value Access Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Provides access to the raw store value. Use `get()` for guaranteed initialization, especially with optional stores. ```APIDOC ## Property: value ### Description Low-level property containing the raw store value. It may be undefined before the first listener is attached. For stores initialized with `atom(initialValue)`, it is of type `PreinitializedWritableAtom` and holds `Value`. It is recommended to use `get()` instead of direct `value` access for guaranteed initialization. This property is useful in framework integration code. ### Characteristics - May be undefined before first listener attachment. - For stores created with `atom(initialValue)`, the type is `PreinitializedWritableAtom` with `value: Value`. - Use `get()` instead of direct `value` access for guaranteed initialization. - Useful in framework integration code. ### Example: ```typescript const $store = atom({ count: 0 }) console.log($store.value) // { count: 0 } console.log($store.get()) // { count: 0 } // For optional stores const $optional = atom() console.log($optional.value) // undefined (before listeners) console.log($optional.get()) // undefined (guaranteed) ``` ``` -------------------------------- ### React Todo List with Immer Updates Source: https://github.com/illuxiza/nanostores-immer/blob/main/README.md Example of integrating Nanostores Immer with React to manage and update a list of todos. The `toggleTodo` function uses `.mut()` for immutable updates. ```tsx import { useStore } from '@nanostores/react' import { atom } from '@illuxiza/nanostores-immer' const $todos = atom([ { id: 1, text: 'Buy milk', done: false } ]) export const TodoList = () => { const todos = useStore($todos) const toggleTodo = (id: number) => { $todos.mut(draft => { const todo = draft.find(t => t.id === id) if (todo) todo.done = !todo.done }) } return (
    {todos.map(todo => (
  • toggleTodo(todo.id)}> {todo.text} {todo.done ? '✓' : ''}
  • ))}
) } ``` -------------------------------- ### atom() Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Creates an immutable store with Immer integration. The store provides methods to get, set, listen, and mutate state using Immer's mutable syntax. ```APIDOC ## atom() ### Description Creates an immutable store with Immer integration. The store provides methods to get, set, listen, and mutate state using Immer's mutable syntax. ### Function Signature ```typescript function atom( ...args: undefined extends Value ? [] | [Value] : [Value] ): PreinitializedWritableAtom & StoreExt ``` ### Parameters #### Path Parameters - **initialValue** (Value) - Optional - The initial value of the store. If omitted, the store initializes to `undefined`. ### Return Type Returns a `PreinitializedWritableAtom`, which is a `WritableAtom` with the `value` property guaranteed to be initialized. The store object extends `ReadableAtom` and `WritableAtom` interfaces. ``` -------------------------------- ### Complex Nested Store Management with Nanostores Immer Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/examples.md This snippet defines a complex application state interface and demonstrates how to use nanostores-immer's `atom` and `mut` functions to perform deep nested mutations on the state. It includes examples for updating user profiles, theme preferences, loading status, and clearing errors. ```typescript import { atom } from '@illuxiza/nanostores-immer' interface User { id: number email: string profile: { firstName: string lastName: string avatar: string } } interface AppState { currentUser: User | null isLoading: boolean error: string | null preferences: { theme: 'light' | 'dark' notifications: boolean language: string } } const initialState: AppState = { currentUser: null, isLoading: false, error: null, preferences: { theme: 'light', notifications: true, language: 'en' } } const $app = atom(initialState) // Deep nested mutations function updateUserProfile(firstName: string, lastName: string) { $app.mut(draft => { if (draft.currentUser) { draft.currentUser.profile.firstName = firstName draft.currentUser.profile.lastName = lastName } }) } function setTheme(theme: 'light' | 'dark') { $app.mut(draft => { draft.preferences.theme = theme }) } function setLoading(loading: boolean) { $app.mut(draft => { draft.isLoading = loading }) } function setUser(user: User) { $app.mut(draft => { draft.currentUser = user draft.error = null }) } function clearError() { $app.mut(draft => { draft.error = null }) } // Usage setLoading(true) setUser({ id: 1, email: 'john@example.com', profile: { firstName: 'John', lastName: 'Doe', avatar: 'https://...' } }) updateUserProfile('Jane', 'Smith') setTheme('dark') ``` -------------------------------- ### ReadonlyIfObject Type Examples Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/types.md Illustrates the behavior of the ReadonlyIfObject conditional type with different input types, including objects, primitives, functions, and undefined. ```typescript type T1 = ReadonlyIfObject<{ name: string }> // Readonly<{ name: string }> type T2 = ReadonlyIfObject // number type T3 = ReadonlyIfObject<() => void> // () => void type T4 = ReadonlyIfObject // undefined ``` -------------------------------- ### Advanced Example with Type Narrowing Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/readonlytype.md Illustrates a more advanced use case where readonlyType is used to enforce read-only access to a complex object store, while internal functions maintain write capabilities. ```APIDOC ## Advanced Example ```typescript import { atom, readonlyType } from '@illuxiza/nanostores-immer' // Define store types interface User { id: number name: string email: string } // Create internal mutable store const $userPrivate = atom({ id: 1, name: 'John', email: 'john@example.com' }) // Export as read-only export const $user = readonlyType($userPrivate) // Only internal code can modify function updateUser(user: User) { $userPrivate.set(user) } function updateUserName(name: string) { $userPrivate.mut(draft => { draft.name = name }) } // Consumer code can only read export function useUser() { const user = $user.get() return user } ``` ``` -------------------------------- ### TypeScript Type Safety with Immer Updates Source: https://github.com/illuxiza/nanostores-immer/blob/main/README.md Illustrates how TypeScript provides type safety when updating state with Immer. The example shows a correct type update and an incorrect one that would result in a type error. ```typescript interface User { id: number name: string settings: { theme: 'light' | 'dark' notifications: boolean } } const $user = atom({ id: 1, name: 'John', settings: { theme: 'light', notifications: true } }) // TypeScript will ensure type safety $user.mut(draft => { draft.settings.theme = 'dark' // ✓ OK draft.settings.theme = 'blue' // ✗ Type Error }) ``` -------------------------------- ### Accessing Raw Store Value Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Use the `value` property for low-level access to the store's raw data. Be aware it might be undefined before listeners are attached. For guaranteed initialization, prefer the `get()` method. ```typescript const $store = atom({ count: 0 }) console.log($store.value) // { count: 0 } console.log($store.get()) // { count: 0 } // For optional stores const $optional = atom() console.log($optional.value) // undefined (before listeners) console.log($optional.get()) // undefined (guaranteed) ``` -------------------------------- ### Get Store Value Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt Access the current value of a store using the `get()` method. This method is available on both writable and readonly stores. ```typescript const currentValue = count.get(); ``` -------------------------------- ### Basic Counter Store with nanostores-immer Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/examples.md Illustrates how to create a simple counter store and perform direct updates using the `mut` method. It also shows how to subscribe to store changes. ```typescript import { atom } from '@illuxiza/nanostores-immer' const $counter = atom({ count: 0 }) // Direct updates function increment() { $counter.mut(draft => draft.count++) } function decrement() { $counter.mut(draft => draft.count--) } function reset() { $counter.set({ count: 0 }) } // Observe changes $counter.subscribe(value => { console.log('Counter:', value.count) }) increment() // Counter: 1 increment() // Counter: 2 decrement() // Counter: 1 reset() // Counter: 0 ``` -------------------------------- ### Basic Store Creation and Update Source: https://github.com/illuxiza/nanostores-immer/blob/main/README.md Shows how to create a basic store and update its state using the `.mut()` method for Immer-based updates, alongside regular `.set()` updates. ```typescript import { atom } from '@illuxiza/nanostores-immer' const $store = atom({ count: 0 }) // Update state with Immer $store.mut(draft => { draft.count++ }) // Regular updates still work $store.set({ count: 2 }) ``` -------------------------------- ### Todo List Store with nanostores-immer Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/examples.md Demonstrates managing a list of todos with add, toggle, remove, and clear operations using `mut`. It also shows how to listen for changes in the todo list. ```typescript import { atom } from '@illuxiza/nanostores-immer' interface Todo { id: number text: string completed: boolean } const $todos = atom([]) function addTodo(text: string) { $todos.mut(draft => { const id = Math.max(...draft.map(t => t.id), 0) + 1 draft.push({ id, text, completed: false }) }) } function toggleTodo(id: number) { $todos.mut(draft => { const todo = draft.find(t => t.id === id) if (todo) { todo.completed = !todo.completed } }) } function removeTodo(id: number) { $todos.mut(draft => { const index = draft.findIndex(t => t.id === id) if (index > -1) { draft.splice(index, 1) } }) } function clearCompleted() { $todos.mut(draft => { draft.length = 0 // Alternatively: return draft.filter(t => !t.completed) // But with Immer, modify in place }) } // Usage addTodo('Buy milk') addTodo('Learn TypeScript') toggleTodo(1) removeTodo(2) $todos.listen((todos, oldTodos) => { console.log('Todos changed:', todos) }) ``` -------------------------------- ### Create and Update Store with Immer Source: https://github.com/illuxiza/nanostores-immer/blob/main/README.md Demonstrates creating a Nanostores atom and updating its state immutably using Immer's mutable syntax via the `.mut()` method. ```typescript import { atom } from '@illuxiza/nanostores-immer' // Create a store const $users = atom ({ admins: [ { id: 1, name: 'John' } ], users: [ { id: 2, name: 'Jane' } ] }) // Update with Immer's mutable syntax $users.mut(draft => { draft.admins.push({ id: 3, name: 'Bob' }) draft.users[0].name = 'Jane Doe' }) ``` -------------------------------- ### Nanostores Immer File Structure Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Illustrates the directory and file organization of the nanostores-immer package. This structure helps in understanding the location of core implementations, type definitions, tests, and package metadata. ```bash nanostores-immer/ ├── atom/ │ ├── index.js # Implementation │ ├── index.d.ts # Types │ ├── index.test.ts # Tests │ └── errors.ts # Type checking examples ├── index.js # Main entry point ├── index.d.ts # Main types ├── package.json # Package metadata └── README.md # Usage guide ``` -------------------------------- ### Nanostores Immer Listener Patterns Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/examples.md Demonstrates five patterns for subscribing to and listening for state changes in nanostores-immer. Includes basic subscription, change detection, derived state watching, side effects, and debounced updates. Use these patterns to manage state reactivity and side effects effectively. ```typescript import { atom } from '@illuxiza/nanostores-immer' const $store = atom({ count: 0, label: 'counter' }) // Pattern 1: Subscribe for all state changes const unsub1 = $store.subscribe((value) => { console.log('State:', value) }) // Pattern 2: Listen for change detection const unsub2 = $store.listen((value, oldValue) => { console.log(`Changed from`, oldValue, `to`, value) }) // Pattern 3: Watch specific value with derived state let previousCount = $store.get().count const unsub3 = $store.listen(value => { if (value.count !== previousCount) { console.log(`Count changed: ${previousCount} → ${value.count}`) previousCount = value.count } }) // Pattern 4: React to changes with side effects const unsub4 = $store.subscribe(value => { // Persist to localStorage localStorage.setItem('store', JSON.stringify(value)) }) // Pattern 5: Debounced updates let timeout: NodeJS.Timeout | null = null const unsub5 = $store.listen(() => { if (timeout) clearTimeout(timeout) timeout = setTimeout(() => { console.log('Store stabilized:', $store.get()) }, 500) }) // Usage $store.mut(draft => draft.count++) $store.mut(draft => draft.count++) $store.set({ count: 0, label: 'reset' }) // Cleanup unsub1() unsub2() unsub3() unsub4() unsub5() ``` -------------------------------- ### Getting Listener Count Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md The `lc` property provides a read-only count of active listeners, including those from `listen()`, `subscribe()`, and `onMount` hooks. It's useful for debugging and advanced patterns. ```typescript const $store = atom({ count: 0 }) console.log($store.lc) // 0 const unsubscribe = $store.subscribe(() => {}) console.log($store.lc) // 1 unsubscribe() console.log($store.lc) // 0 ``` -------------------------------- ### Entry Point Export Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Shows the main export from the nanostores-immer package, which is the enhanced `atom` function. ```typescript export { atom } from './atom/index.js' ``` -------------------------------- ### ReadableAtom Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/types.md Represents a store object that offers read-only access to its value and allows for subscribing to changes. It provides methods to get the current value, subscribe to updates, and manage listeners. ```APIDOC ## ReadableAtom ### Description A store object that provides read-only access to a value and change notifications. ### Fields - **value** (`undefined | Value`) - Required (readonly) - The current store value; may be undefined if not initialized. - **lc** (`number`) - Required (readonly) - The count of active listeners. ### Methods - **`get()`** - Returns the store value (always initialized even without listeners). - **`subscribe(listener)`** - Subscribe with immediate call and future notifications. Returns unsubscribe function. - **`listen(listener)`** - Subscribe without immediate call. Returns unsubscribe function. - **`notify(oldValue?)`** - Manually trigger listener notifications. - **`off()`** - Remove all listeners from the store. ### Used By - `atom()` returns `PreinitializedWritableAtom` which extends `WritableAtom` which extends `ReadableAtom` - All listener callbacks receive values as `ReadonlyIfObject` ``` -------------------------------- ### listen(listener) Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Subscribe to store changes without calling the listener immediately. ```APIDOC ## listen(listener) ### Description Subscribe to store changes without calling the listener immediately. ### Method ```typescript listen( listener: ( value: ReadonlyIfObject, oldValue: ReadonlyIfObject ) => void ): () => void ``` ### Parameters #### Path Parameters - **listener** (function) - Required - Callback invoked only on state changes (not on subscription). Receives the new value and previous value. ### Returns An unsubscribe function that removes the listener. ### Example ```typescript const $store = atom({ count: 0 }) const unsubscribe = $store.listen((value, oldValue) => { console.log('Changed from', oldValue, 'to', value) }) $store.set({ count: 1 }) // Logs: Changed from { count: 0 } to { count: 1 } unsubscribe() ``` ``` -------------------------------- ### ReadableAtom Interface Definition Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/types.md Defines the structure of a read-only atom store, including methods for getting values, subscribing to changes, and managing listeners. Use this interface to understand the contract for read-only stores. ```typescript interface ReadableAtom { get(): Value readonly lc: number listen( listener: ( value: ReadonlyIfObject, oldValue: ReadonlyIfObject ) => void ): () => void notify(oldValue?: ReadonlyIfObject): void off(): void subscribe( listener: ( value: ReadonlyIfObject, oldValue?: ReadonlyIfObject ) => void ): () => void readonly value: undefined | Value } ``` -------------------------------- ### Package.json Exports Configuration Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Illustrates the export map configuration in the package.json file, defining how the package's modules are exposed. ```json { ".": "./index.js", "./package.json": "./package.json" } ``` -------------------------------- ### Store Methods Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/INDEX.md Provides a collection of methods that can be called on any nanostores store instance to interact with its state and listeners. ```APIDOC ## Store Methods ### get() #### Description Get the current value of the store. #### Method `get(): Value` ### set(value) #### Description Directly assign a new value to the store. This method is available on writable stores. #### Method `set(value: Value): void` #### Parameters - **value** (Value) - Required - The new value to set for the store. ### mut(mutater) #### Description Update the store's value using an Immer mutater function. This allows for efficient and safe immutable updates. #### Method `mut(mutater: (draft: Draft) => void): void` #### Parameters - **mutater** (function) - Required - A function that takes the mutable draft of the store's value and performs modifications. ### subscribe(listener) #### Description Subscribe a listener function to store changes. The listener is called immediately with the current value upon subscription, and then again whenever the store's value changes. #### Method `subscribe(listener: (value: Value) => void): () => void` #### Parameters - **listener** (function) - Required - The callback function to execute when the store value changes. #### Returns A function to unsubscribe the listener. ### listen(listener) #### Description Subscribe a listener function to store changes. The listener is called only when the store's value changes, not immediately upon subscription. #### Method `listen(listener: (value: Value) => void): () => void` #### Parameters - **listener** (function) - Required - The callback function to execute when the store value changes. #### Returns A function to unsubscribe the listener. ### notify(oldValue) #### Description Manually trigger notifications for all subscribed listeners. This can be useful after performing complex state updates outside of the standard `set` or `mut` methods. #### Method `notify(oldValue: Value): void` #### Parameters - **oldValue** (Value) - Required - The value of the store before the manual notification. ### off() #### Description Remove all listeners subscribed to this store. This effectively unsubscribes all callbacks previously registered with `subscribe` or `listen`. #### Method `off(): void` ``` -------------------------------- ### Listen to Store Changes (Alternative) Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt The `listen()` method provides an alternative way to subscribe to store changes. It also returns an unsubscribe function. The primary difference from `subscribe` is often in how it's intended to be used within specific frameworks or patterns, though functionally they both provide change notifications. ```typescript const unsubscribe = count.listen((newValue) => { console.log('Count updated to:', newValue); }); // To stop listening: unsubscribe(); ``` -------------------------------- ### Store Signatures Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/INDEX.md Reference for common nanostores methods. These signatures are fully documented in types.md and api-reference/store-methods.md. ```javascript atom(value) → PreinitializedWritableAtom ``` ```javascript readonlyType(store) → ReadableAtom ``` ```javascript store.get() → Value ``` ```javascript store.set(value) → void ``` ```javascript store.mut(mutater) → void ``` ```javascript store.subscribe(listener) → () => void ``` ```javascript store.listen(listener) → () => void ``` ```javascript store.notify(oldValue?) → void ``` ```javascript store.off() → void ``` -------------------------------- ### Store Methods Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt Reference for the methods available on Nanostores Immer stores for accessing and modifying their values. ```APIDOC ## Store Methods ### Description Provides a reference to the methods available on Nanostores Immer stores, including methods for getting, setting, and subscribing to store values. ### Methods #### get() - **Description**: Retrieves the current value of the store. - **Returns**: `Value` - The current value of the store. #### set(newValue) - **Description**: Sets a new value for the store. - **Parameters**: - `newValue` (any) - The new value to set for the store. - **Returns**: `void` #### mut(mutater) - **Description**: Applies a mutable update to the store's value using Immer. - **Parameters**: - `mutater` (function) - A function that takes the current state and returns the new state. - **Returns**: `void` #### subscribe(listener) - **Description**: Subscribes a listener function to changes in the store's value. - **Parameters**: - `listener` (function) - The function to call when the store's value changes. - **Returns**: `() => void` - A function to unsubscribe the listener. #### listen(listener) - **Description**: An alias for `subscribe`, used for listening to store changes. - **Parameters**: - `listener` (function) - The function to call when the store's value changes. - **Returns**: `() => void` - A function to unsubscribe the listener. #### notify(oldValue?) - **Description**: Manually triggers a notification for listeners, optionally with the old value. - **Parameters**: - `oldValue` (any, optional) - The previous value of the store. - **Returns**: `void` #### off() - **Description**: Unsubscribes all listeners from the store. - **Returns**: `void` ``` -------------------------------- ### Create a Writable Atom Store Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt Use the `atom` function to create a new writable store with an initial value. This is the fundamental building block for state management with nanostores. ```typescript import { atom } from "@illuxiza/nanostores-immer"; const count = atom(0); ``` -------------------------------- ### Integrate with React Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/REFERENCE.md Use the `useStore` hook from `@nanostores/react` to connect your nanostores to React components. This allows components to reactively update when the store's state changes. ```typescript import { useStore } from '@nanostores/react' import { atom } from '@illuxiza/nanostores-immer' const $counter = atom({ count: 0 }) function Counter() { const state = useStore($counter) return (

Count: {state.count}

) } ``` -------------------------------- ### Store Methods Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/README.md Methods available on a store instance for interacting with its state. ```APIDOC ## get() ### Description Retrieves the current value of the store. ## set(newValue) ### Description Directly assigns a new value to the store. ### Parameters - **newValue** (any) - The new state value. ## mut(mutater) ### Description Applies an Immer mutator function to update the store's state immutably. ### Parameters - **mutater** (function) - An Immer-compatible function that modifies the state. ## subscribe(listener) ### Description Subscribes a listener function to store changes. The listener is called immediately upon subscription and then on every subsequent change. ### Parameters - **listener** (function) - The callback function to execute on store changes. ## listen(listener) ### Description Subscribes a listener function to store changes. The listener is called only when the store's value changes, not immediately upon subscription. ### Parameters - **listener** (function) - The callback function to execute on store changes. ## notify(oldValue) ### Description Manually triggers a notification for listeners, useful for scenarios where state might have changed without a direct `set` or `mut` call. ### Parameters - **oldValue** (any) - The previous value of the store, used for comparison by listeners. ## off() ### Description Removes all registered listeners from the store, effectively unsubscribing them. ``` -------------------------------- ### Immer Mutations and Manual Notifications Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Explains how to use Immer for efficient state mutations and how to manually trigger notifications. ```APIDOC ## Immer Mutations and Manual Notifications ### Description This section details how to perform state updates using Immer's draft-based mutations and how to manually signal state changes. ### Methods - **`store.mut(mutationFn)`**: Applies an Immer-based mutation to the store. The `mutationFn` receives a draft of the current state, which can be modified directly. - **`store.notify(partialState)`**: Manually triggers a state update and notifies listeners. This is useful for updating the store when the change isn't directly a result of `set` or `mut`. ### Example Usage ```typescript // Immer mutations $app.mut(draft => { draft.loading = true; }); // Manual notification $app.notify({ loading: false }); ``` ``` -------------------------------- ### Core Functions Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/DOCUMENTATION_SUMMARY.txt Reference for the main functions provided by the Nanostores Immer library to create and manage stores. ```APIDOC ## atom(initialValue?: Value) ### Description Creates a new writable atom store with an optional initial value. ### Method `atom` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Returns - `PreinitializedWritableAtom`: A writable atom store. ## readonlyType(store: ReadableAtom) ### Description Creates a read-only version of a given store. ### Method `readonlyType` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Returns - `ReadableAtom`: A read-only atom store. ``` -------------------------------- ### Listener Management and Value Access Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Covers how to manage active listeners, remove them, and access the store's value directly. ```APIDOC ## Listener Management and Value Access ### Description This section explains how to inspect the number of active listeners, remove listeners individually or all at once, and access the store's current value property. ### Methods - **`store.lc`**: A property that returns the count of active listeners. - **`unsubscribe()`**: A function returned by `subscribe` or `listen` that removes a specific listener. - **`store.off()`**: Removes all listeners from the store. - **`store.value`**: A property that directly returns the current value of the store. ### Example Usage ```typescript // Check listener count console.log($app.lc); // Example output: 2 // Remove listeners unsubscribe1(); unsubscribe2(); console.log($app.lc); // Example output: 0 // Off removes all listeners const unsubscribe3 = $app.subscribe(() => {}); $app.off(); console.log($app.lc); // Example output: 0 // Value property console.log($app.value); // Current value object ``` ``` -------------------------------- ### subscribe(listener) Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/atom.md Subscribe to store changes and call the listener immediately with the current value. ```APIDOC ## subscribe(listener) ### Description Subscribe to store changes and call the listener immediately with the current value. ### Method ```typescript subscribe( listener: ( value: ReadonlyIfObject, oldValue?: ReadonlyIfObject ) => void ): () => void ``` ### Parameters #### Path Parameters - **listener** (function) - Required - Callback invoked immediately and on every state change. Receives the current value and optional previous value. ### Returns An unsubscribe function that removes the listener. ### Example ```typescript const $store = atom({ count: 0 }) const unsubscribe = $store.subscribe((value, oldValue) => { console.log('New:', value, 'Old:', oldValue) }) $store.set({ count: 1 }) unsubscribe() ``` ``` -------------------------------- ### Subscribe to Store Changes with Immediate Call Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/store-methods.md Use `subscribe()` to register a listener that is called immediately with the current value and on subsequent changes. It returns an unsubscribe function. ```typescript const $counter = atom(0) const unsubscribe = $counter.subscribe((value, oldValue) => { console.log(`Changed from ${oldValue} to ${value}`) }) // Output immediately: "Changed from undefined to 0" $counter.set(1) // Output: "Changed from 0 to 1" unsubscribe() $counter.set(2) // No output (unsubscribed) ``` -------------------------------- ### Advanced Read-Only Store Export with Custom Types Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/api-reference/readonlytype.md Demonstrates exporting a writable store with a specific interface as read-only, showcasing how to maintain internal mutability while exposing a safe read-only view to consumers. ```typescript import { atom, readonlyType } from '@illuxiza/nanostores-immer' // Define store types interface User { id: number name: string email: string } // Create internal mutable store const $userPrivate = atom({ id: 1, name: 'John', email: 'john@example.com' }) // Export as read-only export const $user = readonlyType($userPrivate) // Only internal code can modify function updateUser(user: User) { $userPrivate.set(user) } function updateUserName(name: string) { $userPrivate.mut(draft => { draft.name = name }) } // Consumer code can only read export function useUser() { const user = $user.get() return user } ``` -------------------------------- ### atom(initialValue) Source: https://github.com/illuxiza/nanostores-immer/blob/main/_autodocs/INDEX.md Creates an immutable store with Immer integration. This function is used to initialize a new store with a given initial value, leveraging Immer for efficient immutable updates. ```APIDOC ## atom(initialValue) ### Description Creates an immutable store with Immer integration. This function is used to initialize a new store with a given initial value, leveraging Immer for efficient immutable updates. ### Function Signature `atom(initialValue: Value): WritableAtom` ### Parameters #### Path Parameters - **initialValue** (any) - Required - The initial value for the store. ```