Skip to content

Refactor mobile components to react hooks #1507

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
89ffa41
:recycle: create option creators, improve header transparency
ghalestrilo Jul 3, 2020
1c4b234
:recycle: refactor <MobileSketchView />
ghalestrilo Jul 17, 2020
88d7f9e
Merge branch 'develop' of https://github.com/processing/p5.js-web-edi…
ghalestrilo Jul 17, 2020
f349199
Merge branch 'feature/mobile-preferences-number-widget' into chore/re…
ghalestrilo Jul 17, 2020
3a596ec
:recycle: refactor <MobilePreferences />, create PreferenceCreators
ghalestrilo Jul 17, 2020
b87a313
:recycle: refactor <MobilePreferences /> to use hooks
ghalestrilo Jul 17, 2020
d3f7d3d
:recycle: refactor <Console /> to use hooks
ghalestrilo Jul 17, 2020
9447bb5
:recycle: remove getConsoleFeedStyle from Console
ghalestrilo Jul 17, 2020
b0565a2
Merge branch 'chore/upgrade-react-redux' into chore/refactor-mobile-h…
ghalestrilo Jul 17, 2020
9e95517
:construction: refactor <Consle /> to hooks
ghalestrilo Jul 20, 2020
627cfbf
Merge branch 'develop' of https://github.com/processing/p5.js-web-edi…
ghalestrilo Jul 20, 2020
234c4ff
:bug: fix broken useState
ghalestrilo Jul 20, 2020
928595c
Merge branch 'feature/error-output' into chore/refactor-mobile-hooks
ghalestrilo Jul 20, 2020
556c9d1
:bug: fix console not opening/closing
ghalestrilo Jul 20, 2020
24a26c1
:broom: remove needless imports
ghalestrilo Jul 20, 2020
604add5
:broom: remove FIXME
ghalestrilo Jul 20, 2020
4ac8fa0
:sparkles: make console-expanding button on bottom bar
ghalestrilo Jul 21, 2020
db5d853
:sparkles: add console-opening button on bottom bar
ghalestrilo Jul 21, 2020
c9a4d6e
:broom: remove needless imports
ghalestrilo Jul 21, 2020
482b1d9
:ok_hand: restore original code icon
ghalestrilo Jul 21, 2020
3f01fc4
Merge branch 'develop' of https://github.com/processing/p5.js-web-edi…
ghalestrilo Jul 21, 2020
f3bedb0
:ok_hand: make console button toggle between collapse and expand
ghalestrilo Jul 21, 2020
ccbe96d
:truck: move preferences creators to components/Preferences
ghalestrilo Jul 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/common/icons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import Exit from '../images/exit.svg';
import DropdownArrow from '../images/down-filled-triangle.svg';
import Preferences from '../images/preferences.svg';
import Play from '../images/triangle-arrow-right.svg';
import Code from '../images/code.svg';
import Terminal from '../images/terminal.svg';


// HOC that adds the right web accessibility props
// https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html
Expand Down Expand Up @@ -74,3 +77,4 @@ export const ExitIcon = withLabel(Exit);
export const DropdownArrowIcon = withLabel(DropdownArrow);
export const PreferencesIcon = withLabel(Preferences);
export const PlayIcon = withLabel(Play);
export const TerminalIcon = withLabel(Terminal);
35 changes: 35 additions & 0 deletions client/components/mobile/ActionStrip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import styled from 'styled-components';
import { bindActionCreators } from 'redux';
import { useDispatch, useSelector } from 'react-redux';
import { remSize } from '../../theme';
import IconButton from './IconButton';
import { TerminalIcon } from '../../common/icons';
import * as IDEActions from '../../modules/IDE/actions/ide';

const BottomBarContent = styled.h2`
padding: ${remSize(8)};

svg {
max-height: ${remSize(32)};
}
`;

export default () => {
const { expandConsole, collapseConsole } = bindActionCreators(IDEActions, useDispatch());
const { consoleIsExpanded } = useSelector(state => state.ide);

const actions = [{ icon: TerminalIcon, aria: 'Say Something', action: consoleIsExpanded ? collapseConsole : expandConsole }];

return (
<BottomBarContent>
{actions.map(({ icon, aria, action }) =>
(<IconButton
icon={icon}
aria-label={aria}
key={`bottom-bar-${aria}`}
onClick={() => action()}
/>))}
</BottomBarContent>
);
};
4 changes: 3 additions & 1 deletion client/components/mobile/Footer.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import { prop } from '../../theme';
import { prop, grays } from '../../theme';


const background = prop('MobilePanel.default.background');
Expand All @@ -12,4 +12,6 @@ export default styled.div`
bottom: 0;
background: ${background};
color: ${textColor};

& > * + * { border-top: dashed 1px ${prop('Separator')} }
`;
5 changes: 2 additions & 3 deletions client/components/mobile/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import styled from 'styled-components';
import PropTypes from 'prop-types';
import { prop, remSize } from '../../theme';

const background = prop('MobilePanel.default.background');
const background = transparent => prop(transparent ? 'backgroundColor' : 'MobilePanel.default.background');
const textColor = prop('primaryTextColor');


const HeaderDiv = styled.div`
position: fixed;
width: 100%;
background: ${props => (props.transparent ? 'transparent' : background)};
background: ${props => background(props.transparent === true)};
color: ${textColor};
padding: ${remSize(12)};
padding-left: ${remSize(16)};
Expand All @@ -23,7 +23,6 @@ const HeaderDiv = styled.div`
justify-content: flex-start;
align-items: center;

// TODO:
svg {
max-height: ${remSize(32)};
padding: ${remSize(4)}
Expand Down
5 changes: 5 additions & 0 deletions client/images/terminal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
258 changes: 103 additions & 155 deletions client/modules/IDE/components/Console.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import { useSelector, useDispatch, connect } from 'react-redux';
import React, { useRef } from 'react';

import { bindActionCreators } from 'redux';

import { useSelector, useDispatch } from 'react-redux';
import classNames from 'classnames';
import { Console as ConsoleFeed } from 'console-feed';
import {
Expand All @@ -25,172 +27,118 @@ import DownArrowIcon from '../../../images/down-arrow.svg';

import * as IDEActions from '../../IDE/actions/ide';
import * as ConsoleActions from '../../IDE/actions/console';
import { useDidUpdate } from '../../../utils/custom-hooks';

class ConsoleComponent extends React.Component {
componentDidUpdate(prevProps) {
this.consoleMessages.scrollTop = this.consoleMessages.scrollHeight;
if (this.props.theme !== prevProps.theme) {
this.props.clearConsole();
this.props.dispatchConsoleEvent(this.props.consoleEvents);
}

if (this.props.fontSize !== prevProps.fontSize) {
this.props.clearConsole();
this.props.dispatchConsoleEvent(this.props.consoleEvents);
}
}

getConsoleFeedStyle(theme, times) {
const style = {};
const CONSOLE_FEED_LIGHT_ICONS = {
LOG_WARN_ICON: `url(${warnLightUrl})`,
LOG_ERROR_ICON: `url(${errorLightUrl})`,
LOG_DEBUG_ICON: `url(${debugLightUrl})`,
LOG_INFO_ICON: `url(${infoLightUrl})`
};
const CONSOLE_FEED_DARK_ICONS = {
LOG_WARN_ICON: `url(${warnDarkUrl})`,
LOG_ERROR_ICON: `url(${errorDarkUrl})`,
LOG_DEBUG_ICON: `url(${debugDarkUrl})`,
LOG_INFO_ICON: `url(${infoDarkUrl})`
};
const CONSOLE_FEED_CONTRAST_ICONS = {
LOG_WARN_ICON: `url(${warnContrastUrl})`,
LOG_ERROR_ICON: `url(${errorContrastUrl})`,
LOG_DEBUG_ICON: `url(${debugContrastUrl})`,
LOG_INFO_ICON: `url(${infoContrastUrl})`
};
const CONSOLE_FEED_SIZES = {
TREENODE_LINE_HEIGHT: 1.2,
BASE_FONT_SIZE: this.props.fontSize,
ARROW_FONT_SIZE: this.props.fontSize,
LOG_ICON_WIDTH: this.props.fontSize,
LOG_ICON_HEIGHT: 1.45 * this.props.fontSize,
};
const getConsoleFeedStyle = (theme, times, fontSize) => {
const style = {};
const CONSOLE_FEED_LIGHT_ICONS = {
LOG_WARN_ICON: `url(${warnLightUrl})`,
LOG_ERROR_ICON: `url(${errorLightUrl})`,
LOG_DEBUG_ICON: `url(${debugLightUrl})`,
LOG_INFO_ICON: `url(${infoLightUrl})`
};
const CONSOLE_FEED_DARK_ICONS = {
LOG_WARN_ICON: `url(${warnDarkUrl})`,
LOG_ERROR_ICON: `url(${errorDarkUrl})`,
LOG_DEBUG_ICON: `url(${debugDarkUrl})`,
LOG_INFO_ICON: `url(${infoDarkUrl})`
};
const CONSOLE_FEED_CONTRAST_ICONS = {
LOG_WARN_ICON: `url(${warnContrastUrl})`,
LOG_ERROR_ICON: `url(${errorContrastUrl})`,
LOG_DEBUG_ICON: `url(${debugContrastUrl})`,
LOG_INFO_ICON: `url(${infoContrastUrl})`
};
const CONSOLE_FEED_SIZES = {
TREENODE_LINE_HEIGHT: 1.2,
BASE_FONT_SIZE: fontSize,
ARROW_FONT_SIZE: fontSize,
LOG_ICON_WIDTH: fontSize,
LOG_ICON_HEIGHT: 1.45 * fontSize,
};

if (times > 1) {
Object.assign(style, CONSOLE_FEED_WITHOUT_ICONS);
}
switch (theme) {
case 'light':
return Object.assign(CONSOLE_FEED_LIGHT_STYLES, CONSOLE_FEED_LIGHT_ICONS, CONSOLE_FEED_SIZES, style);
case 'dark':
return Object.assign(CONSOLE_FEED_DARK_STYLES, CONSOLE_FEED_DARK_ICONS, CONSOLE_FEED_SIZES, style);
case 'contrast':
return Object.assign(CONSOLE_FEED_CONTRAST_STYLES, CONSOLE_FEED_CONTRAST_ICONS, CONSOLE_FEED_SIZES, style);
default:
return '';
}
if (times > 1) {
Object.assign(style, CONSOLE_FEED_WITHOUT_ICONS);
}

render() {
const consoleClass = classNames({
'preview-console': true,
'preview-console--collapsed': !this.props.isExpanded
});

return (
<section className={consoleClass} >
<header className="preview-console__header">
<h2 className="preview-console__header-title">Console</h2>
<div className="preview-console__header-buttons">
<button className="preview-console__clear" onClick={this.props.clearConsole} aria-label="Clear console">
Clear
</button>
<button
className="preview-console__collapse"
onClick={this.props.collapseConsole}
aria-label="Close console"
>
<DownArrowIcon focusable="false" aria-hidden="true" />
</button>
<button className="preview-console__expand" onClick={this.props.expandConsole} aria-label="Open console" >
<UpArrowIcon focusable="false" aria-hidden="true" />
</button>
</div>
</header>
<div ref={(element) => { this.consoleMessages = element; }} className="preview-console__messages">
{this.props.consoleEvents.map((consoleEvent) => {
const { method, times } = consoleEvent;
const { theme } = this.props;
return (
<div key={consoleEvent.id} className={`preview-console__message preview-console__message--${method}`}>
{ times > 1 &&
<div
className="preview-console__logged-times"
style={{ fontSize: this.props.fontSize, borderRadius: this.props.fontSize / 2 }}
>
{times}
</div>
}
<ConsoleFeed
styles={this.getConsoleFeedStyle(theme, times)}
logs={[consoleEvent]}
/>
</div>
);
})}
</div>
</section>
);
switch (theme) {
case 'light':
return Object.assign(CONSOLE_FEED_LIGHT_STYLES, CONSOLE_FEED_LIGHT_ICONS, CONSOLE_FEED_SIZES, style);
case 'dark':
return Object.assign(CONSOLE_FEED_DARK_STYLES, CONSOLE_FEED_DARK_ICONS, CONSOLE_FEED_SIZES, style);
case 'contrast':
return Object.assign(CONSOLE_FEED_CONTRAST_STYLES, CONSOLE_FEED_CONTRAST_ICONS, CONSOLE_FEED_SIZES, style);
default:
return '';
}
}

ConsoleComponent.propTypes = {
consoleEvents: PropTypes.arrayOf(PropTypes.shape({
method: PropTypes.string.isRequired,
args: PropTypes.arrayOf(PropTypes.string)
})),
isExpanded: PropTypes.bool.isRequired,
collapseConsole: PropTypes.func.isRequired,
expandConsole: PropTypes.func.isRequired,
clearConsole: PropTypes.func.isRequired,
dispatchConsoleEvent: PropTypes.func.isRequired,
theme: PropTypes.string.isRequired,
fontSize: PropTypes.number.isRequired
};

ConsoleComponent.defaultProps = {
consoleEvents: []
};

// TODO: Use Hooks implementation. Requires react-redux 7.1.0
/*
const Console = () => {
const consoleEvents = useSelector(state => state.console);
const { consoleIsExpanded } = useSelector(state => state.ide);
const isExpanded = useSelector(state => state.ide.consoleIsExpanded);
const { theme, fontSize } = useSelector(state => state.preferences);

const dispatch = useDispatch();
const {
collapseConsole, expandConsole, clearConsole, dispatchConsoleEvent
} = bindActionCreators({ ...IDEActions, ...ConsoleActions }, useDispatch());

useDidUpdate(() => {
clearConsole();
dispatchConsoleEvent(consoleEvents);
}, [theme, fontSize]);

const cm = useRef({});

useDidUpdate(() => { cm.current.scrollTop = cm.current.scrollHeight; });

const consoleClass = classNames({
'preview-console': true,
'preview-console--collapsed': !isExpanded
});

return (
<ConsoleComponent
consoleEvents={consoleEvents}
isExpanded={consoleIsExpanded}
theme={theme}
fontSize={fontSize}
collapseConsole={() => dispatch({})}
expandConsole={() => dispatch({})}
clearConsole={() => dispatch({})}
dispatchConsoleEvent={() => dispatch({})}
/>
<section className={consoleClass} >
<header className="preview-console__header">
<h2 className="preview-console__header-title">Console</h2>
<div className="preview-console__header-buttons">
<button className="preview-console__clear" onClick={clearConsole} aria-label="Clear console">
Clear
</button>
<button
className="preview-console__collapse"
onClick={collapseConsole}
aria-label="Close console"
>
<DownArrowIcon focusable="false" aria-hidden="true" />
</button>
<button className="preview-console__expand" onClick={expandConsole} aria-label="Open console" >
<UpArrowIcon focusable="false" aria-hidden="true" />
</button>
</div>
</header>
<div ref={cm} className="preview-console__messages">
{consoleEvents.map((consoleEvent) => {
const { method, times } = consoleEvent;
return (
<div key={consoleEvent.id} className={`preview-console__message preview-console__message--${method}`}>
{ times > 1 &&
<div
className="preview-console__logged-times"
style={{ fontSize, borderRadius: fontSize / 2 }}
>
{times}
</div>
}
<ConsoleFeed
styles={getConsoleFeedStyle(theme, times, fontSize)}
logs={[consoleEvent]}
/>
</div>
);
})}
</div>
</section>
);
};
*/

const Console = connect(
state => ({
consoleEvents: state.console,
isExpanded: state.ide.consoleIsExpanded,
theme: state.preferences.theme,
fontSize: state.preferences.fontSize
}),
dispatch => ({
collapseConsole: () => dispatch(IDEActions.collapseConsole()),
expandConsole: () => dispatch(IDEActions.expandConsole()),
clearConsole: () => dispatch(ConsoleActions.clearConsole()),
dispatchConsoleEvent: msgs => dispatch(ConsoleActions.dispatchConsoleEvent(msgs)),
})
)(ConsoleComponent);

export default Console;
Loading