a post-component library for building user-interfaces on the web.
1import type { Renderable } from 'dhtml'
2import { invalidate, onMount } from 'dhtml/client'
3import type { Bus } from './bus'
4import { suspend } from './suspense'
5
6export interface Query<T> {
7 (): T
8 revalidate(): void
9}
10
11type QueryFn<T> = (prev: T | null) => Promise<T>
12
13export function createQuery<T>(renderable: Renderable, fn: QueryFn<T>): Query<T> {
14 let value: T | null = null
15 let promise = handle()
16
17 async function handle() {
18 value = await fn(value)
19 invalidate(renderable)
20 return value
21 }
22
23 function query() {
24 if (value == null) return suspend(renderable, promise)
25 return value
26 }
27
28 query.revalidate = () => {
29 promise = handle()
30 }
31
32 return query
33}
34
35export function createSubscribedQuery<T, Event extends string>(
36 renderable: Renderable,
37 bus: Bus<Event>,
38 event: Event,
39 fn: QueryFn<T>,
40): Query<T> {
41 const query = createQuery(renderable, fn)
42 onMount(renderable, () => bus.subscribe(event, query.revalidate))
43 return query
44}