|
@@ -118,6 +118,9 @@ function hitTest(element: ExcalidrawElement, x: number, y: number): boolean {
|
118
|
118
|
const y2 = getElementAbsoluteY2(element);
|
119
|
119
|
|
120
|
120
|
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
|
|
121
|
+ } else if (element.type === "selection") {
|
|
122
|
+ console.warn("This should not happen, we need to investigate why it does.");
|
|
123
|
+ return false;
|
121
|
124
|
} else {
|
122
|
125
|
throw new Error("Unimplemented type " + element.type);
|
123
|
126
|
}
|
|
@@ -571,6 +574,40 @@ const KEYS = {
|
571
|
574
|
BACKSPACE: "Backspace"
|
572
|
575
|
};
|
573
|
576
|
|
|
577
|
+const SHAPES = [
|
|
578
|
+ {
|
|
579
|
+ label: "Rectange",
|
|
580
|
+ value: "rectangle"
|
|
581
|
+ },
|
|
582
|
+ {
|
|
583
|
+ label: "Ellipse",
|
|
584
|
+ value: "ellipse"
|
|
585
|
+ },
|
|
586
|
+ {
|
|
587
|
+ label: "Arrow",
|
|
588
|
+ value: "arrow"
|
|
589
|
+ },
|
|
590
|
+ {
|
|
591
|
+ label: "Text",
|
|
592
|
+ value: "text"
|
|
593
|
+ },
|
|
594
|
+ {
|
|
595
|
+ label: "Selection",
|
|
596
|
+ value: "selection"
|
|
597
|
+ }
|
|
598
|
+];
|
|
599
|
+
|
|
600
|
+const shapesShortcutKeys = SHAPES.map(shape => shape.label[0].toLowerCase());
|
|
601
|
+
|
|
602
|
+function findElementByKey(key: string) {
|
|
603
|
+ const defaultElement = "selection";
|
|
604
|
+ return SHAPES.reduce((element, shape) => {
|
|
605
|
+ if (shape.value[0] !== key) return element;
|
|
606
|
+
|
|
607
|
+ return shape.value;
|
|
608
|
+ }, defaultElement);
|
|
609
|
+}
|
|
610
|
+
|
574
|
611
|
function isArrowKey(keyCode: string) {
|
575
|
612
|
return (
|
576
|
613
|
keyCode === KEYS.ARROW_LEFT ||
|
|
@@ -643,32 +680,11 @@ class App extends React.Component<{}, AppState> {
|
643
|
680
|
});
|
644
|
681
|
this.forceUpdate();
|
645
|
682
|
event.preventDefault();
|
|
683
|
+ } else if (shapesShortcutKeys.includes(event.key.toLowerCase())) {
|
|
684
|
+ this.setState({ elementType: findElementByKey(event.key) });
|
646
|
685
|
}
|
647
|
686
|
};
|
648
|
687
|
|
649
|
|
- private renderOption({
|
650
|
|
- type,
|
651
|
|
- children
|
652
|
|
- }: {
|
653
|
|
- type: string;
|
654
|
|
- children: React.ReactNode;
|
655
|
|
- }) {
|
656
|
|
- return (
|
657
|
|
- <label>
|
658
|
|
- <input
|
659
|
|
- type="radio"
|
660
|
|
- checked={this.state.elementType === type}
|
661
|
|
- onChange={() => {
|
662
|
|
- this.setState({ elementType: type });
|
663
|
|
- clearSelection();
|
664
|
|
- this.forceUpdate();
|
665
|
|
- }}
|
666
|
|
- />
|
667
|
|
- {children}
|
668
|
|
- </label>
|
669
|
|
- );
|
670
|
|
- }
|
671
|
|
-
|
672
|
688
|
public render() {
|
673
|
689
|
return (
|
674
|
690
|
<div
|
|
@@ -713,11 +729,20 @@ class App extends React.Component<{}, AppState> {
|
713
|
729
|
>
|
714
|
730
|
<fieldset>
|
715
|
731
|
<legend>Shapes</legend>
|
716
|
|
- {this.renderOption({ type: "rectangle", children: "Rectangle" })}
|
717
|
|
- {this.renderOption({ type: "ellipse", children: "Ellipse" })}
|
718
|
|
- {this.renderOption({ type: "arrow", children: "Arrow" })}
|
719
|
|
- {this.renderOption({ type: "text", children: "Text" })}
|
720
|
|
- {this.renderOption({ type: "selection", children: "Selection" })}
|
|
732
|
+ {SHAPES.map(({ value, label }) => (
|
|
733
|
+ <label>
|
|
734
|
+ <input
|
|
735
|
+ type="radio"
|
|
736
|
+ checked={this.state.elementType === value}
|
|
737
|
+ onChange={() => {
|
|
738
|
+ this.setState({ elementType: value });
|
|
739
|
+ clearSelection();
|
|
740
|
+ this.forceUpdate();
|
|
741
|
+ }}
|
|
742
|
+ />
|
|
743
|
+ <span>{label}</span>
|
|
744
|
+ </label>
|
|
745
|
+ ))}
|
721
|
746
|
</fieldset>
|
722
|
747
|
|
723
|
748
|
<canvas
|