forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {createContext, useContext, useEffect, useMemo, useState} from 'react'
2import {nanoid} from 'nanoid/non-secure'
3
4import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
5import {useHotkeysContext} from '#/lib/hotkeys'
6import {type ImageSource} from '#/view/com/lightbox/ImageViewing/@types'
7
8export type Lightbox = {
9 id: string
10 images: ImageSource[]
11 index: number
12}
13
14const LightboxContext = createContext<{
15 activeLightbox: Lightbox | null
16}>({
17 activeLightbox: null,
18})
19LightboxContext.displayName = 'LightboxContext'
20
21const LightboxControlContext = createContext<{
22 openLightbox: (lightbox: Omit<Lightbox, 'id'>) => void
23 closeLightbox: () => boolean
24}>({
25 openLightbox: () => {},
26 closeLightbox: () => false,
27})
28LightboxControlContext.displayName = 'LightboxControlContext'
29
30export function Provider({children}: React.PropsWithChildren<{}>) {
31 const [activeLightbox, setActiveLightbox] = useState<Lightbox | null>(null)
32 const {disableScope, enableScope} = useHotkeysContext()
33
34 useEffect(() => {
35 if (activeLightbox) {
36 disableScope('global')
37 } else {
38 enableScope('global')
39 }
40 }, [activeLightbox, disableScope, enableScope])
41
42 const openLightbox = useNonReactiveCallback(
43 (lightbox: Omit<Lightbox, 'id'>) => {
44 setActiveLightbox(prevLightbox => {
45 if (prevLightbox) {
46 // Ignore duplicate open requests. If it's already open,
47 // the user has to explicitly close the previous one first.
48 return prevLightbox
49 } else {
50 return {...lightbox, id: nanoid()}
51 }
52 })
53 },
54 )
55
56 const closeLightbox = useNonReactiveCallback(() => {
57 let wasActive = !!activeLightbox
58 setActiveLightbox(null)
59 return wasActive
60 })
61
62 const state = useMemo(
63 () => ({
64 activeLightbox,
65 }),
66 [activeLightbox],
67 )
68
69 const methods = useMemo(
70 () => ({
71 openLightbox,
72 closeLightbox,
73 }),
74 [openLightbox, closeLightbox],
75 )
76
77 return (
78 <LightboxContext.Provider value={state}>
79 <LightboxControlContext.Provider value={methods}>
80 {children}
81 </LightboxControlContext.Provider>
82 </LightboxContext.Provider>
83 )
84}
85
86export function useLightbox() {
87 return useContext(LightboxContext)
88}
89
90export function useLightboxControls() {
91 return useContext(LightboxControlContext)
92}