Просмотр исходного кода

fix: Support Excalidraw inside scrollable container (#3018)

* refactor: remove position fixed from excalidraw container, modal and stats

* remove unused css

* remove position fixed from toast and scroll to content

* Make excal interactable by fixing offsets and set popover as fixed since position needs to be calculate from viewport  top

* Assign 200px less than height of Excalidraw to the selected shapes actions o UI doesn't overflow

* update changelog, readme and package.json
vanilla_orig
Aakansha Doshi 4 лет назад
Родитель
Сommit
830fb64a25
Аккаунт пользователя с таким Email не найден

+ 6
- 0
src/components/App.tsx Просмотреть файл

@@ -51,6 +51,7 @@ import {
51 51
   LINE_CONFIRM_THRESHOLD,
52 52
   MIME_TYPES,
53 53
   POINTER_BUTTON,
54
+  SCROLL_TIMEOUT,
54 55
   TAP_TWICE_TIMEOUT,
55 56
   TEXT_TO_CENTER_SNAP_THRESHOLD,
56 57
   TOUCH_CTX_MENU_TIMEOUT,
@@ -825,6 +826,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
825 826
 
826 827
     document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
827 828
     document.addEventListener(EVENT.CUT, this.onCut);
829
+    document.addEventListener(EVENT.SCROLL, this.onScroll);
828 830
 
829 831
     window.addEventListener(EVENT.RESIZE, this.onResize, false);
830 832
     window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
@@ -998,6 +1000,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
998 1000
     }
999 1001
   }
1000 1002
 
1003
+  private onScroll = debounce(() => {
1004
+    this.setState({ ...this.getCanvasOffsets() });
1005
+  }, SCROLL_TIMEOUT);
1006
+
1001 1007
   // Copy/paste
1002 1008
 
1003 1009
   private onCut = withBatchedUpdates((event: ClipboardEvent) => {

+ 21
- 13
src/components/LayerUI.tsx Просмотреть файл

@@ -442,7 +442,15 @@ const LayerUI = ({
442 442
         "transition-left": zenModeEnabled,
443 443
       })}
444 444
     >
445
-      <Island className={CLASSES.SHAPE_ACTIONS_MENU} padding={2}>
445
+      <Island
446
+        className={CLASSES.SHAPE_ACTIONS_MENU}
447
+        padding={2}
448
+        style={{
449
+          // we want to make sure this doesn't overflow so substracting 200
450
+          // which is approximately height of zoom footer and top left menu items with some buffer
451
+          maxHeight: `${appState.height - 200}px`,
452
+        }}
453
+      >
446 454
         <SelectedShapeActions
447 455
           appState={appState}
448 456
           elements={elements}
@@ -603,18 +611,6 @@ const LayerUI = ({
603 611
       >
604 612
         {t("buttons.exitZenMode")}
605 613
       </button>
606
-      {appState.scrolledOutside && (
607
-        <button
608
-          className="scroll-back-to-content"
609
-          onClick={() => {
610
-            setAppState({
611
-              ...calculateScrollCenter(elements, appState, canvas),
612
-            });
613
-          }}
614
-        >
615
-          {t("buttons.scrollBackToContent")}
616
-        </button>
617
-      )}
618 614
     </footer>
619 615
   );
620 616
 
@@ -677,6 +673,18 @@ const LayerUI = ({
677 673
       {renderBottomAppMenu()}
678 674
       {renderGitHubCorner()}
679 675
       {renderFooter()}
676
+      {appState.scrolledOutside && (
677
+        <button
678
+          className="scroll-back-to-content"
679
+          onClick={() => {
680
+            setAppState({
681
+              ...calculateScrollCenter(elements, appState, canvas),
682
+            });
683
+          }}
684
+        >
685
+          {t("buttons.scrollBackToContent")}
686
+        </button>
687
+      )}
680 688
     </div>
681 689
   );
682 690
 };

+ 8
- 3
src/components/Modal.scss Просмотреть файл

@@ -1,8 +1,13 @@
1 1
 @import "../css/variables.module";
2 2
 
3 3
 .excalidraw {
4
+  &.excalidraw-modal-container {
5
+    position: absolute;
6
+    z-index: 10;
7
+  }
8
+
4 9
   .Modal {
5
-    position: fixed;
10
+    position: absolute;
6 11
     top: 0;
7 12
     left: 0;
8 13
     right: 0;
@@ -15,7 +20,7 @@
15 20
   }
16 21
 
17 22
   .Modal__background {
18
-    position: fixed;
23
+    position: absolute;
19 24
     top: 0;
20 25
     left: 0;
21 26
     right: 0;
@@ -82,7 +87,7 @@
82 87
     }
83 88
 
84 89
     .Modal__content {
85
-      position: fixed;
90
+      position: absolute;
86 91
       top: 0;
87 92
       left: 0;
88 93
       right: 0;

+ 1
- 1
src/components/Modal.tsx Просмотреть файл

@@ -54,7 +54,7 @@ const useBodyRoot = () => {
54 54
       ?.classList.contains("Appearance_dark");
55 55
     const div = document.createElement("div");
56 56
 
57
-    div.classList.add("excalidraw");
57
+    div.classList.add("excalidraw", "excalidraw-modal-container");
58 58
 
59 59
     if (isDarkTheme) {
60 60
       div.classList.add("Appearance_dark");

+ 1
- 9
src/components/Popover.scss Просмотреть файл

@@ -1,14 +1,6 @@
1 1
 .excalidraw {
2 2
   .popover {
3
-    position: absolute;
4
-    z-index: 10;
5
-  }
6
-
7
-  .popover .cover {
8 3
     position: fixed;
9
-    top: 0;
10
-    left: 0;
11
-    right: 0;
12
-    bottom: 0;
4
+    z-index: 10;
13 5
   }
14 6
 }

+ 1
- 1
src/components/Stats.scss Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 @import "../css/variables.module";
2 2
 
3 3
 .Stats {
4
-  position: fixed;
4
+  position: absolute;
5 5
   top: 64px;
6 6
   right: 12px;
7 7
   font-size: 12px;

+ 1
- 1
src/components/Toast.scss Просмотреть файл

@@ -11,7 +11,7 @@
11 11
     left: 50%;
12 12
     margin-left: -150px;
13 13
     padding: 4px 0;
14
-    position: fixed;
14
+    position: absolute;
15 15
     text-align: center;
16 16
     width: 300px;
17 17
     z-index: 999999;

+ 2
- 0
src/constants.ts Просмотреть файл

@@ -47,6 +47,7 @@ export enum EVENT {
47 47
   TOUCH_END = "touchend",
48 48
   HASHCHANGE = "hashchange",
49 49
   VISIBILITY_CHANGE = "visibilitychange",
50
+  SCROLL = "scroll",
50 51
 }
51 52
 
52 53
 export const ENV = {
@@ -92,6 +93,7 @@ export const TOUCH_CTX_MENU_TIMEOUT = 500;
92 93
 export const TITLE_TIMEOUT = 10000;
93 94
 export const TOAST_TIMEOUT = 5000;
94 95
 export const VERSION_TIMEOUT = 30000;
96
+export const SCROLL_TIMEOUT = 500;
95 97
 
96 98
 export const ZOOM_STEP = 0.1;
97 99
 

+ 1
- 3
src/css/styles.scss Просмотреть файл

@@ -10,7 +10,6 @@
10 10
 .excalidraw {
11 11
   color: var(--text-color-primary);
12 12
   display: flex;
13
-  position: fixed;
14 13
   top: 0;
15 14
   bottom: 0;
16 15
   left: 0;
@@ -362,7 +361,6 @@
362 361
 
363 362
   .App-menu__left {
364 363
     overflow-y: auto;
365
-    max-height: calc(100vh - 236px);
366 364
   }
367 365
 
368 366
   .dropdown-select {
@@ -434,7 +432,7 @@
434 432
 
435 433
   .scroll-back-to-content {
436 434
     color: var(--popup-text-color);
437
-    position: fixed;
435
+    position: absolute;
438 436
     left: 50%;
439 437
     bottom: 30px;
440 438
     transform: translateX(-50%);

+ 14
- 0
src/packages/excalidraw/CHANGELOG.md Просмотреть файл

@@ -12,6 +12,20 @@ The change should be grouped under one of the below section and must contain PR
12 12
 Please add the latest change on the top under the correct section.
13 13
 -->
14 14
 
15
+## 0.3.1
16
+
17
+## Excalidraw API
18
+
19
+### Fixes
20
+
21
+- Support Excalidraw inside scrollable container [#3018](https://github.com/excalidraw/excalidraw/pull/3018)
22
+
23
+## Excalidraw Library
24
+
25
+### Fixes
26
+
27
+- Allow to toggle between modes when view only mode to make UI consistent [#3009](https://github.com/excalidraw/excalidraw/pull/3009)
28
+
15 29
 ## 0.3.0
16 30
 
17 31
 ## Excalidraw API

+ 15
- 11
src/packages/excalidraw/README.md Просмотреть файл

@@ -37,18 +37,18 @@ You can update the value of `PUBLIC_URL` if you want to serve it from a differen
37 37
 1. If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module as shown below
38 38
 
39 39
 ```js
40
-import React, { useEffect, useState, createRef } from "react";
40
+import React, { useEffect, useState, useRef } from "react";
41 41
 import Excalidraw from "@excalidraw/excalidraw";
42 42
 import InitialData from "./initialData";
43 43
 
44
-import "./styles.css";
44
+import "./styles.scss";
45 45
 
46 46
 export default function App() {
47
-  const excalidrawRef = createRef();
48
-
47
+  const excalidrawRef = useRef(null);
48
+  const excalidrawWrapperRef = useRef(null);
49 49
   const [dimensions, setDimensions] = useState({
50
-    width: window.innerWidth,
51
-    height: window.innerHeight,
50
+    width: undefined,
51
+    height: undefined,
52 52
   });
53 53
 
54 54
   const [viewModeEnabled, setViewModeEnabled] = useState(false);
@@ -56,17 +56,21 @@ export default function App() {
56 56
   const [gridModeEnabled, setGridModeEnabled] = useState(false);
57 57
 
58 58
   useEffect(() => {
59
+    setDimensions({
60
+      width: excalidrawWrapperRef.current.getBoundingClientRect().width,
61
+      height: excalidrawWrapperRef.current.getBoundingClientRect().height,
62
+    });
59 63
     const onResize = () => {
60 64
       setDimensions({
61
-        width: window.innerWidth,
62
-        height: window.innerHeight,
65
+        width: excalidrawWrapperRef.current.getBoundingClientRect().width,
66
+        height: excalidrawWrapperRef.current.getBoundingClientRect().height,
63 67
       });
64 68
     };
65 69
 
66 70
     window.addEventListener("resize", onResize);
67 71
 
68 72
     return () => window.removeEventListener("resize", onResize);
69
-  }, []);
73
+  }, [excalidrawWrapperRef]);
70 74
 
71 75
   const updateScene = () => {
72 76
     const sceneData = {
@@ -102,6 +106,7 @@ export default function App() {
102 106
 
103 107
   return (
104 108
     <div className="App">
109
+      <h1> Excalidraw Example</h1>
105 110
       <div className="button-wrapper">
106 111
         <button className="update-scene" onClick={updateScene}>
107 112
           Update Scene
@@ -139,7 +144,7 @@ export default function App() {
139 144
           Grid mode
140 145
         </label>
141 146
       </div>
142
-      <div className="excalidraw-wrapper">
147
+      <div className="excalidraw-wrapper" ref={excalidrawWrapperRef}>
143 148
         <Excalidraw
144 149
           ref={excalidrawRef}
145 150
           width={dimensions.width}
@@ -148,7 +153,6 @@ export default function App() {
148 153
           onChange={(elements, state) =>
149 154
             console.log("Elements :", elements, "State : ", state)
150 155
           }
151
-          user={{ name: "Excalidraw User" }}
152 156
           onPointerUpdate={(payload) => console.log(payload)}
153 157
           onCollabButtonClick={() =>
154 158
             window.alert("You clicked on collab button")

+ 1
- 1
src/packages/excalidraw/package-lock.json Просмотреть файл

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "@excalidraw/excalidraw",
3
-  "version": "0.3.0",
3
+  "version": "0.3.1",
4 4
   "lockfileVersion": 1,
5 5
   "requires": true,
6 6
   "dependencies": {

+ 1
- 1
src/packages/excalidraw/package.json Просмотреть файл

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "@excalidraw/excalidraw",
3
-  "version": "0.3.0",
3
+  "version": "0.3.1",
4 4
   "main": "dist/excalidraw.min.js",
5 5
   "files": [
6 6
     "dist/*"

Загрузка…
Отмена
Сохранить