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
This commit is contained in:
parent
5b343a9d46
commit
830fb64a25
@ -51,6 +51,7 @@ import {
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
POINTER_BUTTON,
|
||||
SCROLL_TIMEOUT,
|
||||
TAP_TWICE_TIMEOUT,
|
||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
@ -825,6 +826,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
|
||||
document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
|
||||
document.addEventListener(EVENT.CUT, this.onCut);
|
||||
document.addEventListener(EVENT.SCROLL, this.onScroll);
|
||||
|
||||
window.addEventListener(EVENT.RESIZE, this.onResize, false);
|
||||
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
|
||||
@ -998,6 +1000,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onScroll = debounce(() => {
|
||||
this.setState({ ...this.getCanvasOffsets() });
|
||||
}, SCROLL_TIMEOUT);
|
||||
|
||||
// Copy/paste
|
||||
|
||||
private onCut = withBatchedUpdates((event: ClipboardEvent) => {
|
||||
|
@ -442,7 +442,15 @@ const LayerUI = ({
|
||||
"transition-left": zenModeEnabled,
|
||||
})}
|
||||
>
|
||||
<Island className={CLASSES.SHAPE_ACTIONS_MENU} padding={2}>
|
||||
<Island
|
||||
className={CLASSES.SHAPE_ACTIONS_MENU}
|
||||
padding={2}
|
||||
style={{
|
||||
// we want to make sure this doesn't overflow so substracting 200
|
||||
// which is approximately height of zoom footer and top left menu items with some buffer
|
||||
maxHeight: `${appState.height - 200}px`,
|
||||
}}
|
||||
>
|
||||
<SelectedShapeActions
|
||||
appState={appState}
|
||||
elements={elements}
|
||||
@ -603,18 +611,6 @@ const LayerUI = ({
|
||||
>
|
||||
{t("buttons.exitZenMode")}
|
||||
</button>
|
||||
{appState.scrolledOutside && (
|
||||
<button
|
||||
className="scroll-back-to-content"
|
||||
onClick={() => {
|
||||
setAppState({
|
||||
...calculateScrollCenter(elements, appState, canvas),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("buttons.scrollBackToContent")}
|
||||
</button>
|
||||
)}
|
||||
</footer>
|
||||
);
|
||||
|
||||
@ -677,6 +673,18 @@ const LayerUI = ({
|
||||
{renderBottomAppMenu()}
|
||||
{renderGitHubCorner()}
|
||||
{renderFooter()}
|
||||
{appState.scrolledOutside && (
|
||||
<button
|
||||
className="scroll-back-to-content"
|
||||
onClick={() => {
|
||||
setAppState({
|
||||
...calculateScrollCenter(elements, appState, canvas),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("buttons.scrollBackToContent")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,8 +1,13 @@
|
||||
@import "../css/variables.module";
|
||||
|
||||
.excalidraw {
|
||||
&.excalidraw-modal-container {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.Modal {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@ -15,7 +20,7 @@
|
||||
}
|
||||
|
||||
.Modal__background {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@ -82,7 +87,7 @@
|
||||
}
|
||||
|
||||
.Modal__content {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
@ -54,7 +54,7 @@ const useBodyRoot = () => {
|
||||
?.classList.contains("Appearance_dark");
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("excalidraw");
|
||||
div.classList.add("excalidraw", "excalidraw-modal-container");
|
||||
|
||||
if (isDarkTheme) {
|
||||
div.classList.add("Appearance_dark");
|
||||
|
@ -1,14 +1,6 @@
|
||||
.excalidraw {
|
||||
.popover {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.popover .cover {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
@import "../css/variables.module";
|
||||
|
||||
.Stats {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
right: 12px;
|
||||
font-size: 12px;
|
||||
|
@ -11,7 +11,7 @@
|
||||
left: 50%;
|
||||
margin-left: -150px;
|
||||
padding: 4px 0;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
z-index: 999999;
|
||||
|
@ -47,6 +47,7 @@ export enum EVENT {
|
||||
TOUCH_END = "touchend",
|
||||
HASHCHANGE = "hashchange",
|
||||
VISIBILITY_CHANGE = "visibilitychange",
|
||||
SCROLL = "scroll",
|
||||
}
|
||||
|
||||
export const ENV = {
|
||||
@ -92,6 +93,7 @@ export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
||||
export const TITLE_TIMEOUT = 10000;
|
||||
export const TOAST_TIMEOUT = 5000;
|
||||
export const VERSION_TIMEOUT = 30000;
|
||||
export const SCROLL_TIMEOUT = 500;
|
||||
|
||||
export const ZOOM_STEP = 0.1;
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
.excalidraw {
|
||||
color: var(--text-color-primary);
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@ -362,7 +361,6 @@
|
||||
|
||||
.App-menu__left {
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 236px);
|
||||
}
|
||||
|
||||
.dropdown-select {
|
||||
@ -434,7 +432,7 @@
|
||||
|
||||
.scroll-back-to-content {
|
||||
color: var(--popup-text-color);
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 30px;
|
||||
transform: translateX(-50%);
|
||||
|
@ -12,6 +12,20 @@ The change should be grouped under one of the below section and must contain PR
|
||||
Please add the latest change on the top under the correct section.
|
||||
-->
|
||||
|
||||
## 0.3.1
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
### Fixes
|
||||
|
||||
- Support Excalidraw inside scrollable container [#3018](https://github.com/excalidraw/excalidraw/pull/3018)
|
||||
|
||||
## Excalidraw Library
|
||||
|
||||
### Fixes
|
||||
|
||||
- Allow to toggle between modes when view only mode to make UI consistent [#3009](https://github.com/excalidraw/excalidraw/pull/3009)
|
||||
|
||||
## 0.3.0
|
||||
|
||||
## Excalidraw API
|
||||
|
@ -37,18 +37,18 @@ You can update the value of `PUBLIC_URL` if you want to serve it from a differen
|
||||
1. If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module as shown below
|
||||
|
||||
```js
|
||||
import React, { useEffect, useState, createRef } from "react";
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import Excalidraw from "@excalidraw/excalidraw";
|
||||
import InitialData from "./initialData";
|
||||
|
||||
import "./styles.css";
|
||||
import "./styles.scss";
|
||||
|
||||
export default function App() {
|
||||
const excalidrawRef = createRef();
|
||||
|
||||
const excalidrawRef = useRef(null);
|
||||
const excalidrawWrapperRef = useRef(null);
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
});
|
||||
|
||||
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
||||
@ -56,17 +56,21 @@ export default function App() {
|
||||
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDimensions({
|
||||
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||
height: excalidrawWrapperRef.current.getBoundingClientRect().height,
|
||||
});
|
||||
const onResize = () => {
|
||||
setDimensions({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
width: excalidrawWrapperRef.current.getBoundingClientRect().width,
|
||||
height: excalidrawWrapperRef.current.getBoundingClientRect().height,
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener("resize", onResize);
|
||||
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, []);
|
||||
}, [excalidrawWrapperRef]);
|
||||
|
||||
const updateScene = () => {
|
||||
const sceneData = {
|
||||
@ -102,6 +106,7 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1> Excalidraw Example</h1>
|
||||
<div className="button-wrapper">
|
||||
<button className="update-scene" onClick={updateScene}>
|
||||
Update Scene
|
||||
@ -139,7 +144,7 @@ export default function App() {
|
||||
Grid mode
|
||||
</label>
|
||||
</div>
|
||||
<div className="excalidraw-wrapper">
|
||||
<div className="excalidraw-wrapper" ref={excalidrawWrapperRef}>
|
||||
<Excalidraw
|
||||
ref={excalidrawRef}
|
||||
width={dimensions.width}
|
||||
@ -148,7 +153,6 @@ export default function App() {
|
||||
onChange={(elements, state) =>
|
||||
console.log("Elements :", elements, "State : ", state)
|
||||
}
|
||||
user={{ name: "Excalidraw User" }}
|
||||
onPointerUpdate={(payload) => console.log(payload)}
|
||||
onCollabButtonClick={() =>
|
||||
window.alert("You clicked on collab button")
|
||||
|
2
src/packages/excalidraw/package-lock.json
generated
2
src/packages/excalidraw/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@excalidraw/excalidraw",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@excalidraw/excalidraw",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"main": "dist/excalidraw.min.js",
|
||||
"files": [
|
||||
"dist/*"
|
||||
|
Loading…
x
Reference in New Issue
Block a user