Skip to content

Commit 4985b92

Browse files
committed
enhance(carousel): Close carousel on browser back navigation
1 parent a3c5a33 commit 4985b92

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

components/carousel.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,39 @@ function CarouselOverflow ({ originalSrc, rel }) {
114114
export function CarouselProvider ({ children }) {
115115
const media = useRef(new Map())
116116
const showModal = useShowModal()
117+
const [isCarouselOpen, setIsCarouselOpen] = useState(false)
117118

118119
const showCarousel = useCallback(({ src }) => {
119120
// only show confirmed entries
120121
const confirmedEntries = Array.from(media.current.entries())
121122
.filter(([, entry]) => entry.confirmed)
122123

124+
setIsCarouselOpen(true)
123125
showModal((close, setOptions) => {
124126
return <Carousel close={close} mediaArr={confirmedEntries} src={src} setOptions={setOptions} />
125127
}, {
126128
fullScreen: true,
127-
overflow: <CarouselOverflow {...media.current.get(src)} />
129+
overflow: <CarouselOverflow {...media.current.get(src)} />,
130+
hash: 'carousel',
131+
onClose: () => {
132+
setIsCarouselOpen(false)
133+
}
128134
})
129135
}, [showModal])
130136

137+
useEffect(() => {
138+
if (typeof window === 'undefined') return
139+
140+
if (window.location.hash === '#carousel') {
141+
const confirmedEntries = Array.from(media.current.entries())
142+
.filter(([, entry]) => entry.confirmed)
143+
144+
if (confirmedEntries.length > 0) {
145+
showCarousel({ src: confirmedEntries[0][0] })
146+
}
147+
}
148+
}, [showCarousel])
149+
131150
const addMedia = useCallback(({ src, originalSrc, rel }) => {
132151
media.current.set(src, { src, originalSrc, rel, confirmed: false })
133152
}, [])
@@ -137,8 +156,16 @@ export function CarouselProvider ({ children }) {
137156
if (mediaItem) {
138157
mediaItem.confirmed = true
139158
media.current.set(src, mediaItem)
159+
160+
if (typeof window !== 'undefined' && window.location.hash === '#carousel' && !isCarouselOpen) {
161+
const confirmedEntries = Array.from(media.current.entries())
162+
.filter(([, entry]) => entry.confirmed)
163+
if (confirmedEntries.length >= 1) {
164+
showCarousel({ src })
165+
}
166+
}
140167
}
141-
}, [])
168+
}, [showCarousel, isCarouselOpen])
142169

143170
const removeMedia = useCallback((src) => {
144171
media.current.delete(src)

components/modal.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,22 @@ export default function useModal () {
5959
return
6060
}
6161

62+
const currentHash = window.location.hash
63+
if (currentHash) {
64+
const hasModalWithHash = modalStack.current.some(
65+
modal => modal.options?.hash && `#${modal.options.hash}` === currentHash
66+
)
67+
if (hasModalWithHash) {
68+
window.history.replaceState(window.history.state, '', window.location.pathname + window.location.search)
69+
}
70+
}
71+
6272
while (modalStack.current.length) {
6373
getCurrentContent()?.options?.onClose?.()
6474
modalStack.current.pop()
6575
}
6676
forceUpdate()
67-
}, [onBack])
77+
}, [onBack, getCurrentContent])
6878

6979
const router = useRouter()
7080
useEffect(() => {
@@ -80,6 +90,21 @@ export default function useModal () {
8090
return () => router.events.off('routeChangeStart', maybeOnClose)
8191
}, [router.events, onClose, getCurrentContent])
8292

93+
useEffect(() => {
94+
const handleHashChange = () => {
95+
const currentContent = getCurrentContent()
96+
if (!currentContent?.options?.hash) return
97+
98+
const expectedHash = `#${currentContent.options.hash}`
99+
if (window.location.hash !== expectedHash) {
100+
onClose()
101+
}
102+
}
103+
104+
window.addEventListener('hashchange', handleHashChange)
105+
return () => window.removeEventListener('hashchange', handleHashChange)
106+
}, [onClose, getCurrentContent])
107+
83108
const modal = useMemo(() => {
84109
if (modalStack.current.length === 0) {
85110
return null
@@ -116,6 +141,12 @@ export default function useModal () {
116141
const showModal = useCallback(
117142
(getContent, options) => {
118143
document.activeElement?.blur()
144+
if (options?.hash) {
145+
const newHash = `#${options.hash}`
146+
if (window.location.hash !== newHash) {
147+
window.history.pushState(window.history.state, '', newHash)
148+
}
149+
}
119150
const ref = { node: getContent(onClose, setOptions), options }
120151
if (options?.replaceModal) {
121152
modalStack.current = [ref]
@@ -124,7 +155,7 @@ export default function useModal () {
124155
}
125156
forceUpdate()
126157
},
127-
[onClose]
158+
[onClose, setOptions]
128159
)
129160

130161
return [modal, showModal]

0 commit comments

Comments
 (0)