⚗️ create <OverlayManager /> component

This commit is contained in:
ghalestrilo 2020-07-22 18:48:24 -03:00
parent c58cdc29c3
commit 371e4ccdde
3 changed files with 57 additions and 129 deletions

View file

@ -6,119 +6,20 @@ import { remSize, prop, common } from '../theme';
import IconButton from './mobile/IconButton'; import IconButton from './mobile/IconButton';
import Button from '../common/Button'; import Button from '../common/Button';
// <ul className="nav__dropdown">
// <ul className="nav__dropdown">
// <li className="nav__dropdown-item">
// <button
// onFocus={this.handleFocusForLang}
// onBlur={this.handleBlur}
// value="it"
// onClick={e => this.handleLangSelection(e)}
// >
// Italian (Test Fallback)
// </button>
// </li>
// <li className="nav__dropdown-item">
// <button
// onFocus={this.handleFocusForLang}
// onBlur={this.handleBlur}
// value="en-US"
// onClick={e => this.handleLangSelection(e)}
// >English
// </button>
// </li>
// <li className="nav__dropdown-item">
// <button
// onFocus={this.handleFocusForLang}
// onBlur={this.handleBlur}
// value="es-419"
// onClick={e => this.handleLangSelection(e)}
// >
// Español
// </button>
// </li>
// </ul>
// 'nav__item--open'
// %dropdown-open {
// @include themify() {
// background-color: map-get($theme-map, 'modal-background-color');
// border: 1px solid map-get($theme-map, 'modal-border-color');
// box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color');
// color: getThemifyVariable('primary-text-color');
// }
// text-align: left;
// width: ${remSize(180)};
// display: flex;
// position: absolute;
// flex-direction: column;
// top: 95%;
// height: auto;
// z-index: 9999;
// border-radius: ${remSize(6)};
// & li:first-child {
// border-radius: ${remSize(5)} ${remSize(5)} 0 0;
// }
// & li:last-child {
// border-radius: 0 0 ${remSize(5)} ${remSize(5)};
// }
// -------------
// & li {
// & button,
// & a {
// @include themify() {
// color: getThemifyVariable('primary-text-color');
// }
// width: 100%;
// text-align: left;
// padding: ${remSize(8)} ${remSize(16)};
// }
// height: ${remSize(35)};
// cursor: pointer;
// display: flex;
// align-items: center;
// }
// & li:hover {
// @include themify() {
// background-color: getThemifyVariable('button-background-hover-color');
// color: getThemifyVariable('button-hover-color')
// }
// & button, & a {
// @include themify() {
// color: getThemifyVariable('button-hover-color');
// }
// }
// }
// }
// %dropdown-open-left {
// @extend %dropdown-open;
// left: 0;
// }
// %dropdown-open-right {
// @extend %dropdown-open;
// right: 0;
// }
const DropdownWrapper = styled.ul` const DropdownWrapper = styled.ul`
background-color: ${prop('Modal.background')}; background-color: ${prop('Modal.background')};
border: 1px solid ${prop('Modal.border')}; border: 1px solid ${prop('Modal.border')};
box-shadow: 0 0 18px 0 ${prop('shadowColor')}; box-shadow: 0 0 18px 0 ${prop('shadowColor')};
color: ${prop('primaryTextColor')}; color: ${prop('primaryTextColor')};
position: absolute;
top: ${remSize(64)};
right: ${remSize(16)};
text-align: left; text-align: left;
width: ${remSize(180)}; width: ${remSize(180)};
display: flex; display: flex;
position: absolute;
flex-direction: column; flex-direction: column;
top: 95%;
height: auto; height: auto;
z-index: 9999; z-index: 9999;
border-radius: ${remSize(6)}; border-radius: ${remSize(6)};
@ -150,14 +51,10 @@ const DropdownWrapper = styled.ul`
padding: ${remSize(8)} ${remSize(16)}; padding: ${remSize(8)} ${remSize(16)};
} }
} }
`; `;
// { onPress // TODO: Add Icon to the left of the items in the menu
// ? <IconButton // const MaybeIcon = (Element, label) => Element && <Element aria-label={label} />;
// : <Link to={to}>{title}</Link>}
const MaybeIcon = (Element, label) => Element && <Element aria-label={label} />;
const Dropdown = ({ items }) => ( const Dropdown = ({ items }) => (
<DropdownWrapper> <DropdownWrapper>
@ -165,7 +62,7 @@ const Dropdown = ({ items }) => (
{items && items.map(({ title, icon, href }) => ( {items && items.map(({ title, icon, href }) => (
<li key={`nav-${title && title.toLowerCase()}`}> <li key={`nav-${title && title.toLowerCase()}`}>
<Link to={href}> <Link to={href}>
{MaybeIcon(icon, `Navigate to ${title}`)} {/* {MaybeIcon(icon, `Navigate to ${title}`)} */}
{title} {title}
</Link> </Link>
</li> </li>

View file

@ -34,7 +34,8 @@ class App extends React.Component {
render() { render() {
return ( return (
<div className="app"> <div className="app">
{this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && <DevTools />} {/* FIXME: Remove && false */}
{false && this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && <DevTools />}
{this.props.children} {this.props.children}
</div> </div>
); );

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
@ -42,6 +42,42 @@ const BottomBarContent = styled.h2`
// const overlays = {}; // const overlays = {};
// const OverlayManager = name => overlays[name] || null; // const OverlayManager = name => overlays[name] || null;
const OverlayManager = ({ ref, overlay, hideOverlay }) => {
useEffect(() => {
const handleClickOutside = ({ target }) => {
if (ref && ref.current && !ref.current.contains(target)) { hideOverlay(); console.log('click'); }
};
document.addEventListener('mousedown', handleClickOutside);
return () => { document.removeEventListener('mousedown', handleClickOutside); };
}, [ref]);
const headerNavOptions = [
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences' },
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/examples' },
{ icon: PreferencesIcon, title: 'Original View', href: '/mobile/preferences' }
];
return (
<div ref={(r) => { if (ref) { ref.current = r; } }}>
{(overlay === 'dropdown') && <Dropdown items={headerNavOptions} />}
</div>
);
};
const refPropType = PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({ current: PropTypes.instanceOf(Element) })
]);
OverlayManager.propTypes = {
ref: refPropType.isRequired,
overlay: PropTypes.string,
hideOverlay: PropTypes.func.isRequired
};
OverlayManager.defaultProps = { overlay: null };
const MobileIDEView = (props) => { const MobileIDEView = (props) => {
const { const {
@ -53,18 +89,15 @@ const MobileIDEView = (props) => {
} = props; } = props;
const [tmController, setTmController] = useState(null); // eslint-disable-line const [tmController, setTmController] = useState(null); // eslint-disable-line
const [overlay, setOverlay] = useState(null); // eslint-disable-line const [overlayName, setOverlay] = useState(null); // eslint-disable-line
// const overlayActive = name => (overlay === name); // TODO: Move this to OverlayController (?)
const hideOverlay = () => setOverlay(null);
const overlayRef = useRef();
const headerNavOptions = [
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences' },
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/examples' },
{ icon: PreferencesIcon, title: 'Original View', href: '/mobile/preferences' }
];
return ( return (
<Screen fullscreen> <Screen fullscreen >
<Header <Header
title={project.name} title={project.name}
subtitle={selectedFile.name} subtitle={selectedFile.name}
@ -81,10 +114,6 @@ const MobileIDEView = (props) => {
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" /> <IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
</Header> </Header>
{/* TODO: Overlays */}
<Dropdown items={headerNavOptions} />
<IDEWrapper> <IDEWrapper>
<Editor <Editor
lintWarning={preferences.lintWarning} lintWarning={preferences.lintWarning}
@ -122,11 +151,12 @@ const MobileIDEView = (props) => {
/> />
</IDEWrapper> </IDEWrapper>
{/* {/* TODO: Create Overlay Manager */}
<Footer> {<OverlayManager
<Console /> ref={overlayRef}
<BottomBarContent>Bottom Bar</BottomBarContent> overlay={overlayName}
</Footer> */} hideOverlay={hideOverlay}
/>}
</Screen> </Screen>
); );
}; };