Skip to content

Commit 09e1f3d

Browse files
authored
Quick Actions (codesandbox#380)
* Add Quick Actions * Fix keymapping validation * Fix tests * Fix linter * Fix registering of keybindings * Fix cmd+alt+p not registering keyup events
1 parent 82f734f commit 09e1f3d

21 files changed

Lines changed: 433 additions & 65 deletions

File tree

packages/app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
"downshift": "^1.0.0-rc.14",
120120
"eslint-config-react-app": "^1.0.5",
121121
"file-saver": "^1.3.3",
122+
"geniejs": "^0.5.0",
122123
"glamor": "^2.20.25",
123124
"gsap": "^1.20.3",
124125
"gulp": "^3.9.1",
@@ -185,7 +186,7 @@
185186
"/create-zip\\/.*\\/files/"
186187
],
187188
"transformIgnorePatterns": [
188-
"node_modules/(?!(common))"
189+
"node_modules/(?!(common|react-icons))"
189190
],
190191
"moduleNameMapper": {
191192
"\\.css$": "<rootDir>/__mocks__/styleMock.js",

packages/app/src/app/components/Preference/PreferenceKeybinding/KeybindingInput.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22

33
import Input from 'app/components/Input';
44

5-
import { normalizeKey } from 'app/store/preferences/keybindings';
5+
import { normalizeKey, formatKey } from 'app/store/preferences/keybindings';
66

77
type Props = {
88
value: Array<string>,
@@ -14,22 +14,6 @@ type Props = {
1414
const SPECIAL_KEYS = ['Meta', 'Control', 'Alt', 'Shift', 'Enter', 'Backspace'];
1515
const IGNORED_KEYS = ['Backspace', 'Escape', 'CapsLock'];
1616

17-
function formatKey(key: string) {
18-
switch (key) {
19-
case 'Meta': {
20-
const isMac = !!navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i);
21-
if (isMac) {
22-
return '⌘';
23-
}
24-
return '⊞';
25-
}
26-
case 'Control':
27-
return 'Ctrl';
28-
default:
29-
return key;
30-
}
31-
}
32-
3317
function sortKeys(keys: Array<string>) {
3418
return keys.sort((a, b) => {
3519
const isASpecial = SPECIAL_KEYS.indexOf(a) > -1;

packages/app/src/app/components/sandbox/CodeEditor/Monaco.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -728,16 +728,6 @@ export default class CodeEditor extends React.Component<Props, State> {
728728
this.handleSaveCode();
729729
}
730730
);
731-
732-
const quickCommandAction = this.editor.getAction(
733-
'editor.action.quickCommand'
734-
);
735-
this.editor.addCommand(
736-
this.monaco.KeyMod.CtrlCmd | // eslint-disable-line no-bitwise
737-
this.monaco.KeyMod.Shift | // eslint-disable-line no-bitwise
738-
this.monaco.KeyCode.KEY_P, // eslint-disable-line no-bitwise
739-
quickCommandAction._run // eslint-disable-line no-underscore-dangle
740-
);
741731
};
742732

743733
disposeModules = (modules: Array<Module>) => {

packages/app/src/app/containers/KeybindingManager.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import React, { KeyboardEvent } from 'react';
22
import { connect } from 'react-redux';
33
import { createSelector } from 'reselect';
44

5-
import { KEYBINDINGS, normalizeKey } from 'app/store/preferences/keybindings';
6-
import { keybindingsSelector } from 'app/store/preferences/selectors';
5+
import { normalizeKey } from 'app/store/preferences/keybindings';
6+
import { userKeybindingsSelector } from 'app/store/preferences/selectors';
77
import { modalSelector } from 'app/store/modal/selectors';
88

99
type Props = {
1010
sandboxId: string,
1111
keybindings: {
1212
[key: string]: {
13+
title: string,
1314
bindings: [Array<string>, ?Array<string>],
1415
action: Function,
1516
},
@@ -22,14 +23,9 @@ type Props = {
2223
};
2324

2425
const mapStateToProps = createSelector(
25-
keybindingsSelector,
26+
userKeybindingsSelector,
2627
modalSelector,
27-
(userKeybindings, modal) => {
28-
const newBindings = { ...KEYBINDINGS };
29-
Object.keys(userKeybindings).forEach(key => {
30-
newBindings[key].bindings = userKeybindings[key];
31-
});
32-
28+
(newBindings, modal) => {
3329
const bindingStrings = {};
3430

3531
Object.keys(newBindings).forEach(key => {
@@ -57,6 +53,7 @@ const mapDispatchToProps = dispatch => ({
5753
class KeybindingManager extends React.Component<Props> {
5854
pressedComboKeys = [];
5955
pressedComboMetaKeys = [];
56+
pressedSpecialKeys = [];
6057
checkedStrokes = this.props.bindingStrings;
6158

6259
removeFromPressedComboKeys = (key: string) => {
@@ -80,6 +77,19 @@ class KeybindingManager extends React.Component<Props> {
8077
}
8178
}
8279

80+
// We also register special keys, sometimes key ups are not registered
81+
// for special keys, so after every 2 seconds we clear the array
82+
if (this.pressedSpecialKeys.indexOf(key) === -1) {
83+
this.pressedSpecialKeys.push(key);
84+
85+
clearTimeout(this.specialTimeout);
86+
this.specialTimeout = setTimeout(() => {
87+
this.pressedSpecialKeys.forEach(k => {
88+
this.removeFromPressedComboKeys(k);
89+
});
90+
}, 1500);
91+
}
92+
8393
// check match
8494
const match = this.checkCombosForPressedKeys();
8595

@@ -91,6 +101,7 @@ class KeybindingManager extends React.Component<Props> {
91101
if (typeof match === 'string') {
92102
this.pressedComboKeys = [];
93103
this.pressedComboMetaKeys = [];
104+
this.pressedSpecialKeys = [];
94105
this.checkedStrokes = this.props.bindingStrings;
95106

96107
this.props.dispatch(

packages/app/src/app/containers/Modal.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,12 @@ class ModalContainer extends React.PureComponent {
9292
props: Props;
9393

9494
closeModal = e => {
95-
if (!e || !e.defaultPrevented) {
96-
const { modalActions } = this.props;
97-
modalActions.closeModal();
95+
const { modalActions, modal } = this.props;
96+
if (e && e.keyCode && modal.preventEscapeClosing) {
97+
return;
9898
}
99+
100+
modalActions.closeModal();
99101
};
100102

101103
getStyles = (width = 400, top = 20) => ({

packages/app/src/app/containers/Preferences/KeyMapping/Preferences.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Preferences extends React.Component<Props> {
5252
const valB1 = value[1] && [...value[1]].sort().join('');
5353
const alreadyExists = bindings.some(([b0, b1]) => {
5454
if (
55+
b0 &&
5556
[...b0]
5657
.sort()
5758
.join('')
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import { formatKey } from 'app/store/preferences/keybindings';
4+
5+
type Props = {
6+
bindings: Array<string>,
7+
};
8+
9+
const Key = styled.div`
10+
padding: 0.25rem 0.3rem;
11+
display: inline-flex;
12+
align-items: center;
13+
justify-content: center;
14+
background-color: ${props => props.theme.background2};
15+
border-radius: 3px;
16+
margin: 0 1px;
17+
font-size: 0.75rem;
18+
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
19+
color: rgba(255, 255, 255, 0.9);
20+
`;
21+
22+
export default ({ bindings }: Props) =>
23+
bindings.map(key => <Key key={key}>{formatKey(key)}</Key>);

0 commit comments

Comments
 (0)