(undefined);
- const [focusIndex, setFocusIndex] = useAtom(
- searchItemInFocusAtom,
- jotaiScope,
- );
+ const [focusIndex, setFocusIndex] = useAtom(searchItemInFocusAtom);
const elementsMap = app.scene.getNonDeletedElementsMap();
useEffect(() => {
diff --git a/packages/excalidraw/components/Sidebar/Sidebar.tsx b/packages/excalidraw/components/Sidebar/Sidebar.tsx
index efa6ccbe3dfc..0eb61d9383c7 100644
--- a/packages/excalidraw/components/Sidebar/Sidebar.tsx
+++ b/packages/excalidraw/components/Sidebar/Sidebar.tsx
@@ -8,8 +8,8 @@ import React, {
useCallback,
} from "react";
import { Island } from "../Island";
-import { atom, useSetAtom } from "jotai";
-import { jotaiScope } from "../../jotai";
+import { atom } from "jotai";
+import { useSetAtom } from "../../jotai";
import type { SidebarProps, SidebarPropsContextValue } from "./common";
import { SidebarPropsContext } from "./common";
import { SidebarHeader } from "./SidebarHeader";
@@ -58,7 +58,7 @@ export const SidebarInner = forwardRef(
const setAppState = useExcalidrawSetAppState();
- const setIsSidebarDockedAtom = useSetAtom(isSidebarDockedAtom, jotaiScope);
+ const setIsSidebarDockedAtom = useSetAtom(isSidebarDockedAtom);
useLayoutEffect(() => {
setIsSidebarDockedAtom(!!docked);
diff --git a/packages/excalidraw/components/TTDDialog/TTDDialog.tsx b/packages/excalidraw/components/TTDDialog/TTDDialog.tsx
index f0c63770adc0..2b2ffbc94ad9 100644
--- a/packages/excalidraw/components/TTDDialog/TTDDialog.tsx
+++ b/packages/excalidraw/components/TTDDialog/TTDDialog.tsx
@@ -25,7 +25,8 @@ import type { BinaryFiles } from "../../types";
import { ArrowRightIcon } from "../icons";
import "./TTDDialog.scss";
-import { atom, useAtom } from "jotai";
+import { atom } from "jotai";
+import { useAtom } from "../../jotai";
import { trackEvent } from "../../analytics";
import { InlineIcon } from "../InlineIcon";
import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
diff --git a/packages/excalidraw/components/Trans.test.tsx b/packages/excalidraw/components/Trans.test.tsx
index df8ec526ea0a..cd911b099c6f 100644
--- a/packages/excalidraw/components/Trans.test.tsx
+++ b/packages/excalidraw/components/Trans.test.tsx
@@ -4,6 +4,7 @@ import fallbackLangData from "../locales/en.json";
import Trans from "./Trans";
import type { TranslationKeys } from "../i18n";
+import { Provider } from "../jotai";
describe("Test ", () => {
it("should translate the the strings correctly", () => {
@@ -17,7 +18,7 @@ describe("Test ", () => {
};
const { getByTestId } = render(
- <>
+
", () => {
connect-link={(el) =>
{el}}
/>
- >,
+ ,
);
expect(getByTestId("test1").innerHTML).toEqual("Hello world");
diff --git a/packages/excalidraw/components/hoc/withInternalFallback.tsx b/packages/excalidraw/components/hoc/withInternalFallback.tsx
index 4131c51ec9f0..e0abc0d662ea 100644
--- a/packages/excalidraw/components/hoc/withInternalFallback.tsx
+++ b/packages/excalidraw/components/hoc/withInternalFallback.tsx
@@ -1,4 +1,4 @@
-import { atom, useAtom } from "jotai";
+import { atom } from "jotai";
import React, { useLayoutEffect, useRef } from "react";
import { useTunnels } from "../../context/tunnels";
@@ -13,9 +13,11 @@ export const withInternalFallback = (
__fallback?: boolean;
}
> = (props) => {
- const { jotaiScope } = useTunnels();
+ const {
+ jotai: { useAtom },
+ } = useTunnels();
// for rerenders
- const [, setCounter] = useAtom(renderAtom, jotaiScope);
+ const [, setCounter] = useAtom(renderAtom);
// for initial & subsequent renders. Tracked as component state
// due to excalidraw multi-instance scanerios.
const metaRef = useRef({
diff --git a/packages/excalidraw/components/main-menu/DefaultItems.tsx b/packages/excalidraw/components/main-menu/DefaultItems.tsx
index 7a9dce84a753..17ede8c66238 100644
--- a/packages/excalidraw/components/main-menu/DefaultItems.tsx
+++ b/packages/excalidraw/components/main-menu/DefaultItems.tsx
@@ -32,9 +32,8 @@ import {
actionToggleTheme,
} from "../../actions";
import clsx from "clsx";
-import { useSetAtom } from "jotai";
import { activeConfirmDialogAtom } from "../ActiveConfirmDialog";
-import { jotaiScope } from "../../jotai";
+import { useSetAtom } from "../../jotai";
import { useUIAppState } from "../../context/ui-appState";
import { openConfirmModal } from "../OverwriteConfirm/OverwriteConfirmState";
import Trans from "../Trans";
@@ -189,10 +188,7 @@ Help.displayName = "Help";
export const ClearCanvas = () => {
const { t } = useI18n();
- const setActiveConfirmDialog = useSetAtom(
- activeConfirmDialogAtom,
- jotaiScope,
- );
+ const setActiveConfirmDialog = useSetAtom(activeConfirmDialogAtom);
const actionManager = useExcalidrawActionManager();
if (!actionManager.isActionEnabled(actionClearCanvas)) {
diff --git a/packages/excalidraw/context/tunnels.ts b/packages/excalidraw/context/tunnels.ts
index 8dc325ff9667..712a0e22a4a4 100644
--- a/packages/excalidraw/context/tunnels.ts
+++ b/packages/excalidraw/context/tunnels.ts
@@ -1,5 +1,6 @@
import React from "react";
import tunnel from "tunnel-rat";
+import { createIsolation } from "jotai-scope";
export type Tunnel = ReturnType;
@@ -14,13 +15,15 @@ type TunnelsContextValue = {
DefaultSidebarTabTriggersTunnel: Tunnel;
OverwriteConfirmDialogTunnel: Tunnel;
TTDDialogTriggerTunnel: Tunnel;
- jotaiScope: symbol;
+ jotai: ReturnType;
};
export const TunnelsContext = React.createContext(null!);
export const useTunnels = () => React.useContext(TunnelsContext);
+const isolatedJotai = createIsolation();
+
export const useInitializeTunnels = () => {
return React.useMemo((): TunnelsContextValue => {
return {
@@ -34,7 +37,7 @@ export const useInitializeTunnels = () => {
DefaultSidebarTabTriggersTunnel: tunnel(),
OverwriteConfirmDialogTunnel: tunnel(),
TTDDialogTriggerTunnel: tunnel(),
- jotaiScope: Symbol(),
+ jotai: isolatedJotai,
};
}, []);
};
diff --git a/packages/excalidraw/hooks/useLibraryItemSvg.ts b/packages/excalidraw/hooks/useLibraryItemSvg.ts
index dc8cac3c9928..618ddf0ec8cc 100644
--- a/packages/excalidraw/hooks/useLibraryItemSvg.ts
+++ b/packages/excalidraw/hooks/useLibraryItemSvg.ts
@@ -1,7 +1,7 @@
-import { atom, useAtom } from "jotai";
+import { atom } from "jotai";
import { useEffect, useState } from "react";
import { COLOR_PALETTE } from "../colors";
-import { jotaiScope } from "../jotai";
+import { useAtom } from "../jotai";
import { exportToSvg } from "../../utils/export";
import type { LibraryItem } from "../types";
@@ -68,7 +68,7 @@ export const useLibraryItemSvg = (
};
export const useLibraryCache = () => {
- const [svgCache] = useAtom(libraryItemSvgsCache, jotaiScope);
+ const [svgCache] = useAtom(libraryItemSvgsCache);
const clearLibraryCache = () => svgCache.clear();
diff --git a/packages/excalidraw/hooks/useScrollPosition.ts b/packages/excalidraw/hooks/useScrollPosition.ts
index e4efb460ea5f..6d53c30d6e07 100644
--- a/packages/excalidraw/hooks/useScrollPosition.ts
+++ b/packages/excalidraw/hooks/useScrollPosition.ts
@@ -1,5 +1,6 @@
import { useEffect } from "react";
-import { atom, useAtom } from "jotai";
+import { atom } from "jotai";
+import { useAtom } from "../jotai";
import throttle from "lodash.throttle";
const scrollPositionAtom = atom(0);
diff --git a/packages/excalidraw/i18n.ts b/packages/excalidraw/i18n.ts
index 10373ef56a52..e9d67a7e05e7 100644
--- a/packages/excalidraw/i18n.ts
+++ b/packages/excalidraw/i18n.ts
@@ -1,7 +1,7 @@
import fallbackLangData from "./locales/en.json";
import percentages from "./locales/percentages.json";
-import { jotaiScope, jotaiStore } from "./jotai";
-import { atom, useAtomValue } from "jotai";
+import { useAtomValue, jotaiStore } from "./jotai";
+import { atom } from "jotai";
import type { NestedKeyOf } from "./utility-types";
const COMPLETION_THRESHOLD = 85;
@@ -165,6 +165,6 @@ const editorLangCodeAtom = atom(defaultLang.code);
// - component is rendered internally by , but the component
// is memoized w/o being updated on `langCode`, `AppState`, or `UIAppState`
export const useI18n = () => {
- const langCode = useAtomValue(editorLangCodeAtom, jotaiScope);
+ const langCode = useAtomValue(editorLangCodeAtom);
return { t, langCode };
};
diff --git a/packages/excalidraw/index.tsx b/packages/excalidraw/index.tsx
index ae94c78b5671..4379b5fad9be 100644
--- a/packages/excalidraw/index.tsx
+++ b/packages/excalidraw/index.tsx
@@ -11,8 +11,7 @@ import "./fonts/fonts.css";
import type { AppProps, ExcalidrawProps } from "./types";
import { defaultLang } from "./i18n";
import { DEFAULT_UI_OPTIONS } from "./constants";
-import { Provider } from "jotai";
-import { jotaiScope, jotaiStore } from "./jotai";
+import { Provider, jotaiStore } from "./jotai";
import Footer from "./components/footer/FooterCenter";
import MainMenu from "./components/main-menu/MainMenu";
import WelcomeScreen from "./components/welcome-screen/WelcomeScreen";
@@ -114,7 +113,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
}, []);
return (
- jotaiStore} scope={jotaiScope}>
+
["Provider"] =
+ jotai.Provider;
+
+export const jotaiStore: ReturnType = createStore();
export const useAtomWithInitialValue = <
T extends unknown,
@@ -12,7 +17,7 @@ export const useAtomWithInitialValue = <
atom: A,
initialValue: T | (() => T),
) => {
- const [value, setValue] = useAtom(atom);
+ const [value, setValue] = _useAtom(atom);
useLayoutEffect(() => {
if (typeof initialValue === "function") {
diff --git a/packages/excalidraw/package.json b/packages/excalidraw/package.json
index 53715d9cc20a..bb14572447cd 100644
--- a/packages/excalidraw/package.json
+++ b/packages/excalidraw/package.json
@@ -52,7 +52,8 @@
"fractional-indexing": "3.2.0",
"fuzzy": "0.1.3",
"image-blob-reduce": "3.0.1",
- "jotai": "1.13.1",
+ "jotai": "2.11.0",
+ "jotai-scope": "0.7.2",
"lodash.throttle": "4.1.1",
"nanoid": "3.3.3",
"open-color": "1.9.1",
diff --git a/yarn.lock b/yarn.lock
index b97d9a706a5b..7eb706e64f05 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7339,10 +7339,15 @@ jest-worker@^27.4.5:
merge-stream "^2.0.0"
supports-color "^8.0.0"
-jotai@1.13.1:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/jotai/-/jotai-1.13.1.tgz#20cc46454cbb39096b12fddfa635b873b3668236"
- integrity sha512-RUmH1S4vLsG3V6fbGlKzGJnLrDcC/HNb5gH2AeA9DzuJknoVxSGvvg8OBB7lke+gDc4oXmdVsaKn/xDUhWZ0vw==
+jotai-scope@0.7.2:
+ version "0.7.2"
+ resolved "https://registry.yarnpkg.com/jotai-scope/-/jotai-scope-0.7.2.tgz#3e9ec5b743bd9f36b08b32cf5151786049bfcce7"
+ integrity sha512-Gwed97f3dDObrO43++2lRcgOqw4O2sdr4JCjP/7eHK1oPACDJ7xKHGScpJX9XaflU+KBHXF+VhwECnzcaQiShg==
+
+jotai@2.11.0:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.11.0.tgz#923f8351e0b2d721036af892c0ae25625049d120"
+ integrity sha512-zKfoBBD1uDw3rljwHkt0fWuja1B76R7CjznuBO+mSX6jpsO1EBeWNRKpeaQho9yPI/pvCv4recGfgOXGxwPZvQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"