import { ReadonlySignal, Signal } from "@preact/signals-core"; import { useSignal } from "@preact/signals"; import { Fragment, createElement, ComponentChildren } from "preact"; import { useMemo } from "preact/hooks"; interface ShowProps { when: Signal | ReadonlySignal | (() => T); fallback?: ComponentChildren; children: ComponentChildren | ((value: NonNullable) => ComponentChildren); } const Item = (props: any) => { return typeof props.children === "function" ? props.children(props.v, props.i) : props.children; }; Item.displayName = "Item"; export function Show( props: ShowProps ): ComponentChildren | null { const value = typeof props.when === "function" ? props.when() : props.when.value; if (!value) return props.fallback || null; return ; } Show.displayName = "Show"; interface ForProps { each: | Signal> | ReadonlySignal> | (() => Array | Signal> | ReadonlySignal>); fallback?: ComponentChildren; getKey?: (item: T, index: number) => string | number; children: (value: T, index: number) => ComponentChildren; } export function For(props: ForProps): ComponentChildren | null { const cache = useMemo(() => new Map(), []); const list = (typeof props.each === "function" ? props.each() : props.each) as | Signal> | Array; const listValue = list instanceof Signal ? list.value : list; if (!listValue.length) return props.fallback || null; const removed = new Set(cache.keys()); const items = listValue.map((value, index) => { removed.delete(value); if (!cache.has(value)) { const key = props.getKey ? props.getKey(value, index) : index; const result = ( ); cache.set(value, result); return result; } return cache.get(value); }); removed.forEach(value => { cache.delete(value); }); return createElement(Fragment, null, items); } For.displayName = "For"; export function useLiveSignal(value: T): Signal { const s = useSignal(value); if (s.peek() !== value) s.value = value; return s; } export function useSignalRef(value: T): Signal & { current: T } { const ref = useSignal(value) as Signal & { current: T }; if (!("current" in ref)) Object.defineProperty(ref, "current", refSignalProto); return ref; } const refSignalProto = { configurable: true, get(this: Signal) { return this.value; }, set(this: Signal, v: any) { this.value = v; }, };