diff --git a/README.md b/README.md index 56d166e..6353d3d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Type safe, framework agnostic, Zod based, custom events extension library. [![NPM Version](https://img.shields.io/npm/v/zod-custom-events.svg?style=flat-square)](https://www.npmjs.com/package/@georgecht/zod-custom-events) [![JSR Version](https://jsr.io/badges/@georgecht/zod-custom-events)](https://jsr.io/@georgecht/zod-custom-events) -[![JSR Score](https://jsr.io/badges/@georgecht/zod-custom-events/score)](https://jsr.io/@/) +[![JSR Score](https://jsr.io/badges/@georgecht/zod-custom-events/score)](https://jsr.io/@georgecht/zod-custom-events) [![CI](https://img.shields.io/github/actions/workflow/status/georgecht/zod-custom-events/release.yml?style=flat-square)](https://github.com/georgecht/zod-custom-events/actions/workflows/release.yml) [![Codecov](https://codecov.io/github/GeorgeCht/zod-custom-events/graph/badge.svg?token=X8MC11L7NV)](https://codecov.io/github/GeorgeCht/zod-custom-events) [![Checked with Biome](https://img.shields.io/badge/checked_with-biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) @@ -27,13 +27,36 @@ Type safe, framework agnostic, Zod based, custom events extension library. - ✅ Middleware support for event processing - ✅ Less than __1kb__ minified and gzipped +## Table of Contents + +* [Installation](#installation) +* [Usage](#usage) +* [API Reference](#api-reference) + * [EventController](#eventcontroller) + 1. `Constructor` + 2. `Subscribe` + 3. `Unsubscribe` + 4. `Dispatch` + 5. `Refine` + 6. `Update` + 7. `Middleware` + +* [Contributing](#contributing) +* [License](#license) + +## Preview + example ## Installation +### Prerequisites + +- [Zod](https://github.com/colinhacks/zod) + Install zod-custom-events using your favorite package manager or CDN, then include it in your project: -### Using Node.js or Bun +### Using NPM ```bash # Install with npm @@ -65,5 +88,272 @@ bunx jsr add @georgecht/zod-custom-events ### Using a CDN ```html + + + + +``` + +## Usage + +Here's a basic example of how to use zod-custom-events: + +```typescript +import { z } from 'zod'; +import { EventController } from 'zod-custom-events'; + +// Define your event schema +const userSchema = z.object({ + id: z.number(), + email: z.email(), +}); + +// Create an event controller +const userEventController = new EventController(userSchema, 'user-event'); + +// Subscribe to the event +userEventController.subscribe((event) => { + console.log('Received user event:', event.detail); +}); + +// Dispatch an event +userEventController.dispatch({ + id: 123, + email: 'my@email.com', +}); + +// Cleanup +userEventController.unsubscribe(); +``` + +## API Reference + +The API reference is available on [GitHub](https://github.com/GeorgeCht/zod-custom-events/blob/main/README.md#api-reference). + +### EventController + +The main class for managing custom events. The `EventController` extends the `CustomEvent` interface with a `detail` property of type `T`. Meaning it will match the [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) interface and infer all the functionality. + +--- + +#### 👉 Constructor + +```typescript +constructor(schema: T, eventName: string, options?: EventControllerOptions) +``` + +Creates a new `EventController` instance. + +##### Parameters + +- `schema` - The Zod schema for validating the event payload. +- `eventName` - The name of the custom event. +- `options` optional - Configuration options for the `EventController`. + +##### Example + +```typescript +import { z } from 'zod'; +import { EventController } from 'zod-custom-events'; + +const schema = z.object({ + name: z.string(), +}); + +const controller = new EventController(schema, 'myEvent', { + onError: ({ error }) => console.error('Validation error:', error), + onDispatch: ({ payload }) => console.log('Dispatching event with payload:', payload), +}); +``` + +##### Available options + +- `element` optional - The element to bind the event to. Defaults to `window`. +- `onError` optional - Error handler for validation errors. +- `onDispatch` optional - Callback function called before dispatching the event. +- `onSubscribe` optional - Callback function called when the event listener is added. +- `onUnsubscribe` optional - Callback function called when the event listener is removed. + +--- + +#### 👉 Subscribe + +Subscribe to the event. + +```typescript +subscribe(listener: (event: TypedCustomEvent>) => void, options?: AddEventListenerOptions): void +``` + +##### Parameters + +- `listener` - The function to be called when the event is triggered. +- `options` - Optional parameters for the event listener. + +##### Available options + +- `once` optional - A boolean value indicating that the `listener` should be invoked at most [`once`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#once) after being added. If `true`, the `listener` would be automatically removed when invoked. +- `passive` optional - A boolean indicating whether the event listener is a [`passive`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#passive) listener. If set to `true`, indicates that the function specified by listener will never call [`preventDefault()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault). If a passive listener calls `preventDefault()`, nothing will happen and a console warning may be generated. +- `signal` optional - An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) to signal when the listener should be removed. + +##### Simple example + +```typescript +controller.subscribe((event) => { + console.log('Received user event:', event.detail); +}); +``` + +##### Example with abort signal and once option + +```typescript +// With abort signal and once option +const abortController = new AbortController(); +const { signal } = abortController; + +controller.subscribe((event) => { + console.log('Received user event:', event.detail); +}, { signal, once: true }); + +// Later in the code +abortController.abort(); +``` + +--- + +#### 👉 Unsubscribe + +Removes the previously registered event listener for the event. + +```typescript +unsubscribe(options?: EventListenerOptions): void +``` + +##### Parameters + +- `options` optional - Optional parameters to match the event listener. + +##### Available options +- `capture` optional - A boolean value indicating that events of this type will be dispatched to the registered `listener` before being dispatched to any `EventTarget` beneath it in the DOM tree. + +##### Example + +```typescript +controller.unsubscribe(); +``` + +--- + +#### 👉 Dispatch + +Dispatches the event, validating its payload using the Zod schema and applying middleware. + +```typescript +dispatch(payload: EventPayload, eventInitDict?: CustomEventInit>): Promise +``` + +##### Parameters + +- `payload` - The data associated with the event. Validated against the `Zod` schema initially provided. +- `eventInitDict` optional - Optional parameters for initializing the event. + +##### Available `eventInitDict` options + +- `bubbles` optional - A boolean value indicating whether or not the event can bubble through the DOM. +- `cancelable` optional - A boolean value indicating whether the event can be cancelled. +- `composed` optional - A boolean value indicating whether the event will trigger listeners outside of a shadow root (see [`Event.composed`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composed) for more details). + +##### Example + +```typescript +controller.dispatch({ + id: 1, + name: 'John Doe', +}, { + bubbles: true +}); +``` + +--- + +#### 👉 Refine + +Sets a condition for the event, allowing control over whether the event is dispatched. + +```typescript +refine(condition: (payload: EventPayload) => boolean, callback?: (ctx: EventPayloadContext) => void): void +``` + +##### Parameters + +- `condition` - A function that takes the event payload as input and returns a boolean. +- `callback` optional - An optional callback function to be called when the condition is not met. + +##### Example + +```typescript +controller.refine( + (payload) => payload.id > 0, + (ctx) => { + const { payload } = ctx; + console.log("Invalid user ID:", payload.id) + } +); +``` + +--- + +#### 👉 Update + +Updates the `EventController` options. + +```typescript +update(options: Partial>): void ``` + +##### Parameters + +- `options` optional - New configuration options for the `EventController`. + +##### Example + +```typescript +const controller = new EventController(schema, 'myEvent'); + +// Later in the code +controller.update({ + onError: ({ error }) => console.warn('New error handler:', error), + onDispatch: ({ payload }) => console.log('New dispatch handler:', payload), +}); +``` + +--- + +#### 👉 Use + +Adds a middleware function to the event processing pipeline. + +```typescript +use(middleware: Middleware>): void +``` + +##### Parameters + +- `middleware` - A function that processes the event context and calls the next middleware. + +##### Example + +```typescript +controller.use(async (ctx, next) => { + console.log("Processing user event:", ctx.payload); + await next(); +}); +``` + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request. + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. \ No newline at end of file