Skip to content

Commit 8da6497

Browse files
committed
♻️ create useAsModal HOC
1 parent 8339be1 commit 8da6497

File tree

3 files changed

+52
-14
lines changed

3 files changed

+52
-14
lines changed

client/components/OverlayManager.jsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { createPortal } from 'react-dom';
55
import Dropdown from './Dropdown';
66

77
import { PreferencesIcon } from '../common/icons';
8-
import { useHideOnBlur } from '../utils/custom-hooks';
8+
import { useModalBehavior } from '../utils/custom-hooks';
99

1010

1111
const OverlayManager = ({ overlay, hideOverlay }) => {
@@ -23,13 +23,14 @@ const OverlayManager = ({ overlay, hideOverlay }) => {
2323
},
2424
];
2525

26-
const setRef = useHideOnBlur(hideOverlay);
26+
// const setRef = useModalBehavior(hideOverlay);
27+
// const [visible, trigger, setRef] = useModalBehavior();
2728

2829
const jsx = (
2930
<React.Fragment>
30-
<div ref={setRef} >
31-
{overlay === 'dropdown' && <Dropdown items={headerNavOptions} />}
32-
</div>
31+
{/* <div ref={setRef} >
32+
{visible && <Dropdown items={headerNavOptions} />}
33+
</div> */}
3334
</React.Fragment>
3435
);
3536

client/modules/IDE/pages/MobileIDEView.jsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ import Footer from '../../../components/mobile/Footer';
2929
import IDEWrapper from '../../../components/mobile/IDEWrapper';
3030
import Console from '../components/Console';
3131
import { remSize } from '../../../theme';
32-
import OverlayManager from '../../../components/OverlayManager';
32+
// import OverlayManager from '../../../components/OverlayManager';
3333
import ActionStrip from '../../../components/mobile/ActionStrip';
34+
import { useAsModal } from '../../../utils/custom-hooks';
35+
import { PreferencesIcon } from '../../../common/icons';
36+
import Dropdown from '../../../components/Dropdown';
3437

3538
const isUserOwner = ({ project, user }) => (project.owner && project.owner.id === user.id);
3639

@@ -39,6 +42,20 @@ const Expander = styled.div`
3942
height: ${props => (props.expanded ? remSize(160) : remSize(27))};
4043
`;
4144

45+
const headerNavOptions = [
46+
{
47+
icon: PreferencesIcon,
48+
title: 'Preferences',
49+
href: '/mobile/preferences',
50+
},
51+
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/examples' },
52+
{
53+
icon: PreferencesIcon,
54+
title: 'Original Editor',
55+
href: '/mobile/preferences',
56+
},
57+
];
58+
4259

4360
const MobileIDEView = (props) => {
4461
const {
@@ -56,6 +73,8 @@ const MobileIDEView = (props) => {
5673
const hideOverlay = () => setOverlay(null);
5774
// const overlayRef = useRef({});
5875

76+
const [triggerNavDropdown, NavDropDown] = useAsModal(<Dropdown items={headerNavOptions} />);
77+
5978
return (
6079
<Screen fullscreen>
6180
<Header
@@ -66,7 +85,7 @@ const MobileIDEView = (props) => {
6685
}
6786
>
6887
<IconButton
69-
onClick={() => setOverlay('dropdown')}
88+
onClick={triggerNavDropdown}
7089
icon={MoreIcon}
7190
aria-label="Options"
7291
/>
@@ -114,12 +133,12 @@ const MobileIDEView = (props) => {
114133
{ide.consoleIsExpanded && <Expander expanded><Console /></Expander>}
115134
<ActionStrip />
116135
</Footer>
117-
118-
<OverlayManager
136+
<NavDropDown />
137+
{/* <OverlayManager
119138
// ref={overlayRef}
120139
overlay={overlayName}
121140
hideOverlay={hideOverlay}
122-
/>
141+
/> */}
123142
</Screen>
124143
);
125144
};

client/utils/custom-hooks.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useRef } from 'react';
1+
import React, { useEffect, useRef, useMemo, useState } from 'react';
22

33
export const noop = () => {};
44

@@ -14,13 +14,22 @@ export const useDidUpdate = (callback, deps) => {
1414
}, deps);
1515
};
1616

17-
export const useHideOnBlur = (hideOverlay) => {
17+
// Usage: const ref = useModalBehavior(() => setSomeState(false))
18+
// place this ref on a component
19+
export const useModalBehavior = (hideOverlay) => {
1820
const ref = useRef({});
21+
22+
// Return values
1923
const setRef = (r) => { ref.current = r; };
24+
const [visible, setVisible] = useState(true);
25+
const trigger = () => setVisible(true);
26+
27+
const hide = () => setVisible(false);
28+
2029

2130
const handleClickOutside = ({ target }) => {
2231
if (ref && ref.current && !ref.current.contains(target)) {
23-
hideOverlay();
32+
hide();
2433
}
2534
};
2635

@@ -29,5 +38,14 @@ export const useHideOnBlur = (hideOverlay) => {
2938
return () => document.removeEventListener('mousedown', handleClickOutside);
3039
}, [ref]);
3140

32-
return setRef;
41+
return [visible, trigger, setRef];
42+
};
43+
44+
// TODO: This is HOC, not a hook. Where do we put it?
45+
export const useAsModal = (component) => {
46+
const [visible, trigger, setRef] = useModalBehavior();
47+
48+
const wrapper = () => (<div ref={setRef}> {visible && component} </div>); // eslint-disable-line
49+
50+
return [trigger, wrapper];
3351
};

0 commit comments

Comments
 (0)