Skip to content

Commit e82dc82

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into aviroopjana/fix-collection-list
# Conflicts: # client/modules/IDE/components/CollectionList/CollectionListRow.jsx
2 parents a7830e5 + f21b847 commit e82dc82

File tree

130 files changed

+2300
-3049
lines changed

Some content is hidden

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

130 files changed

+2300
-3049
lines changed

.env.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ MAILGUN_KEY=<your-mailgun-api-key>
1919
ML5_LIBRARY_USERNAME=ml5
2020
ML5_LIBRARY_EMAIL=examples@ml5js.org
2121
ML5_LIBRARY_PASS=helloml5
22-
MOBILE_ENABLED=true
2322
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
2423
PORT=8000
2524
PREVIEW_PORT=8002

README.md

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,10 @@ The p5.js Editor is a collaborative project created by many individuals, mostly
1212

1313
Learn more about [our community](https://p5js.org/community/) and read our community statement and [code of conduct](./.github/CODE_OF_CONDUCT.md). You can directly support our work with p5.js by [donating to the Processing Foundation](https://processingfoundation.org/support).
1414

15-
## Get Started
15+
## Getting Started
1616

1717
Make your first sketch in the [p5.js Editor](https://editor.p5js.org/)! Learn more about sketching with p5.js on the [Get Started](https://p5js.org/get-started/) and find everything you can do in the [Reference](https://p5js.org/reference/). You can also look at [examples](https://editor.p5js.org/p5/sketches) and remix them in the p5.js Editor.
1818

19-
## Setting Up the Development Environment
20-
21-
- Refer to [this documentation for setting up your environment](https://github.com/processing/p5.js-web-editor/blob/develop/contributor_docs/installation.md)
22-
23-
2419

2520
## Issues
2621

@@ -31,10 +26,43 @@ If you have found a bug in the p5.js Web Editor, you can file it under the ["iss
3126
* p5.sound: [https://github.com/processing/p5.js-sound/issues](https://github.com/processing/p5.js-sound/issues)
3227
* p5.js website: [https://github.com/processing/p5.js-website/issues](https://github.com/processing/p5.js-website/issues)
3328

29+
30+
### How Do I Know My Issue or Pull Request is Getting Reviewed?
31+
32+
To see which pull requests and issues are currently being reviewed, check the [PR Review Board](https://github.com/processing/p5.js-web-editor/projects/9) or the following Milestones: [MINOR Release](https://github.com/processing/p5.js-web-editor/milestone/8).
33+
34+
Issues and Pull Requests categorized under the PATCH or MINOR Release Milestones will be prioritized since they are planned to be merged for the next release to Production. Please feel free to [comment on this pinned issue](https://github.com/processing/p5.js-web-editor/issues/2534) if you would like your issue to be considered for the next release!
35+
36+
37+
### When Will the Next Production Release Be?
38+
39+
We will aim to deploy on a 1-2 month basis. Here are some dates we’re working towards:
40+
41+
2.11.0 MINOR Release: By December 22, 2023
42+
43+
[You can read more about Semantic Versioning and the differences between a MINOR and PATCH release](https://semver.org/).
44+
45+
46+
## References for Contributing to the p5.js Web Editor
47+
48+
[Code of Conduct](https://editor.p5js.org/code-of-conduct)
49+
50+
[Contribution Guidelines for p5.js](https://p5js.org/contributor-docs/#/)
51+
52+
[Contribution Guidelines for the p5.js Web Editor](https://github.com/processing/p5.js-web-editor/tree/develop/contributor_docs)
53+
54+
[p5.js Community Statement](https://p5js.org/community/)
55+
56+
3457
## Acknowledgements
3558

3659
Support for this project has come from [Processing Foundation](https://processingfoundation.org/), [NYU ITP](https://tisch.nyu.edu/itp), [CS4All, NYC DOE](http://cs4all.nyc/), [COSA at DU](https://liberalarts.du.edu/emergent-digital-practices/open-source-arts), [STUDIO for Creative Inquiry](https://studioforcreativeinquiry.org/), [Grant for the Web](https://www.grantfortheweb.org/), [New Media Rights](https://www.newmediarights.org/), and many others.
3760

38-
Hosting and technical support has come from: <br />
39-
<a href="https://releasehub.com/" target="_blank"><img width="100" src="https://assets.website-files.com/603dd147c5b0a480611bd348/603dd147c5b0a469bc1bd451_logo--dark.svg" /></a>
61+
Hosting and technical support has come from:
62+
<br />
63+
<br />
64+
<a href="https://releasehub.com/" target="_blank"><img width="100" src="https://assets.website-files.com/603dd147c5b0a480611bd348/603dd147c5b0a469bc1bd451_logo--dark.svg" /></a>
65+
<br />
4066
<a href="https://www.browserstack.com/" target="_blank"><img width="100" src="https://user-images.githubusercontent.com/6063380/46976166-ab280a80-d096-11e8-983b-18dd38c8cc9b.png" /></a>
67+
<br />
68+
<a href="https://www.fastly.com/" target="_blank"><img width="100" src="https://cdn-assets-us.frontify.com/s3/frontify-enterprise-files-us/eyJwYXRoIjoiZmFzdGx5XC9hY2NvdW50c1wvYzJcLzQwMDEwMjNcL3Byb2plY3RzXC8xMVwvYXNzZXRzXC80ZVwvNzc0XC9lZTZmYzlkOWYzNWE1NjBkNjUzNjFkNGI0NGQ2MTNmZi0xNjIxNTIyODg4LnBuZyJ9:fastly:nVuY3PxyFqQMI6elJsMzxAGLH3IFlmiuMdacHAGRMkE?width=2400" /></a>

client/components/mobile/IconButton.jsx renamed to client/common/IconButton.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import styled from 'styled-components';
4-
import Button from '../../common/Button';
5-
import { remSize } from '../../theme';
4+
import Button from './Button';
5+
import { remSize } from '../theme';
66

77
const ButtonWrapper = styled(Button)`
88
width: ${remSize(48)};

client/common/RouterTab.jsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import PropTypes from 'prop-types';
2+
import React from 'react';
3+
import { NavLink } from 'react-router-dom';
4+
5+
/**
6+
* Wraps the react-router `NavLink` with dashboard-header__tab styling.
7+
*/
8+
const Tab = ({ children, to }) => (
9+
<li className="dashboard-header__tab">
10+
<NavLink
11+
className="dashboard-header__tab__title"
12+
activeClassName="dashboard-header__tab--selected"
13+
to={{ pathname: to, state: { skipSavingPath: true } }}
14+
>
15+
{children}
16+
</NavLink>
17+
</li>
18+
);
19+
20+
Tab.propTypes = {
21+
children: PropTypes.string.isRequired,
22+
to: PropTypes.string.isRequired
23+
};
24+
25+
export default Tab;

client/modules/IDE/hooks/useKeyDownHandlers.js renamed to client/common/useKeyDownHandlers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import mapKeys from 'lodash/mapKeys';
1+
import { mapKeys } from 'lodash';
22
import PropTypes from 'prop-types';
33
import { useCallback, useEffect, useRef } from 'react';
44

client/common/useModalClose.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect, useRef } from 'react';
2+
import useKeyDownHandlers from './useKeyDownHandlers';
3+
4+
/**
5+
* Common logic for Modal, Overlay, etc.
6+
*
7+
* Pass in the `onClose` handler.
8+
*
9+
* Can optionally pass in a ref, in case the `onClose` function needs to use the ref.
10+
*
11+
* Calls the provided `onClose` function on:
12+
* - Press Escape key.
13+
* - Click outside the element.
14+
*
15+
* Returns a ref to attach to the outermost element of the modal.
16+
*
17+
* @param {() => void} onClose
18+
* @param {React.MutableRefObject<HTMLElement | null>} [passedRef]
19+
* @return {React.MutableRefObject<HTMLElement | null>}
20+
*/
21+
export default function useModalClose(onClose, passedRef) {
22+
const createdRef = useRef(null);
23+
const modalRef = passedRef || createdRef;
24+
25+
useEffect(() => {
26+
modalRef.current?.focus();
27+
28+
function handleClick(e) {
29+
// ignore clicks on the component itself
30+
if (modalRef.current && !modalRef.current.contains(e.target)) {
31+
onClose?.();
32+
}
33+
}
34+
35+
document.addEventListener('click', handleClick, false);
36+
37+
return () => {
38+
document.removeEventListener('click', handleClick, false);
39+
};
40+
}, [onClose, modalRef]);
41+
42+
useKeyDownHandlers({ escape: onClose });
43+
44+
return modalRef;
45+
}

client/components/Dropdown.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import styled from 'styled-components';
44
import { remSize, prop } from '../theme';
5-
import IconButton from './mobile/IconButton';
5+
import IconButton from '../common/IconButton';
66

7-
const DropdownWrapper = styled.ul`
7+
export const DropdownWrapper = styled.ul`
88
background-color: ${prop('Modal.background')};
99
border: 1px solid ${prop('Modal.border')};
1010
box-shadow: 0 0 18px 0 ${prop('shadowColor')};
@@ -52,6 +52,7 @@ const DropdownWrapper = styled.ul`
5252
& button span,
5353
& a {
5454
padding: ${remSize(8)} ${remSize(16)};
55+
font-size: ${remSize(12)};
5556
}
5657
5758
* {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import PropTypes from 'prop-types';
2+
import React, { forwardRef, useCallback, useRef, useState } from 'react';
3+
import useModalClose from '../../common/useModalClose';
4+
import DownArrowIcon from '../../images/down-filled-triangle.svg';
5+
import { DropdownWrapper } from '../Dropdown';
6+
7+
// TODO: enable arrow keys to navigate options from list
8+
9+
const DropdownMenu = forwardRef(
10+
(
11+
{ children, anchor, 'aria-label': ariaLabel, align, className, classes },
12+
ref
13+
) => {
14+
// Note: need to use a ref instead of a state to avoid stale closures.
15+
const focusedRef = useRef(false);
16+
17+
const [isOpen, setIsOpen] = useState(false);
18+
19+
const close = useCallback(() => setIsOpen(false), [setIsOpen]);
20+
21+
const anchorRef = useModalClose(close, ref);
22+
23+
const toggle = useCallback(() => {
24+
setIsOpen((prevState) => !prevState);
25+
}, [setIsOpen]);
26+
27+
const handleFocus = () => {
28+
focusedRef.current = true;
29+
};
30+
31+
const handleBlur = () => {
32+
focusedRef.current = false;
33+
setTimeout(() => {
34+
if (!focusedRef.current) {
35+
close();
36+
}
37+
}, 200);
38+
};
39+
40+
return (
41+
<div ref={anchorRef} className={className}>
42+
<button
43+
className={classes.button}
44+
aria-label={ariaLabel}
45+
tabIndex="0"
46+
onClick={toggle}
47+
onBlur={handleBlur}
48+
onFocus={handleFocus}
49+
>
50+
{anchor ?? <DownArrowIcon focusable="false" aria-hidden="true" />}
51+
</button>
52+
{isOpen && (
53+
<DropdownWrapper
54+
className={classes.list}
55+
align={align}
56+
onMouseUp={() => {
57+
setTimeout(close, 0);
58+
}}
59+
onBlur={handleBlur}
60+
onFocus={handleFocus}
61+
>
62+
{children}
63+
</DropdownWrapper>
64+
)}
65+
</div>
66+
);
67+
}
68+
);
69+
70+
DropdownMenu.propTypes = {
71+
/**
72+
* Provide <MenuItem> elements as children to control the contents of the menu.
73+
*/
74+
children: PropTypes.node.isRequired,
75+
/**
76+
* Can optionally override the contents of the button which opens the menu.
77+
* Defaults to <DownArrowIcon>
78+
*/
79+
anchor: PropTypes.node,
80+
'aria-label': PropTypes.string.isRequired,
81+
align: PropTypes.oneOf(['left', 'right']),
82+
className: PropTypes.string,
83+
classes: PropTypes.shape({
84+
button: PropTypes.string,
85+
list: PropTypes.string
86+
})
87+
};
88+
89+
DropdownMenu.defaultProps = {
90+
anchor: null,
91+
align: 'right',
92+
className: '',
93+
classes: {}
94+
};
95+
96+
export default DropdownMenu;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import PropTypes from 'prop-types';
2+
import React from 'react';
3+
import ButtonOrLink from '../../common/ButtonOrLink';
4+
5+
// TODO: combine with NavMenuItem
6+
7+
function MenuItem({ hideIf, ...rest }) {
8+
if (hideIf) {
9+
return null;
10+
}
11+
12+
return (
13+
<li>
14+
<ButtonOrLink {...rest} />
15+
</li>
16+
);
17+
}
18+
19+
MenuItem.propTypes = {
20+
...ButtonOrLink.propTypes,
21+
onClick: PropTypes.func,
22+
value: PropTypes.string,
23+
/**
24+
* Provides a way to deal with optional items.
25+
*/
26+
hideIf: PropTypes.bool
27+
};
28+
29+
MenuItem.defaultProps = {
30+
onClick: null,
31+
value: null,
32+
hideIf: false
33+
};
34+
35+
export default MenuItem;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { useMediaQuery } from 'react-responsive';
3+
import styled from 'styled-components';
4+
import { prop, remSize } from '../../theme';
5+
import DropdownMenu from './DropdownMenu';
6+
7+
import DownFilledTriangleIcon from '../../images/down-filled-triangle.svg';
8+
import MoreIconSvg from '../../images/more.svg';
9+
10+
const DotsHorizontal = styled(MoreIconSvg)`
11+
transform: rotate(90deg);
12+
`;
13+
14+
const TableDropdownIcon = () => {
15+
// TODO: centralize breakpoints
16+
const isMobile = useMediaQuery({ maxWidth: 770 });
17+
18+
return isMobile ? (
19+
<DotsHorizontal focusable="false" aria-hidden="true" />
20+
) : (
21+
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
22+
);
23+
};
24+
25+
const TableDropdown = styled(DropdownMenu).attrs({
26+
align: 'right',
27+
anchor: <TableDropdownIcon />
28+
})`
29+
& > button {
30+
width: ${remSize(25)};
31+
height: ${remSize(25)};
32+
padding: 0;
33+
& svg {
34+
max-width: 100%;
35+
max-height: 100%;
36+
}
37+
& polygon,
38+
& path {
39+
fill: ${prop('inactiveTextColor')};
40+
}
41+
}
42+
& ul {
43+
top: 63%;
44+
right: calc(100% - 26px);
45+
}
46+
`;
47+
48+
export default TableDropdown;

0 commit comments

Comments
 (0)