diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx
index 897bc09a..e23b02d0 100644
--- a/src/components/Actions.tsx
+++ b/src/components/Actions.tsx
@@ -31,12 +31,10 @@ export const SelectedShapeActions = ({
appState,
elements,
renderAction,
- activeTool,
}: {
appState: AppState;
elements: readonly ExcalidrawElement[];
renderAction: ActionManager["renderAction"];
- activeTool: AppState["activeTool"]["type"];
}) => {
const targetElements = getTargetElements(
getNonDeletedElements(elements),
@@ -56,13 +54,13 @@ export const SelectedShapeActions = ({
const isRTL = document.documentElement.getAttribute("dir") === "rtl";
const showFillIcons =
- hasBackground(activeTool) ||
+ hasBackground(appState.activeTool.type) ||
targetElements.some(
(element) =>
hasBackground(element.type) && !isTransparent(element.backgroundColor),
);
const showChangeBackgroundIcons =
- hasBackground(activeTool) ||
+ hasBackground(appState.activeTool.type) ||
targetElements.some((element) => hasBackground(element.type));
const showLinkIcon =
@@ -79,23 +77,23 @@ export const SelectedShapeActions = ({
return (
- {((hasStrokeColor(activeTool) &&
- activeTool !== "image" &&
+ {((hasStrokeColor(appState.activeTool.type) &&
+ appState.activeTool.type !== "image" &&
commonSelectedType !== "image") ||
targetElements.some((element) => hasStrokeColor(element.type))) &&
renderAction("changeStrokeColor")}
{showChangeBackgroundIcons && renderAction("changeBackgroundColor")}
{showFillIcons && renderAction("changeFillStyle")}
- {(hasStrokeWidth(activeTool) ||
+ {(hasStrokeWidth(appState.activeTool.type) ||
targetElements.some((element) => hasStrokeWidth(element.type))) &&
renderAction("changeStrokeWidth")}
- {(activeTool === "freedraw" ||
+ {(appState.activeTool.type === "freedraw" ||
targetElements.some((element) => element.type === "freedraw")) &&
renderAction("changeStrokeShape")}
- {(hasStrokeStyle(activeTool) ||
+ {(hasStrokeStyle(appState.activeTool.type) ||
targetElements.some((element) => hasStrokeStyle(element.type))) && (
<>
{renderAction("changeStrokeStyle")}
@@ -103,12 +101,12 @@ export const SelectedShapeActions = ({
>
)}
- {(canChangeSharpness(activeTool) ||
+ {(canChangeSharpness(appState.activeTool.type) ||
targetElements.some((element) => canChangeSharpness(element.type))) && (
<>{renderAction("changeSharpness")}>
)}
- {(hasText(activeTool) ||
+ {(hasText(appState.activeTool.type) ||
targetElements.some((element) => hasText(element.type))) && (
<>
{renderAction("changeFontSize")}
@@ -123,7 +121,7 @@ export const SelectedShapeActions = ({
(element) =>
hasBoundTextElement(element) || isBoundToContainer(element),
) && renderAction("changeVerticalAlign")}
- {(canHaveArrowheads(activeTool) ||
+ {(canHaveArrowheads(appState.activeTool.type) ||
targetElements.some((element) => canHaveArrowheads(element.type))) && (
<>{renderAction("changeArrowhead")}>
)}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 4314c3d3..91a6cbe7 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -272,6 +272,7 @@ const deviceContextInitialValue = {
};
const DeviceContext = React.createContext
(deviceContextInitialValue);
export const useDevice = () => useContext(DeviceContext);
+
const ExcalidrawContainerContext = React.createContext<{
container: HTMLDivElement | null;
id: string | null;
@@ -279,6 +280,22 @@ const ExcalidrawContainerContext = React.createContext<{
export const useExcalidrawContainer = () =>
useContext(ExcalidrawContainerContext);
+const ExcalidrawElementsContext = React.createContext<
+ readonly NonDeletedExcalidrawElement[]
+>([]);
+
+const ExcalidrawAppStateContext = React.createContext({
+ ...getDefaultAppState(),
+ width: 0,
+ height: 0,
+ offsetLeft: 0,
+ offsetTop: 0,
+});
+export const useExcalidrawElements = () =>
+ useContext(ExcalidrawElementsContext);
+export const useExcalidrawAppState = () =>
+ useContext(ExcalidrawAppStateContext);
+
let didTapTwice: boolean = false;
let tappedTwiceTimer = 0;
let cursorX = 0;
@@ -505,63 +522,69 @@ class App extends React.Component {
value={this.excalidrawContainerValue}
>
-
- this.addElementsFromPasteOrLibrary({
- elements,
- position: "center",
- files: null,
- })
- }
- langCode={getLanguage().code}
- isCollaborating={this.props.isCollaborating}
- renderTopRightUI={renderTopRightUI}
- renderCustomFooter={renderFooter}
- renderCustomStats={renderCustomStats}
- showExitZenModeBtn={
- typeof this.props?.zenModeEnabled === "undefined" &&
- this.state.zenModeEnabled
- }
- showThemeBtn={
- typeof this.props?.theme === "undefined" &&
- this.props.UIOptions.canvasActions.theme
- }
- libraryReturnUrl={this.props.libraryReturnUrl}
- UIOptions={this.props.UIOptions}
- focusContainer={this.focusContainer}
- library={this.library}
- id={this.id}
- onImageAction={this.onImageAction}
- />
-
-
- {selectedElement.length === 1 && this.state.showHyperlinkPopup && (
-
- )}
- {this.state.toast !== null && (
- this.setToast(null)}
- duration={this.state.toast.duration}
- closable={this.state.toast.closable}
- />
- )}
- {this.renderCanvas()}
+
+
+
+ this.addElementsFromPasteOrLibrary({
+ elements,
+ position: "center",
+ files: null,
+ })
+ }
+ langCode={getLanguage().code}
+ isCollaborating={this.props.isCollaborating}
+ renderTopRightUI={renderTopRightUI}
+ renderCustomFooter={renderFooter}
+ renderCustomStats={renderCustomStats}
+ showExitZenModeBtn={
+ typeof this.props?.zenModeEnabled === "undefined" &&
+ this.state.zenModeEnabled
+ }
+ showThemeBtn={
+ typeof this.props?.theme === "undefined" &&
+ this.props.UIOptions.canvasActions.theme
+ }
+ libraryReturnUrl={this.props.libraryReturnUrl}
+ UIOptions={this.props.UIOptions}
+ focusContainer={this.focusContainer}
+ library={this.library}
+ id={this.id}
+ onImageAction={this.onImageAction}
+ />
+
+
+ {selectedElement.length === 1 &&
+ this.state.showHyperlinkPopup && (
+
+ )}
+ {this.state.toast !== null && (
+ this.setToast(null)}
+ duration={this.state.toast.duration}
+ closable={this.state.toast.closable}
+ />
+ )}
+ {this.renderCanvas()}
+ {" "}
+
diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx
index 845aabf5..168e701d 100644
--- a/src/components/LayerUI.tsx
+++ b/src/components/LayerUI.tsx
@@ -71,8 +71,8 @@ const LayerUI = ({
appState,
files,
setAppState,
- canvas,
elements,
+ canvas,
onCollabButtonClick,
onLockToggle,
onPenModeToggle,
@@ -210,8 +210,8 @@ const LayerUI = ({
)}
@@ -244,7 +244,6 @@ const LayerUI = ({
appState={appState}
elements={elements}
renderAction={actionManager.renderAction}
- activeTool={appState.activeTool.type}
/>
@@ -279,7 +278,6 @@ const LayerUI = ({
libraryReturnUrl={libraryReturnUrl}
focusContainer={focusContainer}
library={library}
- theme={appState.theme}
files={files}
id={id}
appState={appState}
diff --git a/src/components/LibraryMenu.tsx b/src/components/LibraryMenu.tsx
index 5ba502f9..c9fc7570 100644
--- a/src/components/LibraryMenu.tsx
+++ b/src/components/LibraryMenu.tsx
@@ -80,7 +80,6 @@ export const LibraryMenu = ({
onInsertLibraryItems,
pendingElements,
onAddToLibrary,
- theme,
setAppState,
files,
libraryReturnUrl,
@@ -93,7 +92,6 @@ export const LibraryMenu = ({
onClose: () => void;
onInsertLibraryItems: (libraryItems: LibraryItems) => void;
onAddToLibrary: () => void;
- theme: AppState["theme"];
files: BinaryFiles;
setAppState: React.Component["setState"];
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
@@ -105,7 +103,6 @@ export const LibraryMenu = ({
const ref = useRef(null);
const device = useDevice();
-
useOnClickOutside(
ref,
useCallback(
@@ -290,7 +287,7 @@ export const LibraryMenu = ({
appState={appState}
libraryReturnUrl={libraryReturnUrl}
library={library}
- theme={theme}
+ theme={appState.theme}
files={files}
id={id}
selectedItems={selectedItems}
diff --git a/src/components/MobileMenu.tsx b/src/components/MobileMenu.tsx
index 42b56422..a8a30282 100644
--- a/src/components/MobileMenu.tsx
+++ b/src/components/MobileMenu.tsx
@@ -221,7 +221,6 @@ export const MobileMenu = ({
appState={appState}
elements={elements}
renderAction={actionManager.renderAction}
- activeTool={appState.activeTool.type}
/>
) : null}
diff --git a/src/element/Hyperlink.tsx b/src/element/Hyperlink.tsx
index 509af764..37ed2b09 100644
--- a/src/element/Hyperlink.tsx
+++ b/src/element/Hyperlink.tsx
@@ -32,6 +32,7 @@ import { getElementAbsoluteCoords } from "./";
import "./Hyperlink.scss";
import { trackEvent } from "../analytics";
+import { useExcalidrawAppState } from "../components/App";
const CONTAINER_WIDTH = 320;
const SPACE_BOTTOM = 85;
@@ -48,15 +49,15 @@ let IS_HYPERLINK_TOOLTIP_VISIBLE = false;
export const Hyperlink = ({
element,
- appState,
setAppState,
onLinkOpen,
}: {
element: NonDeletedExcalidrawElement;
- appState: AppState;
setAppState: React.Component["setState"];
onLinkOpen: ExcalidrawProps["onLinkOpen"];
}) => {
+ const appState = useExcalidrawAppState();
+
const linkVal = element.link || "";
const [inputVal, setInputVal] = useState(linkVal);