-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.tsx
98 lines (89 loc) · 2.28 KB
/
index.tsx
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
93
94
95
96
97
98
'use client'
import {
type FC,
type JSX,
type ReactNode,
Fragment,
createContext,
useContext,
useMemo,
useRef,
useState,
} from 'react'
interface PromptContext {
allocSlot(getJsx: (id: string) => JSX.Element): string
deleteSlot(id: string): void
}
const PromptContext = createContext<PromptContext | null>(null)
export interface PromptContextProviderProps {
children: ReactNode
}
export const PromptProvider: FC<PromptContextProviderProps> = ({
children,
}) => {
const [slots, setSlots] = useState<Slot[]>([])
const lastId = useRef(0)
return (
<PromptContext.Provider
value={useMemo(
() => ({
allocSlot(getJsx) {
const id = 'p' + lastId.current++
setSlots([...slots, { id, jsx: getJsx(id) }])
return id
},
deleteSlot(id) {
setSlots(slots.filter(s => s.id !== id))
},
}),
[slots, setSlots]
)}
>
{children}
{slots.map(({ id, jsx }) => (
<Fragment key={id}>{jsx}</Fragment>
))}
</PromptContext.Provider>
)
}
interface Slot {
id: string
jsx: JSX.Element
}
export default function usePrompt<ResolvesWith, RejectsWith, Variables>(
PromptComponent: PromptComponent<ResolvesWith, RejectsWith, Variables>
) {
const { allocSlot, deleteSlot } = useContext(PromptContext) ?? {}
return useMemo(
() => ({
prompt: async (variables: Variables): Promise<ResolvesWith> =>
new Promise((resolve, reject) => {
allocSlot?.(id => {
const close = () => deleteSlot?.(id)
return (
<PromptComponent
{...{ variables }}
resolve={value => {
close()
resolve(value)
}}
reject={error => {
close()
reject(error)
}}
/>
)
})
}),
}),
[PromptComponent, allocSlot, deleteSlot]
)
}
export interface PromptComponentProps<ResolvesWith, RejectsWith, Variables> {
resolve(v: ResolvesWith): void
reject(v: RejectsWith): void
variables: Variables
}
export type PromptComponent<ResolvesWith, RejectsWith, Variables> = FC<
PromptComponentProps<ResolvesWith, RejectsWith, Variables>
>