forked from hplush/slowreader
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommon.ts
More file actions
92 lines (83 loc) · 2.19 KB
/
common.ts
File metadata and controls
92 lines (83 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { nanoid } from 'nanoid/non-secure'
import { atom, type ReadableAtom } from 'nanostores'
import { isNotFoundError } from '../not-found.ts'
import type { PopupName } from '../router.ts'
type Extra = {
destroy: () => void
}
export type BasePopup<
Name extends PopupName = PopupName,
Loading extends boolean = boolean,
NotFound extends boolean = boolean
> = {
destroy(): void
readonly loading: ReadableAtom<Loading>
readonly name: Name
readonly notFound: NotFound
readonly param: string
readonly uniqueId: string
}
export interface PopupCreator<
Name extends PopupName,
Rest extends Extra = Extra
> {
(
param: string
):
| (BasePopup<Name, false, false> & Rest)
| BasePopup<Name, false, true>
| BasePopup<Name, true>
}
export type LoadedPopup<Popup extends BasePopup> = Extract<
Popup,
{ loading: ReadableAtom<false>; notFound: false }
>
export type CreatedLoadedPopup<Creator extends PopupCreator<PopupName>> =
LoadedPopup<ReturnType<Creator>>
export function getPopupId(name: PopupName, param: string): string {
return `${name}-${param.replace(/[^\w]/g, '_')}-popup`
}
export function definePopup<Name extends PopupName, Rest extends Extra>(
name: Name,
builder: (param: string) => Promise<Rest>
): PopupCreator<Name, Rest> {
let creator: PopupCreator<Name, Rest> = param => {
let destroyed = false
let rest: Rest | undefined
let loading = atom(true)
let popup = {
destroy() {
destroyed = true
rest?.destroy()
},
loading,
name,
notFound: false,
param,
uniqueId: nanoid()
}
loading.set(true)
builder(param)
.then(extra => {
rest = extra
if (destroyed) extra.destroy()
for (let i in rest) {
// @ts-expect-error Too complex case for TypeScript
popup[i] = extra[i]
}
loading.set(false)
})
.catch((e: unknown) => {
if (isNotFoundError(e)) {
popup.notFound = true
popup.destroy()
loading.set(false)
/* node:coverage ignore next 3 */
} else {
throw e
}
})
return popup as ReturnType<PopupCreator<Name, Rest>>
}
return creator
}