Skip to content

Commit 9b6057e

Browse files
authored
Merge branch 'develop' into refactor/copyable-input
2 parents 3abfd77 + d5eee45 commit 9b6057e

File tree

96 files changed

+4054
-5303
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+4054
-5303
lines changed

.storybook/preview-head.html

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/176#issuecomment-683150213
3+
window.$RefreshReg$ = () => {};
4+
window.$RefreshSig$ = () => () => {};
5+
</script>

.storybook/preview.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import React from 'react';
22
import { Provider } from 'react-redux';
3+
import { MemoryRouter } from 'react-router';
34

45
import ThemeProvider from '../client/modules/App/components/ThemeProvider';
56
import configureStore from '../client/store';
67
import '../client/i18n-test';
7-
import '../client/styles/build/css/main.css'
8+
import '../client/styles/storybook.css'
89

910
const initialState = window.__INITIAL_STATE__;
1011

@@ -13,9 +14,11 @@ const store = configureStore(initialState);
1314
export const decorators = [
1415
(Story) => (
1516
<Provider store={store}>
16-
<ThemeProvider>
17-
<Story />
18-
</ThemeProvider>
17+
<MemoryRouter>
18+
<ThemeProvider>
19+
<Story />
20+
</ThemeProvider>
21+
</MemoryRouter>
1922
</Provider>
2023
),
2124
]

client/common/ButtonOrLink.test.jsx

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { render, screen, fireEvent } from '../test-utils';
2+
import { render, screen, fireEvent, waitFor, history } from '../test-utils';
33
import ButtonOrLink from './ButtonOrLink';
44

55
describe('ButtonOrLink', () => {
@@ -25,8 +25,12 @@ describe('ButtonOrLink', () => {
2525
expect(link).toHaveAttribute('href', 'https://p5js.org');
2626
});
2727

28-
it('can render an internal link with react-router', () => {
28+
it('can render an internal link with react-router', async () => {
2929
render(<ButtonOrLink href="/about">About</ButtonOrLink>);
30-
// TODO: how can this be tested? Needs a router provider?
30+
31+
const link = screen.getByText('About');
32+
fireEvent.click(link);
33+
34+
await waitFor(() => expect(history.location.pathname).toEqual('/about'));
3135
});
3236
});

client/common/icons.jsx

+10-4
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@ import DropdownArrow from '../images/down-filled-triangle.svg';
1313
import Preferences from '../images/preferences.svg';
1414
import Play from '../images/triangle-arrow-right.svg';
1515
import More from '../images/more.svg';
16+
import Editor from '../images/editor.svg';
17+
import Account from '../images/account.svg';
1618
import Code from '../images/code.svg';
1719
import Save from '../images/save.svg';
1820
import Terminal from '../images/terminal.svg';
19-
2021
import Folder from '../images/folder-padded.svg';
21-
2222
import CircleTerminal from '../images/circle-terminal.svg';
2323
import CircleFolder from '../images/circle-folder.svg';
2424
import CircleInfo from '../images/circle-info.svg';
25+
import Add from '../images/add.svg';
26+
import Filter from '../images/filter.svg';
27+
import Cross from '../images/cross.svg';
2528

2629
// HOC that adds the right web accessibility props
2730
// https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html
@@ -83,16 +86,19 @@ export const GoogleIcon = withLabel(Google);
8386
export const PlusIcon = withLabel(Plus);
8487
export const CloseIcon = withLabel(Close);
8588
export const ExitIcon = withLabel(Exit);
89+
export const EditorIcon = withLabel(Editor);
90+
export const AccountIcon = withLabel(Account);
8691
export const DropdownArrowIcon = withLabel(DropdownArrow);
8792
export const PreferencesIcon = withLabel(Preferences);
8893
export const PlayIcon = withLabel(Play);
8994
export const MoreIcon = withLabel(More);
9095
export const TerminalIcon = withLabel(Terminal);
9196
export const CodeIcon = withLabel(Code);
9297
export const SaveIcon = withLabel(Save);
93-
9498
export const FolderIcon = withLabel(Folder);
95-
99+
export const CrossIcon = withLabel(Cross);
96100
export const CircleTerminalIcon = withLabel(CircleTerminal);
97101
export const CircleFolderIcon = withLabel(CircleFolder);
98102
export const CircleInfoIcon = withLabel(CircleInfo);
103+
export const AddIcon = withLabel(Add);
104+
export const FilterIcon = withLabel(Filter);

client/components/Nav/NavBar.jsx

+27-22
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import React, {
66
useRef,
77
useState
88
} from 'react';
9+
import useKeyDownHandlers from '../../modules/IDE/hooks/useKeyDownHandlers';
910
import { MenuOpenContext, NavBarContext } from './contexts';
1011

11-
function NavBar({ children }) {
12+
function NavBar({ children, className }) {
1213
const [dropdownOpen, setDropdownOpen] = useState('none');
1314

1415
const timerRef = useRef(null);
@@ -31,18 +32,9 @@ function NavBar({ children }) {
3132
};
3233
}, [nodeRef, setDropdownOpen]);
3334

34-
// TODO: replace with `useKeyDownHandlers` after #2052 is merged
35-
useEffect(() => {
36-
function handleKeyDown(e) {
37-
if (e.keyCode === 27) {
38-
setDropdownOpen('none');
39-
}
40-
}
41-
document.addEventListener('keydown', handleKeyDown, false);
42-
return () => {
43-
document.removeEventListener('keydown', handleKeyDown, false);
44-
};
45-
}, [setDropdownOpen]);
35+
useKeyDownHandlers({
36+
escape: () => setDropdownOpen('none')
37+
});
4638

4739
const clearHideTimeout = useCallback(() => {
4840
if (timerRef.current) {
@@ -55,6 +47,15 @@ function NavBar({ children }) {
5547
timerRef.current = setTimeout(() => setDropdownOpen('none'), 10);
5648
}, [timerRef, setDropdownOpen]);
5749

50+
const toggleDropdownOpen = useCallback(
51+
(dropdown) => {
52+
setDropdownOpen((prevState) =>
53+
prevState === dropdown ? 'none' : dropdown
54+
);
55+
},
56+
[setDropdownOpen]
57+
);
58+
5859
const contextValue = useMemo(
5960
() => ({
6061
createDropdownHandlers: (dropdown) => ({
@@ -64,31 +65,33 @@ function NavBar({ children }) {
6465
);
6566
},
6667
onClick: () => {
67-
setDropdownOpen((prevState) =>
68-
prevState === 'none' ? dropdown : 'none'
69-
);
68+
toggleDropdownOpen(dropdown);
7069
},
7170
onBlur: handleBlur,
7271
onFocus: clearHideTimeout
7372
}),
7473
createMenuItemHandlers: (dropdown) => ({
75-
onMouseUp: () => {
74+
onMouseUp: (e) => {
75+
if (e.button === 2) {
76+
return;
77+
}
7678
setDropdownOpen('none');
7779
},
7880
onBlur: handleBlur,
7981
onFocus: () => {
8082
clearHideTimeout();
8183
setDropdownOpen(dropdown);
8284
}
83-
})
85+
}),
86+
toggleDropdownOpen
8487
}),
85-
[setDropdownOpen, clearHideTimeout, handleBlur]
88+
[setDropdownOpen, toggleDropdownOpen, clearHideTimeout, handleBlur]
8689
);
8790

8891
return (
8992
<NavBarContext.Provider value={contextValue}>
9093
<header>
91-
<nav className="nav" ref={nodeRef}>
94+
<nav className={className} ref={nodeRef}>
9295
<MenuOpenContext.Provider value={dropdownOpen}>
9396
{children}
9497
</MenuOpenContext.Provider>
@@ -99,11 +102,13 @@ function NavBar({ children }) {
99102
}
100103

101104
NavBar.propTypes = {
102-
children: PropTypes.node
105+
children: PropTypes.node,
106+
className: PropTypes.string
103107
};
104108

105109
NavBar.defaultProps = {
106-
children: null
110+
children: null,
111+
className: 'nav'
107112
};
108113

109114
export default NavBar;

client/components/Nav/NavDropdownMenu.jsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, { useContext, useMemo } from 'react';
44
import TriangleIcon from '../../images/down-filled-triangle.svg';
55
import { MenuOpenContext, NavBarContext, ParentMenuContext } from './contexts';
66

7-
function NavDropdownMenu({ id, title, children }) {
7+
export function useMenuProps(id) {
88
const activeMenu = useContext(MenuOpenContext);
99

1010
const isOpen = id === activeMenu;
@@ -16,6 +16,12 @@ function NavDropdownMenu({ id, title, children }) {
1616
id
1717
]);
1818

19+
return { isOpen, handlers };
20+
}
21+
22+
function NavDropdownMenu({ id, title, children }) {
23+
const { isOpen, handlers } = useMenuProps(id);
24+
1925
return (
2026
<li className={classNames('nav__item', isOpen && 'nav__item--open')}>
2127
<button {...handlers}>

client/components/Nav/NavMenuItem.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, { useContext, useMemo } from 'react';
33
import ButtonOrLink from '../../common/ButtonOrLink';
44
import { NavBarContext, ParentMenuContext } from './contexts';
55

6-
function NavMenuItem({ hideIf, ...rest }) {
6+
function NavMenuItem({ hideIf, className, ...rest }) {
77
const parent = useContext(ParentMenuContext);
88

99
const { createMenuItemHandlers } = useContext(NavBarContext);
@@ -18,7 +18,7 @@ function NavMenuItem({ hideIf, ...rest }) {
1818
}
1919

2020
return (
21-
<li className="nav__dropdown-item">
21+
<li className={className}>
2222
<ButtonOrLink {...rest} {...handlers} />
2323
</li>
2424
);
@@ -31,13 +31,15 @@ NavMenuItem.propTypes = {
3131
/**
3232
* Provides a way to deal with optional items.
3333
*/
34-
hideIf: PropTypes.bool
34+
hideIf: PropTypes.bool,
35+
className: PropTypes.string
3536
};
3637

3738
NavMenuItem.defaultProps = {
3839
onClick: null,
3940
value: null,
40-
hideIf: false
41+
hideIf: false,
42+
className: 'nav__dropdown-item'
4143
};
4244

4345
export default NavMenuItem;

client/components/Nav/contexts.jsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ export const MenuOpenContext = createContext('none');
66

77
export const NavBarContext = createContext({
88
createDropdownHandlers: () => ({}),
9-
createMenuItemHandlers: () => ({})
9+
createMenuItemHandlers: () => ({}),
10+
toggleDropdownOpen: () => {}
1011
});

client/components/RootPage.jsx

+6
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ import { prop } from '../theme';
44
const RootPage = styled.div`
55
min-height: 100%;
66
display: flex;
7+
justify-content: start;
78
flex-direction: column;
89
color: ${prop('primaryTextColor')};
910
background-color: ${prop('backgroundColor')};
1011
height: ${({ fixedHeight }) => fixedHeight || 'initial'};
12+
13+
@media (max-width: 770px) {
14+
height: 100%;
15+
overflow: hidden;
16+
}
1117
`;
1218

1319
export default RootPage;

client/constants.js

-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ export const PROJECT_SAVE_SUCCESS = 'PROJECT_SAVE_SUCCESS';
3030
export const PROJECT_SAVE_FAIL = 'PROJECT_SAVE_FAIL';
3131
export const NEW_PROJECT = 'NEW_PROJECT';
3232
export const RESET_PROJECT = 'RESET_PROJECT';
33-
export const SHOW_EDIT_PROJECT_NAME = 'SHOW_EDIT_PROJECT_NAME';
34-
export const HIDE_EDIT_PROJECT_NAME = 'HIDE_EDIT_PROJECT_NAME';
3533

3634
export const SET_PROJECT = 'SET_PROJECT';
3735
export const SET_PROJECTS = 'SET_PROJECTS';

client/images/account.svg

+3
Loading

client/images/add.svg

+3
Loading

client/images/cross.svg

+3
Loading

client/images/editor.svg

+4
Loading

client/images/filter.svg

+3
Loading

client/images/more.svg

+3-3
Loading

client/images/plus-icon.svg

+2-11
Loading

client/index.integration.test.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ describe('index.jsx integration', () => {
5959
// spy on this function and wait for it to be called before making assertions
6060
const spy = jest.spyOn(Actions, 'getUser');
6161

62+
window.process.env.PREVIEW_URL = 'http://localhost:8002';
6263
beforeEach(async () => {
6364
act(() => {
6465
subject();

client/jest.setup.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// eslint-disable-next-line import/no-extraneous-dependencies
2+
import 'jest-styled-components';
13
import 'regenerator-runtime/runtime';
24

35
// See: https://github.com/testing-library/jest-dom

0 commit comments

Comments
 (0)