import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/en/functional-basic/Classes/StorageCallback - Storage Callbacks'/>

# StorageCallback Class

A utility class for managing groups of callback functions associated with specific storage keys. It ensures that multiple components or functions can react to storage changes or triggers in a coordinated, asynchronous manner.

## Key Features

- **Named Instances** — facilitates a singleton-like pattern where instances are retrieved by name and group, ensuring different parts of the application share the same callback list for the same resource.
- **Group Separation** — allows segregating callback lists by group (e.g., 'main', 'global', 'local'), preventing name collisions between different modules.
- **Asynchronous Execution** — supports `Promise`-based callbacks and executes them sequentially during the `run` process.
- **Loading State Tracking** — provides a built-in `loading` flag that is automatically managed during the callback execution phase.

## Initialization

To initialize the object, call the `StorageCallback(name, group)` constructor or use the static method `getInstance(name, group)`.

### Generic Constraints

To ensure strict typing, the class supports the following generics:
- `T = any` — The type of data passed to callbacks.
- `Callback = (value: T) => void | Promise<void>` — The structure of the callback function.

**Parameters:**
- `name: string` — a unique identifier for the storage entry.
- `group: string = 'main'` — optional category to prevent name collisions.

```typescript
import { StorageCallback } from '@dxtmisha/functional-basic'

// 1. Simple initialization (group defaults to 'main')
const storage = new StorageCallback('user-data')

// 2. Using the singleton-like getInstance method
const sharedStorage = StorageCallback.getInstance('settings', 'global')

// 3. Using generics for strict typing
const numberStorage = new StorageCallback<number>('counter')
numberStorage.addCallback((val) => console.log(val + 1))
```

## Methods

### Information

- `getName(): string` — returns the storage instance name.
- `isLoading(): boolean` — returns the current loading state.
- `getLoading(): boolean` — returns the current loading state (alias for `isLoading`).

### Management

- `addCallback(callback: Callback, isOnce?: boolean): this` — adds a new callback to the execution list. If `isOnce: true`, the callback will be removed after the first execution.
- `removeCallback(callback: Callback): this` — removes a specific callback from the list.

### Control

- `preparation(): this` — prepares the state before execution (sets `loading` to `true`). Should be called manually when starting an asynchronous process.
- `run(value: T): Promise<this>` — executes all callbacks sequentially with the provided value. Sets `loading` back to `false` at the start of execution.

## Usage Examples

### Manual Loading Management

When data is fetched asynchronously from an external source (e.g., Figma storage), you can manage the `loading` state manually to coordinate multiple requests.

```typescript
const storage = new StorageCallback('figma-data')

// 1. Check if it is not already loading
if (!storage.isLoading()) {
  // 2. Set loading state to true
  storage.preparation()
  
  // 3. Request the data
  fetchFromFigma((data) => {
    // 4. Run callbacks (run will reset loading to false)
    storage.run(data)
  })
}
```

### One-time Callback

If you only need a function to trigger once (e.g., for initial data hydration), use the `isOnce` flag.

```typescript
const storage = new StorageCallback('initial-data')

storage.addCallback((data) => {
  console.log('Executed once:', data)
}, true)

await storage.run('update 1') // 'Executed once: update 1'
await storage.run('update 2') // (no output, callback removed)
```
