Add shortcuts (#85)

* Add yarn.lock to .gitignore

* Extract available shapes to one place

* Add event listeners for shapes shortcuts

* fixup! Add event listeners for shapes shortcuts

* Underline first letter of shapes

to indicate interactivity

* fixup! Extract available shapes to one place

* fixup! Add event listeners for shapes shortcuts
This commit is contained in:
Alex Bratsos 2020-01-04 01:08:34 +02:00 committed by Christopher Chedeau
parent 8c974411ce
commit 58d81280c9
3 changed files with 64 additions and 28 deletions

3
.gitignore vendored
View File

@ -11,6 +11,9 @@ build
# Dependency directories # Dependency directories
node_modules/ node_modules/
# lock file
yarn.lock
# Editors # Editors
.vscode/ .vscode/

View File

@ -118,6 +118,9 @@ function hitTest(element: ExcalidrawElement, x: number, y: number): boolean {
const y2 = getElementAbsoluteY2(element); const y2 = getElementAbsoluteY2(element);
return x >= x1 && x <= x2 && y >= y1 && y <= y2; return x >= x1 && x <= x2 && y >= y1 && y <= y2;
} else if (element.type === "selection") {
console.warn("This should not happen, we need to investigate why it does.");
return false;
} else { } else {
throw new Error("Unimplemented type " + element.type); throw new Error("Unimplemented type " + element.type);
} }
@ -571,6 +574,40 @@ const KEYS = {
BACKSPACE: "Backspace" BACKSPACE: "Backspace"
}; };
const SHAPES = [
{
label: "Rectange",
value: "rectangle"
},
{
label: "Ellipse",
value: "ellipse"
},
{
label: "Arrow",
value: "arrow"
},
{
label: "Text",
value: "text"
},
{
label: "Selection",
value: "selection"
}
];
const shapesShortcutKeys = SHAPES.map(shape => shape.label[0].toLowerCase());
function findElementByKey(key: string) {
const defaultElement = "selection";
return SHAPES.reduce((element, shape) => {
if (shape.value[0] !== key) return element;
return shape.value;
}, defaultElement);
}
function isArrowKey(keyCode: string) { function isArrowKey(keyCode: string) {
return ( return (
keyCode === KEYS.ARROW_LEFT || keyCode === KEYS.ARROW_LEFT ||
@ -643,32 +680,11 @@ class App extends React.Component<{}, AppState> {
}); });
this.forceUpdate(); this.forceUpdate();
event.preventDefault(); event.preventDefault();
} else if (shapesShortcutKeys.includes(event.key.toLowerCase())) {
this.setState({ elementType: findElementByKey(event.key) });
} }
}; };
private renderOption({
type,
children
}: {
type: string;
children: React.ReactNode;
}) {
return (
<label>
<input
type="radio"
checked={this.state.elementType === type}
onChange={() => {
this.setState({ elementType: type });
clearSelection();
this.forceUpdate();
}}
/>
{children}
</label>
);
}
public render() { public render() {
return ( return (
<div <div
@ -713,11 +729,20 @@ class App extends React.Component<{}, AppState> {
> >
<fieldset> <fieldset>
<legend>Shapes</legend> <legend>Shapes</legend>
{this.renderOption({ type: "rectangle", children: "Rectangle" })} {SHAPES.map(({ value, label }) => (
{this.renderOption({ type: "ellipse", children: "Ellipse" })} <label>
{this.renderOption({ type: "arrow", children: "Arrow" })} <input
{this.renderOption({ type: "text", children: "Text" })} type="radio"
{this.renderOption({ type: "selection", children: "Selection" })} checked={this.state.elementType === value}
onChange={() => {
this.setState({ elementType: value });
clearSelection();
this.forceUpdate();
}}
/>
<span>{label}</span>
</label>
))}
</fieldset> </fieldset>
<canvas <canvas

View File

@ -18,6 +18,14 @@ label {
margin-right: 10px; margin-right: 10px;
} }
label span {
display: inline-block;
}
label span::first-letter {
text-decoration: underline;
}
input[type="number"] { input[type="number"] {
width: 30px; width: 30px;
} }