open-index/open-npm huggingface dataset:
npm package: @figliolia/event-emitter
Description: A basic event emitter for all platforms
Author: Alex Figliolia
Latest version: 1.2.0

# @figliolia/event-emitter

### Installation

```bash
npm i -S @figliolia/event-emitter
# or yarn
yarn add @figliolia/event-emitter
```

### Basic Usage
#### Creating an instance
```typescript
import { EventEmitter } from "@figliolia/event-emitter";

export const MyEmitter = new EventEmitter();
```

#### Emitting Events
```typescript
import { MyEmitter } from "./path/to/myEmitter";

MyEmitter.emit("my-event", /* any data to send to subscribers */);
```

#### Subscribing to Events
```typescript
import { MyEmitter } from "./path/to/myEmitter";

const ID = MyEmitter.on("my-event", (data) => {});

// Cleaning up listeners
MyEmitter.off("my-event", ID);
```

### With Strict Typescript
#### Creating a type-safe Instance
```typescript
import { EventEmitter } from "@figliolia/event-emitter";

type MyEvents = {
  event: {
    dataPoint: number;
    anotherDataPoint: any
  },
  // ...rest
}

export const MyEmitter = new EventEmitter<MyEvents>();
```

#### Emitting type-safe Events
```typescript
import { MyEmitter } from "./path/to/myEmitter";

MyEmitter.emit("event", {
  dataPoint: 2,
  anotherDataPoint: [1, 2, 3]
});

// Incorrect payload types fail typescript validation
MyEmitter.emit("event", {
  dataPoint: "one",
});

// Unsupported events fail typescript validation
MyEmitter.emit("another-event", /* event */);
```

#### Subscribing to Events
```typescript
import { MyEmitter } from "./path/to/myEmitter";

MyEmitter.on("event", (data) => {
  // data is strictly typed to the "event"
});

// Subscriptions to unsupported events fail typescript validation
MyEmitter.on("another-event", /* handler */);
```
npm package: @figliolia/frame-pooler
Description: A task manager for distributing callbacks between animation frames
Author: Alex Figliolia
Latest version: 1.1.3

# Frame Pooler
A task queue for distributing callbacks into animation frames. The Frame Pooler will allow you to run sequential tasks and automatically handle task distribution based on a maximum frame-duration and callstack size.

This library is primarily designed for heavy DOM manipulation and/or animation.

## Installation
```bash
npm i @figliolia/frame-pooler
# or
yarn add @figliolia/frame-pooler
```

## Basic Usage
```typescript
import { FramePooler } from "@figliolia/frame-pooler";

const Pooler = new FramePooler(
  100 
  /* max call stack size per frame (defaults to Infinity) */
);

Pooler.run((time: number) => {
  // heavy DOM reads or updates
});
```

### Background
When building an animation-intensive JavaScript library I found myself benchmarking the performance of concurrent calls to `requestAnimationFrame` vs. pooling callbacks into already open animation frames. 

Due to the fact that logic executed inside of `requestAnimationFrame` can itself take any duration, I landed upon a game loop-like solution for my library - where an animation loop would remain running as long as tasks were pending. And if a given set of tasks exceeded a safe duration for a single frame, the frame will close with remaining tasks executing in the next available frame.

Thus allowing for the best possible frame rate the end-user's device could handle while still receiving user-input.
npm package: @figliolia/galena-async-storage
Description: An Galena middleware that persists your state using React Native's AsyncStorage
Author: Alex Figliolia
Latest version: 1.0.2

# Async Storage Middleware
A [Galena](https://www.npmjs.com/package/@figliolia/galena) middleware for persisting units of State with [Async Storage](https://react-native-async-storage.github.io/async-storage/). 

# Getting Started

## Installation
```bash
npm install --save @figliolia/galena-async-storage
# or
yarn add @figliolia/galena-async-storage
```

## Basic Usage

```typescript
import { State } from "@figliolia/galena";
import { AsyncStorageMiddleware } from "@figliolia/galena-async-storage";
import AsyncStorage from "@react-native-async-storage/async-storage";

const UserState = new State("User", {
  token: "",
  username: ""
});

void AsyncStorage.getItem("User").then(savedState => {
  if(savedState) {
    // Initialize User State from async storage
    UserState.update(state => {
      state.token = savedState.token;
      state.username = savedState.username;
    });
  }
  // Persist all future state mutations using AsyncStorageMiddleware
  UserState.registerMiddleware(new AsyncStorageMiddleware());
});
```
### Persisting State Mutations
Once the `AsyncStorageMiddleware()` is registered on your state, each call to `State.update()`, `State.backgroundUpdate()`, and `State.priorityUpdate()` will persist the latest mutation into `AsyncStorage`. Each entry's key will be equal to `State.name`.

## Factories for Persisted Galena State
In production, you may find yourself with several units of State requiring `AsyncStorage`. If using `Galena` instances, applying this middleware to all unit's of `State` is as easy as calling:

```typescript
import { Galena } from "@figliolia/galena";
import { AsyncStorageMiddleware } from "@figliolia/galena-async-storage";

export const AppState = new Galena([
  new AsyncStorageMiddleware()
]);

const MyState = AppState.composeState("My State", {
  token: "",
  username: ""
});
// MyState.middleware = [new AsyncStorageMiddleware()];
```

However, if you're using Island Architecture and require several AsyncStorage-persisted units of State, a factory can be created for automatically applying the `AsyncStorageMiddleware`

```typescript
import { State, type Middleware } from "@figliolia/galena";
import { AsyncStorageMiddleware } from "@figliolia/galena-async-storage";

export const createPersistedState = <T>(
  name: string, 
  initialState: T, 
  middleware: [new AsyncStorageMiddleware()]
) => {
  const state = new State<T>(name, initialState);
  state.registerMiddleware(...middleware);
  return state;
}
```