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
node_modules/
# lock file
yarn.lock
# Editors
.vscode/

View File

@ -118,6 +118,9 @@ function hitTest(element: ExcalidrawElement, x: number, y: number): boolean {
const y2 = getElementAbsoluteY2(element);
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 {
throw new Error("Unimplemented type " + element.type);
}
@ -571,6 +574,40 @@ const KEYS = {
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) {
return (
keyCode === KEYS.ARROW_LEFT ||
@ -643,32 +680,11 @@ class App extends React.Component<{}, AppState> {
});
this.forceUpdate();
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() {
return (
<div
@ -713,11 +729,20 @@ class App extends React.Component<{}, AppState> {
>
<fieldset>
<legend>Shapes</legend>
{this.renderOption({ type: "rectangle", children: "Rectangle" })}
{this.renderOption({ type: "ellipse", children: "Ellipse" })}
{this.renderOption({ type: "arrow", children: "Arrow" })}
{this.renderOption({ type: "text", children: "Text" })}
{this.renderOption({ type: "selection", children: "Selection" })}
{SHAPES.map(({ value, label }) => (
<label>
<input
type="radio"
checked={this.state.elementType === value}
onChange={() => {
this.setState({ elementType: value });
clearSelection();
this.forceUpdate();
}}
/>
<span>{label}</span>
</label>
))}
</fieldset>
<canvas

View File

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