-
Notifications
You must be signed in to change notification settings - Fork 1
Image preview modal for mobile breakpoint #2470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
45726f7
f5b7536
f788ab5
1909c27
713fcc5
7353861
97e29f4
cb31fc4
a9e23de
3a088ca
89c6ded
e1720dc
adc0207
48a5d0c
178e7bc
1b691f4
532aec9
a3273ac
9c92f68
edb751b
3a73905
f6c028a
b0722f0
c3e07d9
ac11a97
77eff7a
9eeaf12
7150543
05c0a01
a02e331
b27c170
cd496fd
8ee7fb5
d14563a
56679aa
e0e0e03
19f6d69
2da15d1
338734a
da94778
ef500b8
7dabf30
a5a754e
22e2e25
7f99e7d
9ccc7c9
8c87404
8ca0ea0
89c451b
e56810d
2649e67
1ca3195
ffcae6a
422f8b7
dac844e
f087090
5a4d541
9d1738f
f393ba9
f94b264
d4e3138
e7ccc2a
63e9f5e
17271e2
22b59c9
3764f95
b660403
9735f70
9357026
1ffde53
9fd0d77
bb7b2c0
013d467
0b4599a
3415cf6
5f36c56
ae55483
9ba613e
aa37c3c
5c88fb7
40b37d0
df0625c
d40b383
622c51c
f873229
7e56d2a
2b1facb
472af21
4c329bc
76b138c
ee739a2
615f1c4
2869de9
05c7085
4294add
4ec6f0d
664fe18
8c74631
07c6153
1c35c23
915f6e6
de668c3
6aee41d
af498d8
b8552dc
016f43d
34744ee
754bb31
f1478b1
9623bc9
d10bd25
5ecd665
c303af9
f00e146
c1e9f7d
1e66835
57e3245
9ea208c
289040e
d595b3c
603225d
b1397fe
5207d84
c6df875
f7c93a5
7d78498
7c53bae
2b5b009
9755b5e
6fa3274
a557b76
2407a4c
0057d4e
88af331
e942ea3
a50b1c8
dd83ed5
72fd9a1
1443cd6
f2531b0
cae5071
eeb7b14
7b32195
bd284c3
816a8ee
db3e90b
9519d24
2f334ca
ab90b5d
a9ea6e2
a6ca330
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| import React, { ReactNode, useEffect } from 'react'; | ||
| import { createPortal } from 'react-dom'; | ||
| import MediaModal from './MediaModal'; | ||
| import { HTMLElement, MouseEvent, KeyboardEvent } from '@openstax/types/lib.dom'; | ||
|
|
||
| export type MediaModalManager = ReturnType<typeof createMediaModalManager>; | ||
|
|
||
| export function createMediaModalManager(container: HTMLElement | null) { | ||
|
||
| let setModalContent: ((content: ReactNode) => void) | null = null; | ||
|
|
||
| const mount = (setContentHandler: (content: ReactNode) => void) => { | ||
| setModalContent = setContentHandler; | ||
| }; | ||
|
|
||
| const open = (content: ReactNode) => { | ||
| setModalContent?.(content); | ||
| }; | ||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const MediaModalPortal = () => { | ||
| const [isOpen, setIsOpen] = React.useState(false); | ||
| const [modalContent, setContent] = React.useState<ReactNode>(null); | ||
|
|
||
| useEffect(() => { | ||
| if (!isOpen || typeof document === 'undefined') return; | ||
| console.log('Escape key listener added'); | ||
| const onKeyDown = (e: KeyboardEvent) => { | ||
| if (e.key === 'Escape') { | ||
| setIsOpen(false); | ||
| } | ||
| }; | ||
| if (typeof document === 'undefined') return; | ||
|
||
|
|
||
| const doc = document; | ||
|
|
||
| doc.addEventListener('keydown', onKeyDown); | ||
| return () => { | ||
| doc.removeEventListener('keydown', onKeyDown); | ||
| }; | ||
| }, [isOpen]); | ||
|
|
||
| useEffect(() => { | ||
| mount((content) => { | ||
| setContent(content); | ||
| setIsOpen(true); | ||
| }); | ||
| }, []); | ||
|
||
|
|
||
| if (typeof document === 'undefined') return null; | ||
|
|
||
| return createPortal( | ||
| <MediaModal isOpen={isOpen} onClose={() => setIsOpen(false)}> | ||
| {modalContent} | ||
| </MediaModal>, | ||
| document.body | ||
| ); | ||
| }; | ||
|
|
||
| const handleMediaInteraction = (e: MouseEvent | KeyboardEvent) => { | ||
| const target = e.target as HTMLElement; | ||
| if (target.tagName !== 'IMG') return; | ||
|
|
||
| if (e.type === 'keydown') { | ||
| const key = (e as KeyboardEvent).key; | ||
| if (key !== 'Enter' && key !== ' ') return; | ||
| e.preventDefault(); | ||
| } | ||
|
|
||
| const outerHTML = target.outerHTML; | ||
| if (typeof window !== 'undefined') { | ||
| open(<div dangerouslySetInnerHTML={{ __html: outerHTML }} />); | ||
| } | ||
| }; | ||
|
|
||
| const attachListeners = () => { | ||
| if (!container) return; | ||
| container.addEventListener('click', handleMediaInteraction); | ||
| container.addEventListener('keydown', handleMediaInteraction); | ||
| }; | ||
|
|
||
| const detachListeners = () => { | ||
| if (!container) return; | ||
| container.removeEventListener('click', handleMediaInteraction); | ||
| container.removeEventListener('keydown', handleMediaInteraction); | ||
| }; | ||
|
|
||
| return { | ||
RoyEJohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| mount, | ||
| open, | ||
| MediaModalPortal, | ||
| attachListeners, | ||
| detachListeners, | ||
| }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this whole MediaModalManger setup is pretty convoluted, can you look at the highlightManager and try to share some of the patterns?
don't need the singleton class. stylistically, would be more consistent if it was a function and not a class. PageComponent can construct the manager and store the manager reference
PageComponent should orchestrate managers but there shouldn't be any business logic in there, move all the event listeners into the manager, you can bind your listener to the page component element instead of each individual image so that you don't have to re-apply the listeners when the content changes