UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

173 lines (172 loc) 6.29 kB
/** A function that performs cleanup when called */ export type DisposeFn = () => void; /** * Interface for objects that hold resources and can be disposed. * Implement this interface on any object that needs deterministic cleanup. * * @example * ```ts * class MyResource implements IDisposable { * dispose() { /* release resources *\/ } * } * ``` * * @category Utilities * @group Lifecycle */ export interface IDisposable { dispose(): void; } /** * Type guard to check if an object implements {@link IDisposable}. * * @example * ```ts * if (isDisposable(obj)) { * obj.dispose(); // safe to call * } * ``` */ export declare function isDisposable(value: unknown): value is IDisposable; /** * @experimental * Subscribe to a DOM event on any {@link EventTarget} (window, document, HTML elements, etc.) * and return an {@link IDisposable} that removes the listener when disposed. * * Provides full TypeScript event type inference — the callback parameter * is automatically typed based on the event name (e.g. `"resize"` → `UIEvent`, * `"click"` → `MouseEvent`). * * Use with {@link DisposableStore.add} for automatic lifecycle cleanup in components. * * @param target The EventTarget to listen on (window, document, an element, etc.) * @param type The event name (e.g. `"resize"`, `"click"`, `"keydown"`) * @param listener The event handler callback * @param options Optional addEventListener options (passive, capture, once, signal) * @returns An {@link IDisposable} that removes the event listener when disposed * * @example Standalone usage * ```ts * import { on } from "@needle-tools/engine"; * * const sub = on(window, "resize", (ev) => { * // ev is typed as UIEvent * console.log("resized", ev.target); * }); * * // Later: clean up * sub.dispose(); * ``` * * @example With autoCleanup in a component * ```ts * import { Behaviour, on } from "@needle-tools/engine"; * * export class MyComponent extends Behaviour { * onEnable() { * this.autoCleanup(on(window, "resize", (ev) => { /* UIEvent *\/ })); * this.autoCleanup(on(document, "keydown", (ev) => { /* KeyboardEvent *\/ })); * this.autoCleanup(on(this.context.domElement, "click", (ev) => { /* MouseEvent *\/ })); * } * // All listeners removed automatically on disable! * } * ``` * * @category Utilities * @group Lifecycle */ export declare function on<K extends keyof WindowEventMap>(target: Window, type: K, listener: (ev: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable; export declare function on<K extends keyof DocumentEventMap>(target: Document, type: K, listener: (ev: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable; export declare function on<K extends keyof HTMLElementEventMap>(target: HTMLElement, type: K, listener: (ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): IDisposable; export declare function on(target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): IDisposable; /** * A store for managing disposable resources (event subscriptions, listeners, callbacks) * that should be cleaned up together. * * DisposableStore collects disposables and disposes them all at once when * {@link dispose} is called. After disposal, the store can be reused — new items * can be added and a subsequent {@link dispose} call will clean those up. * * This is the same pattern used internally by VSCode for lifecycle-bound resource management. * * @example Basic usage * ```ts * import { DisposableStore, on } from "@needle-tools/engine"; * * const store = new DisposableStore(); * * // Register a DOM event listener (typed!) * store.add(on(window, "resize", (ev) => console.log(ev))); * * // Register the return value of EventList.on() * store.add(myEventList.on(data => console.log(data))); * * // Register a raw cleanup function * store.add(() => someSDK.off("event", handler)); * * // Later: dispose everything at once * store.dispose(); * ``` * * @example Use with Needle Engine components * ```ts * import { Behaviour, serializable, EventList, on } from "@needle-tools/engine"; * * export class MyComponent extends Behaviour { * @serializable(EventList) * onClick?: EventList; * * onEnable() { * // DOM events — fully typed * this.autoCleanup(on(window, "resize", (ev) => this.onResize(ev))); * * // EventList — .on() returns a function, autoCleanup accepts it * this.autoCleanup(this.onClick?.on(() => console.log("clicked!"))); * } * // No onDisable needed — cleaned up automatically! * } * ``` * * @category Utilities * @group Lifecycle */ export declare class DisposableStore implements IDisposable { private _disposables; /** The number of registered disposables */ get size(): number; /** * Register a disposable resource. Accepts: * - An {@link IDisposable} object (has a `dispose()` method) — e.g. from {@link on} * - A cleanup function (e.g. return value of `EventList.on()`) * - `null` or `undefined` (safe no-op for conditional subscriptions) * * When {@link dispose} is called, all registered resources are cleaned up. * * @param disposable The resource to register for disposal * * @example * ```ts * const store = new DisposableStore(); * * // IDisposable object from on() * store.add(on(window, "resize", handler)); * * // Function returned by EventList.on() * store.add(myEvent.on(handler)); * * // Raw cleanup function * store.add(() => connection.close()); * * // Conditional — safe with undefined * store.add(this.maybeEvent?.on(handler)); * ``` */ add(disposable: IDisposable | DisposeFn | Function | null | undefined): void; /** * Dispose all registered resources. Each registered disposable is cleaned up, * then the internal list is cleared. The store can be reused after disposal. * * Called automatically by the engine when a component's `onDisable` lifecycle fires. */ dispose(): void; }