UNPKG

@stainless-code/layers

Version:

Headless, UI-agnostic layer/stack manager for modal/dialog/drawer/popover/toast UI. Call a layer like an async function and await its response.

65 lines (59 loc) 1.83 kB
import type { Layer } from "./layer"; import type { LayerKey } from "./types"; import { keySignature } from "./utils"; export interface LayerGcCacheOptions<P, R, E, D> { /** Read at store time; `<= 0` disables caching. */ gcTime: () => number; onBeforeStore?: (layer: Layer<P, R, E, D>) => void; /** Runs for expiry and same-key displacement, but not restoration. */ onEvict?: (layer: Layer<P, R, E, D>) => void; } export interface LayerGcCache<P, R, E, D> { maybeStore(layer: Layer<P, R, E, D>): void; take(key: LayerKey): Layer<P, R, E, D> | undefined; } /** * Retains dismissed layer data for same-key restoration without reloading. * Only the last dismissed layer for each key is retained. */ export function createLayerGcCache<P, R, E, D>( opts: LayerGcCacheOptions<P, R, E, D>, ): LayerGcCache<P, R, E, D> { const entries = new Map< string, { layer: Layer<P, R, E, D>; timer: ReturnType<typeof setTimeout> } >(); const evict = (sig: string): void => { const entry = entries.get(sig); if (!entry) { return; } clearTimeout(entry.timer); entries.delete(sig); opts.onEvict?.(entry.layer); }; return { maybeStore(layer) { const gcTime = opts.gcTime(); if (gcTime <= 0 || layer.state.data === undefined) { return; } opts.onBeforeStore?.(layer); const sig = keySignature(layer.key); evict(sig); const timer = setTimeout(() => evict(sig), gcTime); entries.set(sig, { layer, timer }); }, take(key) { const sig = keySignature(key); const entry = entries.get(sig); if (!entry) { return undefined; } clearTimeout(entry.timer); entries.delete(sig); // Restoration transfers ownership without eviction cleanup. return entry.layer; }, }; }