fix: Apply theme to only to active excalidraw component (#3446)
* feat: Apply theme to only current instance of excalidraw * fix * fix * fix * fix * fix * update changelog * fix
This commit is contained in:
parent
e0a449aa40
commit
793b69e592
@ -188,8 +188,13 @@ import { Stats } from "./Stats";
|
||||
import { Toast } from "./Toast";
|
||||
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
||||
|
||||
export const IsMobileContext = React.createContext(false);
|
||||
const IsMobileContext = React.createContext(false);
|
||||
export const useIsMobile = () => useContext(IsMobileContext);
|
||||
const ExcalidrawContainerContext = React.createContext<HTMLDivElement | null>(
|
||||
null,
|
||||
);
|
||||
export const useExcalidrawContainer = () =>
|
||||
useContext(ExcalidrawContainerContext);
|
||||
|
||||
const { history } = createHistory();
|
||||
|
||||
@ -305,6 +310,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
private scene: Scene;
|
||||
private resizeObserver: ResizeObserver | undefined;
|
||||
private nearestScrollableContainer: HTMLElement | Document | undefined;
|
||||
|
||||
constructor(props: AppProps) {
|
||||
super(props);
|
||||
const defaultAppState = getDefaultAppState();
|
||||
@ -328,6 +334,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
};
|
||||
|
||||
if (excalidrawRef) {
|
||||
const readyPromise =
|
||||
("current" in excalidrawRef && excalidrawRef.current?.readyPromise) ||
|
||||
@ -456,60 +463,64 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.props.handleKeyboardGlobally ? undefined : this.onKeyDown
|
||||
}
|
||||
>
|
||||
<IsMobileContext.Provider value={this.isMobile}>
|
||||
<LayerUI
|
||||
canvas={this.canvas}
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
actionManager={this.actionManager}
|
||||
elements={this.scene.getElements()}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
onLockToggle={this.toggleLock}
|
||||
onInsertElements={(elements) =>
|
||||
this.addElementsFromPasteOrLibrary(
|
||||
elements,
|
||||
DEFAULT_PASTE_X,
|
||||
DEFAULT_PASTE_Y,
|
||||
)
|
||||
}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
toggleZenMode={this.toggleZenMode}
|
||||
langCode={getLanguage().code}
|
||||
isCollaborating={this.props.isCollaborating || false}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderCustomFooter={renderFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" &&
|
||||
zenModeEnabled
|
||||
}
|
||||
showThemeBtn={
|
||||
typeof this.props?.theme === "undefined" &&
|
||||
this.props.UIOptions.canvasActions.theme
|
||||
}
|
||||
libraryReturnUrl={this.props.libraryReturnUrl}
|
||||
UIOptions={this.props.UIOptions}
|
||||
focusContainer={this.focusContainer}
|
||||
/>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
<div className="excalidraw-contextMenuContainer" />
|
||||
{this.state.showStats && (
|
||||
<Stats
|
||||
<ExcalidrawContainerContext.Provider
|
||||
value={this.excalidrawContainerRef.current}
|
||||
>
|
||||
<IsMobileContext.Provider value={this.isMobile}>
|
||||
<LayerUI
|
||||
canvas={this.canvas}
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
actionManager={this.actionManager}
|
||||
elements={this.scene.getElements()}
|
||||
onClose={this.toggleStats}
|
||||
renderCustomStats={renderCustomStats}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
onLockToggle={this.toggleLock}
|
||||
onInsertElements={(elements) =>
|
||||
this.addElementsFromPasteOrLibrary(
|
||||
elements,
|
||||
DEFAULT_PASTE_X,
|
||||
DEFAULT_PASTE_Y,
|
||||
)
|
||||
}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
toggleZenMode={this.toggleZenMode}
|
||||
langCode={getLanguage().code}
|
||||
isCollaborating={this.props.isCollaborating || false}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderCustomFooter={renderFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" &&
|
||||
zenModeEnabled
|
||||
}
|
||||
showThemeBtn={
|
||||
typeof this.props?.theme === "undefined" &&
|
||||
this.props.UIOptions.canvasActions.theme
|
||||
}
|
||||
libraryReturnUrl={this.props.libraryReturnUrl}
|
||||
UIOptions={this.props.UIOptions}
|
||||
focusContainer={this.focusContainer}
|
||||
/>
|
||||
)}
|
||||
{this.state.toastMessage !== null && (
|
||||
<Toast
|
||||
message={this.state.toastMessage}
|
||||
clearToast={this.clearToast}
|
||||
/>
|
||||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</IsMobileContext.Provider>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
<div className="excalidraw-contextMenuContainer" />
|
||||
{this.state.showStats && (
|
||||
<Stats
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
elements={this.scene.getElements()}
|
||||
onClose={this.toggleStats}
|
||||
renderCustomStats={renderCustomStats}
|
||||
/>
|
||||
)}
|
||||
{this.state.toastMessage !== null && (
|
||||
<Toast
|
||||
message={this.state.toastMessage}
|
||||
clearToast={this.clearToast}
|
||||
/>
|
||||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</IsMobileContext.Provider>
|
||||
</ExcalidrawContainerContext.Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -988,9 +999,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||
});
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.toggle("theme--dark", this.state.theme === "dark");
|
||||
this.excalidrawContainerRef.current?.classList.toggle(
|
||||
"theme--dark",
|
||||
this.state.theme === "dark",
|
||||
);
|
||||
|
||||
if (
|
||||
this.state.editingLinearElement &&
|
||||
|
@ -8,6 +8,7 @@ import "./Dialog.scss";
|
||||
import { back, close } from "./icons";
|
||||
import { Island } from "./Island";
|
||||
import { Modal } from "./Modal";
|
||||
import { AppState } from "../types";
|
||||
|
||||
export const Dialog = (props: {
|
||||
children: React.ReactNode;
|
||||
@ -16,6 +17,7 @@ export const Dialog = (props: {
|
||||
onCloseRequest(): void;
|
||||
title: React.ReactNode;
|
||||
autofocus?: boolean;
|
||||
theme?: AppState["theme"];
|
||||
}) => {
|
||||
const [islandNode, setIslandNode] = useCallbackRefState<HTMLDivElement>();
|
||||
useEffect(() => {
|
||||
@ -70,6 +72,7 @@ export const Dialog = (props: {
|
||||
labelledBy="dialog-title"
|
||||
maxWidth={props.small ? 550 : 800}
|
||||
onCloseRequest={props.onCloseRequest}
|
||||
theme={props.theme}
|
||||
>
|
||||
<Island ref={setIslandNode}>
|
||||
<h2 id="dialog-title" className="Dialog__title">
|
||||
|
@ -4,7 +4,8 @@ import React, { useState, useLayoutEffect, useRef } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import clsx from "clsx";
|
||||
import { KEYS } from "../keys";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useExcalidrawContainer, useIsMobile } from "./App";
|
||||
import { AppState } from "../types";
|
||||
|
||||
export const Modal = (props: {
|
||||
className?: string;
|
||||
@ -12,8 +13,10 @@ export const Modal = (props: {
|
||||
maxWidth?: number;
|
||||
onCloseRequest(): void;
|
||||
labelledBy: string;
|
||||
theme?: AppState["theme"];
|
||||
}) => {
|
||||
const modalRoot = useBodyRoot();
|
||||
const { theme = "light" } = props;
|
||||
const modalRoot = useBodyRoot(theme);
|
||||
|
||||
if (!modalRoot) {
|
||||
return null;
|
||||
@ -48,13 +51,15 @@ export const Modal = (props: {
|
||||
);
|
||||
};
|
||||
|
||||
const useBodyRoot = () => {
|
||||
const useBodyRoot = (theme: AppState["theme"]) => {
|
||||
const [div, setDiv] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const isMobileRef = useRef(isMobile);
|
||||
isMobileRef.current = isMobile;
|
||||
|
||||
const excalidrawContainer = useExcalidrawContainer();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (div) {
|
||||
div.classList.toggle("excalidraw--mobile", isMobile);
|
||||
@ -62,9 +67,9 @@ const useBodyRoot = () => {
|
||||
}, [div, isMobile]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const isDarkTheme = !!document
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.contains("theme--dark");
|
||||
const isDarkTheme =
|
||||
!!excalidrawContainer?.classList.contains("theme--dark") ||
|
||||
theme === "dark";
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("excalidraw", "excalidraw-modal-container");
|
||||
@ -81,7 +86,7 @@ const useBodyRoot = () => {
|
||||
return () => {
|
||||
document.body.removeChild(div);
|
||||
};
|
||||
}, []);
|
||||
}, [excalidrawContainer, theme]);
|
||||
|
||||
return div;
|
||||
};
|
||||
|
@ -640,6 +640,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
|
||||
setErrorMessage={(errorMessage) => {
|
||||
this.setState({ errorMessage });
|
||||
}}
|
||||
theme={this.excalidrawAPI.getAppState().theme}
|
||||
/>
|
||||
)}
|
||||
{errorMessage && (
|
||||
|
@ -13,6 +13,7 @@ import { ToolButton } from "../../components/ToolButton";
|
||||
import { t } from "../../i18n";
|
||||
import "./RoomDialog.scss";
|
||||
import Stack from "../../components/Stack";
|
||||
import { AppState } from "../../types";
|
||||
|
||||
const getShareIcon = () => {
|
||||
const navigator = window.navigator as any;
|
||||
@ -36,6 +37,7 @@ const RoomDialog = ({
|
||||
onRoomCreate,
|
||||
onRoomDestroy,
|
||||
setErrorMessage,
|
||||
theme,
|
||||
}: {
|
||||
handleClose: () => void;
|
||||
activeRoomLink: string;
|
||||
@ -44,6 +46,7 @@ const RoomDialog = ({
|
||||
onRoomCreate: () => void;
|
||||
onRoomDestroy: () => void;
|
||||
setErrorMessage: (message: string) => void;
|
||||
theme: AppState["theme"];
|
||||
}) => {
|
||||
const roomLinkInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -168,6 +171,7 @@ const RoomDialog = ({
|
||||
small
|
||||
onCloseRequest={handleClose}
|
||||
title={t("labels.liveCollaboration")}
|
||||
theme={theme}
|
||||
>
|
||||
{renderRoomDialog()}
|
||||
</Dialog>
|
||||
|
@ -26,6 +26,10 @@ Please add the latest change on the top under the correct section.
|
||||
- Recompute offsets on `scroll` of the nearest scrollable container [#3408](https://github.com/excalidraw/excalidraw/pull/3408). This can be disabled by setting [`detectScroll`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#detectScroll) to `false`.
|
||||
- Add `onPaste` prop to handle custom clipboard behaviours [#3420](https://github.com/excalidraw/excalidraw/pull/3420).
|
||||
|
||||
### Fixes
|
||||
|
||||
- When switching theme, apply it only to the active Excalidraw component. This fixes a case where the theme was getting applied to the first Excalidraw component if you had multiple Excalidraw components on the same page [#3446](https://github.com/excalidraw/excalidraw/pull/3446)
|
||||
|
||||
## Types
|
||||
|
||||
- Renamed the following types in case you depend on them (via [#3427](https://github.com/excalidraw/excalidraw/pull/3427)):
|
||||
|
Loading…
x
Reference in New Issue
Block a user