-
Couldn't load subscription status.
- 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 104 commits
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
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import renderer, { act } from 'react-test-renderer'; | ||
| import MediaModal from './MediaModal'; | ||
| import React from 'react'; | ||
|
|
||
| describe('MediaModal', () => { | ||
| const mockClose = jest.fn(); | ||
|
|
||
| const renderMediaModal = (isOpen: boolean) => | ||
| renderer.create( | ||
| <MediaModal isOpen={isOpen} onClose={mockClose}> | ||
| <div>Test Content</div> | ||
| </MediaModal> | ||
| ); | ||
|
|
||
| beforeEach(() => { | ||
| mockClose.mockReset(); | ||
| }); | ||
|
|
||
| it('does not render when isOpen is false', () => { | ||
| const tree = renderMediaModal(false).toJSON(); | ||
| expect(tree).toBeNull(); | ||
| }); | ||
|
|
||
| it('renders correctly when isOpen is true', () => { | ||
| const tree = renderMediaModal(true).toJSON(); | ||
| expect(tree).toMatchSnapshot(); | ||
| }); | ||
|
|
||
| it('calls onClose when overlay is clicked', () => { | ||
| const component = renderMediaModal(true); | ||
|
|
||
| const overlay = component.root | ||
| .findAllByType('div') | ||
| .find(el => el.props.onClick === mockClose); | ||
| if (!overlay) { | ||
| throw new Error('Overlay div with onClick handler not found'); | ||
| } | ||
|
|
||
| act(() => { | ||
| overlay.props.onClick(); | ||
| }); | ||
|
|
||
| expect(mockClose).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('calls onClose when close button is clicked', () => { | ||
| const component = renderMediaModal(true); | ||
|
|
||
| const closeButton = component.root.findAllByType('button')[0]; | ||
|
|
||
| act(() => { | ||
| closeButton.props.onClick(); | ||
| }); | ||
|
|
||
| expect(mockClose).toHaveBeenCalled(); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import React from 'react'; | ||
| import styled from 'styled-components/macro'; | ||
| import ScrollLock from '../../../components/ScrollLock'; | ||
| import theme from '../../../theme'; | ||
|
|
||
| const buttonHeight = 4.2; // rem | ||
| const buttonMargin = 0.5; // rem | ||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const ScrollableContent = styled.div` | ||
| background: white; | ||
| max-width: 100vw; | ||
| max-height: calc(100vh - ${(buttonHeight + buttonMargin * 2) * 2}rem); | ||
| overflow: auto; | ||
|
|
||
| > img { | ||
| ${/* | ||
| fix ScrollableContent height issue where it is slightly larger than | ||
| the image and leaves a gap at the bottom */ ''} | ||
| display: block; | ||
| } | ||
| `; | ||
|
|
||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const FloatingCloseButton = styled.button` | ||
| position: absolute; | ||
| top: -${buttonHeight + buttonMargin}rem; | ||
| right: ${buttonMargin}rem; | ||
| z-index: 10; | ||
| background: none; | ||
| border: none; | ||
| padding: 0; | ||
| cursor: pointer; | ||
| width: ${buttonHeight}rem; | ||
| height: ${buttonHeight}rem; | ||
| `; | ||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const ContentContainer = styled.div` | ||
| position: relative; | ||
| pointer-events: auto; | ||
| `; | ||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const ModalWrapper = styled.div` | ||
| position: fixed; | ||
| inset: 0; | ||
| overflow: hidden; | ||
| z-index: ${theme.zIndex.highlightSummaryPopup + 1}; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| pointer-events: none; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The modalwrapper needs to take up the whole screen for styling purposes but it eats up click events needed for the Scrolllock. We need the click event to pass through so we can click on overlay to close the modal. |
||
| `; | ||
|
|
||
|
|
||
| // tslint:disable-next-line:variable-name | ||
| const CloseIcon = () => ( | ||
| <svg width='42' height='42' viewBox='0 0 42 42' xmlns='http://www.w3.org/2000/svg'> | ||
| <rect x='1' y='1' width='40' height='40' rx='20' stroke='white' fill='none' /> | ||
| <line x1='16' y1='16' x2='26' y2='26' stroke='white' strokeWidth='2' strokeLinecap='round' /> | ||
| <line x1='26' y1='16' x2='16' y2='26' stroke='white' strokeWidth='2' strokeLinecap='round' /> | ||
| </svg> | ||
| ); | ||
|
|
||
| interface MediaModalProps { | ||
| isOpen: boolean; | ||
| onClose: () => void; | ||
| children: React.ReactNode; | ||
| } | ||
| // tslint:disable-next-line:variable-name | ||
| const MediaModal: React.FC<MediaModalProps> = ({ isOpen, onClose, children }) => { | ||
| if (!isOpen) return null; | ||
|
|
||
| return ( | ||
| <> | ||
| <ScrollLock | ||
| onClick={onClose} | ||
| overlay={true} | ||
| zIndex={theme.zIndex.highlightSummaryPopup} | ||
| /> | ||
| <ModalWrapper aria-modal='true' role='dialog'> | ||
| <ContentContainer > | ||
| <FloatingCloseButton onClick={onClose} aria-label='Close media preview'> | ||
| <CloseIcon /> | ||
| </FloatingCloseButton> | ||
| <ScrollableContent>{children}</ScrollableContent> | ||
| </ContentContainer> | ||
| </ModalWrapper> | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| export default MediaModal; | ||
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 sorta needs to be taking up the whole screen so that it can center things properly, but its gobbling click events so clicking on the overlay isn't closing things. i think you can set a css prop on here to allow click events to pass through and that'll fix it