Browse Source

feat: Add shortcuts for stroke and background color picker (#3318)

* feat: Add shortcuts for opening stroke and background color picker

* Use App.tsx keydown handler

* only get selectedElements if applicable (perf)

* fix tests and snaps

* reuse `appState.openMenu`

Co-authored-by: dwelle <luzar.david@gmail.com>
Arun 4 years ago
parent
commit
6c3e4417e1

+ 7 - 3
src/actions/actionCanvas.tsx

@@ -22,8 +22,8 @@ export const actionChangeViewBackgroundColor = register({
   name: "changeViewBackgroundColor",
   perform: (_, appState, value) => {
     return {
-      appState: { ...appState, viewBackgroundColor: value },
-      commitToHistory: true,
+      appState: { ...appState, ...value },
+      commitToHistory: !!value.viewBackgroundColor,
     };
   },
   PanelComponent: ({ appState, updateData }) => {
@@ -33,7 +33,11 @@ export const actionChangeViewBackgroundColor = register({
           label={t("labels.canvasBackground")}
           type="canvasBackground"
           color={appState.viewBackgroundColor}
-          onChange={(color) => updateData(color)}
+          onChange={(color) => updateData({ viewBackgroundColor: color })}
+          isActive={appState.openMenu === "canvasColorPicker"}
+          setActive={(active) =>
+            updateData({ openMenu: active ? "canvasColorPicker" : null })
+          }
           data-testid="canvas-background-picker"
         />
       </div>

+ 34 - 16
src/actions/actionProperties.tsx

@@ -99,13 +99,18 @@ export const actionChangeStrokeColor = register({
   name: "changeStrokeColor",
   perform: (elements, appState, value) => {
     return {
-      elements: changeProperty(elements, appState, (el) =>
-        newElementWith(el, {
-          strokeColor: value,
-        }),
-      ),
-      appState: { ...appState, currentItemStrokeColor: value },
-      commitToHistory: true,
+      ...(value.currentItemStrokeColor && {
+        elements: changeProperty(elements, appState, (el) =>
+          newElementWith(el, {
+            strokeColor: value.currentItemStrokeColor,
+          }),
+        ),
+      }),
+      appState: {
+        ...appState,
+        ...value,
+      },
+      commitToHistory: !!value.currentItemStrokeColor,
     };
   },
   PanelComponent: ({ elements, appState, updateData }) => (
@@ -120,7 +125,11 @@ export const actionChangeStrokeColor = register({
           (element) => element.strokeColor,
           appState.currentItemStrokeColor,
         )}
-        onChange={updateData}
+        onChange={(color) => updateData({ currentItemStrokeColor: color })}
+        isActive={appState.openMenu === "strokeColorPicker"}
+        setActive={(active) =>
+          updateData({ openMenu: active ? "strokeColorPicker" : null })
+        }
       />
     </>
   ),
@@ -130,13 +139,18 @@ export const actionChangeBackgroundColor = register({
   name: "changeBackgroundColor",
   perform: (elements, appState, value) => {
     return {
-      elements: changeProperty(elements, appState, (el) =>
-        newElementWith(el, {
-          backgroundColor: value,
-        }),
-      ),
-      appState: { ...appState, currentItemBackgroundColor: value },
-      commitToHistory: true,
+      ...(value.currentItemBackgroundColor && {
+        elements: changeProperty(elements, appState, (el) =>
+          newElementWith(el, {
+            backgroundColor: value.currentItemBackgroundColor,
+          }),
+        ),
+      }),
+      appState: {
+        ...appState,
+        ...value,
+      },
+      commitToHistory: !!value.currentItemBackgroundColor,
     };
   },
   PanelComponent: ({ elements, appState, updateData }) => (
@@ -151,7 +165,11 @@ export const actionChangeBackgroundColor = register({
           (element) => element.backgroundColor,
           appState.currentItemBackgroundColor,
         )}
-        onChange={updateData}
+        onChange={(color) => updateData({ currentItemBackgroundColor: color })}
+        isActive={appState.openMenu === "backgroundColorPicker"}
+        setActive={(active) =>
+          updateData({ openMenu: active ? "backgroundColorPicker" : null })
+        }
       />
     </>
   ),

+ 15 - 0
src/components/App.tsx

@@ -1645,6 +1645,21 @@ class App extends React.Component<AppProps, AppState> {
         isHoldingSpace = true;
         setCursor(this.canvas, CURSOR_TYPE.GRABBING);
       }
+
+      if (event.key === KEYS.G || event.key === KEYS.S) {
+        const selectedElements = getSelectedElements(
+          this.scene.getElements(),
+          this.state,
+        );
+        if (selectedElements.length) {
+          if (event.key === KEYS.G) {
+            this.setState({ openMenu: "backgroundColorPicker" });
+          }
+          if (event.key === KEYS.S) {
+            this.setState({ openMenu: "strokeColorPicker" });
+          }
+        }
+      }
     },
   );
 

+ 4 - 1
src/components/ColorPicker.tsx

@@ -238,13 +238,16 @@ export const ColorPicker = ({
   color,
   onChange,
   label,
+  isActive,
+  setActive,
 }: {
   type: "canvasBackground" | "elementBackground" | "elementStroke";
   color: string | null;
   onChange: (color: string) => void;
   label: string;
+  isActive: boolean;
+  setActive: (active: boolean) => void;
 }) => {
-  const [isActive, setActive] = React.useState(false);
   const pickerButton = React.useRef<HTMLButtonElement>(null);
 
   return (

+ 8 - 0
src/components/HelpDialog.tsx

@@ -365,6 +365,14 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
                   label={t("labels.flipVertical")}
                   shortcuts={[getShortcutKey("Shift+V")]}
                 />
+                <Shortcut
+                  label={t("labels.showStroke")}
+                  shortcuts={[getShortcutKey("S")]}
+                />
+                <Shortcut
+                  label={t("labels.showBackground")}
+                  shortcuts={[getShortcutKey("G")]}
+                />
               </ShortcutIsland>
             </Column>
           </Columns>

+ 1 - 0
src/keys.ts

@@ -44,6 +44,7 @@ export const KEYS = {
   A: "a",
   D: "d",
   E: "e",
+  G: "g",
   L: "l",
   O: "o",
   P: "p",

+ 2 - 0
src/locales/en.json

@@ -101,6 +101,8 @@
     "viewMode": "View mode",
     "toggleExportColorScheme": "Toggle export color scheme",
     "share": "Share",
+    "showStroke": "Show stroke color picker",
+    "showBackground": "Show background color picker",
     "toggleTheme": "Toggle theme"
   },
   "buttons": {

+ 2 - 2
src/tests/__snapshots__/contextmenu.test.tsx.snap

@@ -1748,7 +1748,7 @@ Object {
   "name": "Untitled-201933152653",
   "offsetLeft": 20,
   "offsetTop": 10,
-  "openMenu": null,
+  "openMenu": "backgroundColorPicker",
   "pasteDialog": Object {
     "data": null,
     "shown": false,
@@ -2424,7 +2424,7 @@ Object {
 
 exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of elements 1`] = `2`;
 
-exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `25`;
+exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `27`;
 
 exports[`contextMenu element selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = `
 Object {

+ 77 - 152
src/tests/__snapshots__/regressionTests.test.tsx.snap

@@ -3260,7 +3260,7 @@ Object {
   "name": "Untitled-201933152653",
   "offsetLeft": 0,
   "offsetTop": 0,
-  "openMenu": null,
+  "openMenu": "strokeColorPicker",
   "pasteDialog": Object {
     "data": null,
     "shown": false,
@@ -3451,7 +3451,7 @@ Object {
 
 exports[`regression tests change the properties of a shape: [end of test] number of elements 1`] = `1`;
 
-exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `12`;
+exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `14`;
 
 exports[`regression tests click on an element and drag it: [dragged] appState 1`] = `
 Object {
@@ -8734,7 +8734,7 @@ Object {
   "boundElementIds": null,
   "fillStyle": "hachure",
   "groupIds": Array [],
-  "height": 1000,
+  "height": 0,
   "id": "id0",
   "isDeleted": false,
   "opacity": 100,
@@ -8745,9 +8745,9 @@ Object {
   "strokeStyle": "solid",
   "strokeWidth": 1,
   "type": "rectangle",
-  "version": 2,
-  "versionNonce": 1278240551,
-  "width": 1000,
+  "version": 1,
+  "versionNonce": 0,
+  "width": 0,
   "x": 0,
   "y": 0,
 }
@@ -8765,14 +8765,14 @@ Object {
   "isDeleted": false,
   "opacity": 100,
   "roughness": 1,
-  "seed": 449462985,
+  "seed": 1278240551,
   "strokeColor": "#000000",
   "strokeSharpness": "sharp",
   "strokeStyle": "solid",
   "strokeWidth": 1,
   "type": "ellipse",
   "version": 2,
-  "versionNonce": 453191,
+  "versionNonce": 449462985,
   "width": 1000,
   "x": 500,
   "y": 500,
@@ -8799,9 +8799,7 @@ Object {
         "editingGroupId": null,
         "editingLinearElement": null,
         "name": "Untitled-201933152653",
-        "selectedElementIds": Object {
-          "id0": true,
-        },
+        "selectedElementIds": Object {},
         "viewBackgroundColor": "#ffffff",
       },
       "elements": Array [
@@ -8811,7 +8809,7 @@ Object {
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
-          "height": 1000,
+          "height": 0,
           "id": "id0",
           "isDeleted": false,
           "opacity": 100,
@@ -8822,9 +8820,9 @@ Object {
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
-          "width": 1000,
+          "version": 1,
+          "versionNonce": 0,
+          "width": 0,
           "x": 0,
           "y": 0,
         },
@@ -8847,7 +8845,7 @@ Object {
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
-          "height": 1000,
+          "height": 0,
           "id": "id0",
           "isDeleted": false,
           "opacity": 100,
@@ -8858,9 +8856,9 @@ Object {
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
-          "width": 1000,
+          "version": 1,
+          "versionNonce": 0,
+          "width": 0,
           "x": 0,
           "y": 0,
         },
@@ -8875,14 +8873,14 @@ Object {
           "isDeleted": false,
           "opacity": 100,
           "roughness": 1,
-          "seed": 449462985,
+          "seed": 1278240551,
           "strokeColor": "#000000",
           "strokeSharpness": "sharp",
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "ellipse",
           "version": 2,
-          "versionNonce": 453191,
+          "versionNonce": 449462985,
           "width": 1000,
           "x": 500,
           "y": 500,
@@ -8901,7 +8899,7 @@ exports[`regression tests given selected element A with lower z-index than unsel
 Object {
   "collaborators": Map {},
   "currentChartType": "bar",
-  "currentItemBackgroundColor": "#fa5252",
+  "currentItemBackgroundColor": "transparent",
   "currentItemEndArrowhead": "arrow",
   "currentItemFillStyle": "hachure",
   "currentItemFontFamily": 1,
@@ -8982,7 +8980,7 @@ Object {
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] element 0 1`] = `
 Object {
   "angle": 0,
-  "backgroundColor": "#fa5252",
+  "backgroundColor": "red",
   "boundElementIds": null,
   "fillStyle": "hachure",
   "groupIds": Array [],
@@ -8997,8 +8995,8 @@ Object {
   "strokeStyle": "solid",
   "strokeWidth": 1,
   "type": "rectangle",
-  "version": 2,
-  "versionNonce": 1278240551,
+  "version": 1,
+  "versionNonce": 0,
   "width": 1000,
   "x": 0,
   "y": 0,
@@ -9008,24 +9006,24 @@ Object {
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] element 1 1`] = `
 Object {
   "angle": 0,
-  "backgroundColor": "#fa5252",
+  "backgroundColor": "red",
   "boundElementIds": null,
   "fillStyle": "hachure",
   "groupIds": Array [],
-  "height": 1000,
+  "height": 500,
   "id": "id1",
   "isDeleted": false,
   "opacity": 100,
   "roughness": 1,
-  "seed": 449462985,
+  "seed": 1278240551,
   "strokeColor": "#000000",
   "strokeSharpness": "sharp",
   "strokeStyle": "solid",
   "strokeWidth": 1,
-  "type": "ellipse",
-  "version": 2,
-  "versionNonce": 453191,
-  "width": 1000,
+  "type": "rectangle",
+  "version": 1,
+  "versionNonce": 0,
+  "width": 500,
   "x": 500,
   "y": 500,
 }
@@ -9053,49 +9051,14 @@ Object {
         "name": "Untitled-201933152653",
         "selectedElementIds": Object {
           "id0": true,
+          "id2": true,
         },
         "viewBackgroundColor": "#ffffff",
       },
       "elements": Array [
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
-          "boundElementIds": null,
-          "fillStyle": "hachure",
-          "groupIds": Array [],
-          "height": 1000,
-          "id": "id0",
-          "isDeleted": false,
-          "opacity": 100,
-          "roughness": 1,
-          "seed": 337897,
-          "strokeColor": "#000000",
-          "strokeSharpness": "sharp",
-          "strokeStyle": "solid",
-          "strokeWidth": 1,
-          "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
-          "width": 1000,
-          "x": 0,
-          "y": 0,
-        },
-      ],
-    },
-    Object {
-      "appState": Object {
-        "editingGroupId": null,
-        "editingLinearElement": null,
-        "name": "Untitled-201933152653",
-        "selectedElementIds": Object {
-          "id1": true,
-        },
-        "viewBackgroundColor": "#ffffff",
-      },
-      "elements": Array [
-        Object {
-          "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
@@ -9110,32 +9073,32 @@ Object {
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
+          "version": 1,
+          "versionNonce": 0,
           "width": 1000,
           "x": 0,
           "y": 0,
         },
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
-          "height": 1000,
+          "height": 500,
           "id": "id1",
           "isDeleted": false,
           "opacity": 100,
           "roughness": 1,
-          "seed": 449462985,
+          "seed": 1278240551,
           "strokeColor": "#000000",
           "strokeSharpness": "sharp",
           "strokeStyle": "solid",
           "strokeWidth": 1,
-          "type": "ellipse",
-          "version": 2,
-          "versionNonce": 453191,
-          "width": 1000,
+          "type": "rectangle",
+          "version": 1,
+          "versionNonce": 0,
+          "width": 500,
           "x": 500,
           "y": 500,
         },
@@ -9147,13 +9110,13 @@ Object {
 
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of elements 1`] = `2`;
 
-exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `18`;
+exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `11`;
 
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] appState 1`] = `
 Object {
   "collaborators": Map {},
   "currentChartType": "bar",
-  "currentItemBackgroundColor": "#fa5252",
+  "currentItemBackgroundColor": "transparent",
   "currentItemEndArrowhead": "arrow",
   "currentItemFillStyle": "hachure",
   "currentItemFontFamily": 1,
@@ -9235,7 +9198,7 @@ Object {
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] element 0 1`] = `
 Object {
   "angle": 0,
-  "backgroundColor": "#fa5252",
+  "backgroundColor": "red",
   "boundElementIds": null,
   "fillStyle": "hachure",
   "groupIds": Array [],
@@ -9250,8 +9213,8 @@ Object {
   "strokeStyle": "solid",
   "strokeWidth": 1,
   "type": "rectangle",
-  "version": 3,
-  "versionNonce": 1150084233,
+  "version": 2,
+  "versionNonce": 401146281,
   "width": 1000,
   "x": 100,
   "y": 100,
@@ -9261,24 +9224,24 @@ Object {
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] element 1 1`] = `
 Object {
   "angle": 0,
-  "backgroundColor": "#fa5252",
+  "backgroundColor": "red",
   "boundElementIds": null,
   "fillStyle": "hachure",
   "groupIds": Array [],
-  "height": 1000,
+  "height": 500,
   "id": "id1",
   "isDeleted": false,
   "opacity": 100,
   "roughness": 1,
-  "seed": 449462985,
+  "seed": 1278240551,
   "strokeColor": "#000000",
   "strokeSharpness": "sharp",
   "strokeStyle": "solid",
   "strokeWidth": 1,
-  "type": "ellipse",
-  "version": 2,
-  "versionNonce": 453191,
-  "width": 1000,
+  "type": "rectangle",
+  "version": 1,
+  "versionNonce": 0,
+  "width": 500,
   "x": 500,
   "y": 500,
 }
@@ -9306,49 +9269,14 @@ Object {
         "name": "Untitled-201933152653",
         "selectedElementIds": Object {
           "id0": true,
+          "id2": true,
         },
         "viewBackgroundColor": "#ffffff",
       },
       "elements": Array [
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
-          "boundElementIds": null,
-          "fillStyle": "hachure",
-          "groupIds": Array [],
-          "height": 1000,
-          "id": "id0",
-          "isDeleted": false,
-          "opacity": 100,
-          "roughness": 1,
-          "seed": 337897,
-          "strokeColor": "#000000",
-          "strokeSharpness": "sharp",
-          "strokeStyle": "solid",
-          "strokeWidth": 1,
-          "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
-          "width": 1000,
-          "x": 0,
-          "y": 0,
-        },
-      ],
-    },
-    Object {
-      "appState": Object {
-        "editingGroupId": null,
-        "editingLinearElement": null,
-        "name": "Untitled-201933152653",
-        "selectedElementIds": Object {
-          "id1": true,
-        },
-        "viewBackgroundColor": "#ffffff",
-      },
-      "elements": Array [
-        Object {
-          "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
@@ -9363,32 +9291,32 @@ Object {
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "rectangle",
-          "version": 2,
-          "versionNonce": 1278240551,
+          "version": 1,
+          "versionNonce": 0,
           "width": 1000,
           "x": 0,
           "y": 0,
         },
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
-          "height": 1000,
+          "height": 500,
           "id": "id1",
           "isDeleted": false,
           "opacity": 100,
           "roughness": 1,
-          "seed": 449462985,
+          "seed": 1278240551,
           "strokeColor": "#000000",
           "strokeSharpness": "sharp",
           "strokeStyle": "solid",
           "strokeWidth": 1,
-          "type": "ellipse",
-          "version": 2,
-          "versionNonce": 453191,
-          "width": 1000,
+          "type": "rectangle",
+          "version": 1,
+          "versionNonce": 0,
+          "width": 500,
           "x": 500,
           "y": 500,
         },
@@ -9409,7 +9337,7 @@ Object {
       "elements": Array [
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
@@ -9424,32 +9352,32 @@ Object {
           "strokeStyle": "solid",
           "strokeWidth": 1,
           "type": "rectangle",
-          "version": 3,
-          "versionNonce": 1150084233,
+          "version": 2,
+          "versionNonce": 401146281,
           "width": 1000,
           "x": 100,
           "y": 100,
         },
         Object {
           "angle": 0,
-          "backgroundColor": "#fa5252",
+          "backgroundColor": "red",
           "boundElementIds": null,
           "fillStyle": "hachure",
           "groupIds": Array [],
-          "height": 1000,
+          "height": 500,
           "id": "id1",
           "isDeleted": false,
           "opacity": 100,
           "roughness": 1,
-          "seed": 449462985,
+          "seed": 1278240551,
           "strokeColor": "#000000",
           "strokeSharpness": "sharp",
           "strokeStyle": "solid",
           "strokeWidth": 1,
-          "type": "ellipse",
-          "version": 2,
-          "versionNonce": 453191,
-          "width": 1000,
+          "type": "rectangle",
+          "version": 1,
+          "versionNonce": 0,
+          "width": 500,
           "x": 500,
           "y": 500,
         },
@@ -9461,7 +9389,7 @@ Object {
 
 exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of elements 1`] = `2`;
 
-exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `19`;
+exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `12`;
 
 exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1`] = `
 Object {
@@ -13323,16 +13251,13 @@ Object {
     "data": null,
     "shown": false,
   },
-  "previousSelectedElementIds": Object {
-    "id0": true,
-  },
+  "previousSelectedElementIds": Object {},
   "resizingElement": null,
   "scrollX": 0,
   "scrollY": 0,
   "scrolledOutside": false,
   "selectedElementIds": Object {
     "id0": true,
-    "id1": true,
   },
   "selectedGroupIds": Object {},
   "selectionElement": null,
@@ -13476,7 +13401,7 @@ Object {
 
 exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of elements 1`] = `1`;
 
-exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `12`;
+exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `13`;
 
 exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] appState 1`] = `
 Object {

+ 44 - 40
src/tests/regressionTests.test.tsx

@@ -702,33 +702,36 @@ describe("regression tests", () => {
       "when clicking intersection between A and B " +
       "B should be selected on pointer up",
     () => {
-      UI.clickTool("rectangle");
-      // change background color since default is transparent
+      // set background color since default is transparent
       // and transparent elements can't be selected by clicking inside of them
-      clickLabeledElement("Background");
-      clickLabeledElement("#fa5252");
-      mouse.down();
-      mouse.up(1000, 1000);
-
-      // draw ellipse partially over rectangle.
-      // since ellipse was created after rectangle it has an higher z-index.
-      // we don't need to change background color again since change above
-      // affects next drawn elements.
-      UI.clickTool("ellipse");
-      mouse.reset();
-      mouse.down(500, 500);
-      mouse.up(1000, 1000);
+      const rect1 = API.createElement({
+        type: "rectangle",
+        backgroundColor: "red",
+        x: 0,
+        y: 0,
+        width: 1000,
+        height: 1000,
+      });
+      const rect2 = API.createElement({
+        type: "rectangle",
+        backgroundColor: "red",
+        x: 500,
+        y: 500,
+        width: 500,
+        height: 500,
+      });
+      h.elements = [rect1, rect2];
 
-      // select rectangle
-      mouse.reset();
-      mouse.click();
+      mouse.select(rect1);
 
-      // pointer down on intersection between ellipse and rectangle
+      // pointerdown on rect2 covering rect1 while rect1 is selected should
+      // retain rect1 selection
       mouse.down(900, 900);
-      expect(API.getSelectedElement().type).toBe("rectangle");
+      expect(API.getSelectedElement().id).toBe(rect1.id);
 
+      // pointerup should select rect2
       mouse.up();
-      expect(API.getSelectedElement().type).toBe("ellipse");
+      expect(API.getSelectedElement().id).toBe(rect2.id);
     },
   );
 
@@ -737,26 +740,27 @@ describe("regression tests", () => {
       "when dragging on intersection between A and B " +
       "A should be dragged and keep being selected",
     () => {
-      UI.clickTool("rectangle");
-      // change background color since default is transparent
-      // and transparent elements can't be selected by clicking inside of them
-      clickLabeledElement("Background");
-      clickLabeledElement("#fa5252");
-      mouse.down();
-      mouse.up(1000, 1000);
+      const rect1 = API.createElement({
+        type: "rectangle",
+        backgroundColor: "red",
+        x: 0,
+        y: 0,
+        width: 1000,
+        height: 1000,
+      });
+      const rect2 = API.createElement({
+        type: "rectangle",
+        backgroundColor: "red",
+        x: 500,
+        y: 500,
+        width: 500,
+        height: 500,
+      });
+      h.elements = [rect1, rect2];
 
-      // draw ellipse partially over rectangle.
-      // since ellipse was created after rectangle it has an higher z-index.
-      // we don't need to change background color again since change above
-      // affects next drawn elements.
-      UI.clickTool("ellipse");
-      mouse.reset();
-      mouse.down(500, 500);
-      mouse.up(1000, 1000);
+      mouse.select(rect1);
 
-      // select rectangle
-      mouse.reset();
-      mouse.click();
+      expect(API.getSelectedElement().id).toBe(rect1.id);
 
       const { x: prevX, y: prevY } = API.getSelectedElement();
 
@@ -764,7 +768,7 @@ describe("regression tests", () => {
       mouse.down(900, 900);
       mouse.up(100, 100);
 
-      expect(API.getSelectedElement().type).toBe("rectangle");
+      expect(API.getSelectedElement().id).toBe(rect1.id);
       expect(API.getSelectedElement().x).toEqual(prevX + 100);
       expect(API.getSelectedElement().y).toEqual(prevY + 100);
     },

+ 7 - 1
src/types.ts

@@ -81,7 +81,13 @@ export type AppState = {
   isResizing: boolean;
   isRotating: boolean;
   zoom: Zoom;
-  openMenu: "canvas" | "shape" | null;
+  openMenu:
+    | "canvas"
+    | "shape"
+    | "canvasColorPicker"
+    | "backgroundColorPicker"
+    | "strokeColorPicker"
+    | null;
   lastPointerDownWith: PointerType;
   selectedElementIds: { [id: string]: boolean };
   previousSelectedElementIds: { [id: string]: boolean };