|  | @@ -1,29 +1,15 @@
 | 
	
		
			
				|  |  |  import clsx from "clsx";
 | 
	
		
			
				|  |  | -import React, {
 | 
	
		
			
				|  |  | -  RefObject,
 | 
	
		
			
				|  |  | -  useCallback,
 | 
	
		
			
				|  |  | -  useEffect,
 | 
	
		
			
				|  |  | -  useRef,
 | 
	
		
			
				|  |  | -  useState,
 | 
	
		
			
				|  |  | -} from "react";
 | 
	
		
			
				|  |  | +import React, { useCallback } from "react";
 | 
	
		
			
				|  |  |  import { ActionManager } from "../actions/manager";
 | 
	
		
			
				|  |  |  import { CLASSES } from "../constants";
 | 
	
		
			
				|  |  |  import { exportCanvas } from "../data";
 | 
	
		
			
				|  |  | -import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json";
 | 
	
		
			
				|  |  |  import { isTextElement, showSelectedShapeActions } from "../element";
 | 
	
		
			
				|  |  |  import { NonDeletedExcalidrawElement } from "../element/types";
 | 
	
		
			
				|  |  |  import { Language, t } from "../i18n";
 | 
	
		
			
				|  |  |  import { useIsMobile } from "../components/App";
 | 
	
		
			
				|  |  |  import { calculateScrollCenter, getSelectedElements } from "../scene";
 | 
	
		
			
				|  |  |  import { ExportType } from "../scene/types";
 | 
	
		
			
				|  |  | -import {
 | 
	
		
			
				|  |  | -  AppProps,
 | 
	
		
			
				|  |  | -  AppState,
 | 
	
		
			
				|  |  | -  ExcalidrawProps,
 | 
	
		
			
				|  |  | -  BinaryFiles,
 | 
	
		
			
				|  |  | -  LibraryItem,
 | 
	
		
			
				|  |  | -  LibraryItems,
 | 
	
		
			
				|  |  | -} from "../types";
 | 
	
		
			
				|  |  | +import { AppProps, AppState, ExcalidrawProps, BinaryFiles } from "../types";
 | 
	
		
			
				|  |  |  import { muteFSAbortError } from "../utils";
 | 
	
		
			
				|  |  |  import { SelectedShapeActions, ShapesSwitcher, ZoomActions } from "./Actions";
 | 
	
		
			
				|  |  |  import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
 | 
	
	
		
			
				|  | @@ -32,10 +18,8 @@ import { ErrorDialog } from "./ErrorDialog";
 | 
	
		
			
				|  |  |  import { ExportCB, ImageExportDialog } from "./ImageExportDialog";
 | 
	
		
			
				|  |  |  import { FixedSideContainer } from "./FixedSideContainer";
 | 
	
		
			
				|  |  |  import { HintViewer } from "./HintViewer";
 | 
	
		
			
				|  |  | -import { exportFile, load, trash } from "./icons";
 | 
	
		
			
				|  |  |  import { Island } from "./Island";
 | 
	
		
			
				|  |  |  import "./LayerUI.scss";
 | 
	
		
			
				|  |  | -import { LibraryUnit } from "./LibraryUnit";
 | 
	
		
			
				|  |  |  import { LoadingMessage } from "./LoadingMessage";
 | 
	
		
			
				|  |  |  import { LockButton } from "./LockButton";
 | 
	
		
			
				|  |  |  import { MobileMenu } from "./MobileMenu";
 | 
	
	
		
			
				|  | @@ -43,13 +27,13 @@ import { PasteChartDialog } from "./PasteChartDialog";
 | 
	
		
			
				|  |  |  import { Section } from "./Section";
 | 
	
		
			
				|  |  |  import { HelpDialog } from "./HelpDialog";
 | 
	
		
			
				|  |  |  import Stack from "./Stack";
 | 
	
		
			
				|  |  | -import { ToolButton } from "./ToolButton";
 | 
	
		
			
				|  |  |  import { Tooltip } from "./Tooltip";
 | 
	
		
			
				|  |  |  import { UserList } from "./UserList";
 | 
	
		
			
				|  |  |  import Library from "../data/library";
 | 
	
		
			
				|  |  |  import { JSONExportDialog } from "./JSONExportDialog";
 | 
	
		
			
				|  |  |  import { LibraryButton } from "./LibraryButton";
 | 
	
		
			
				|  |  |  import { isImageFileHandle } from "../data/blob";
 | 
	
		
			
				|  |  | +import { LibraryMenu } from "./LibraryMenu";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  interface LayerUIProps {
 | 
	
		
			
				|  |  |    actionManager: ActionManager;
 | 
	
	
		
			
				|  | @@ -81,302 +65,6 @@ interface LayerUIProps {
 | 
	
		
			
				|  |  |    onImageAction: (data: { insertOnCanvasDirectly: boolean }) => void;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const useOnClickOutside = (
 | 
	
		
			
				|  |  | -  ref: RefObject<HTMLElement>,
 | 
	
		
			
				|  |  | -  cb: (event: MouseEvent) => void,
 | 
	
		
			
				|  |  | -) => {
 | 
	
		
			
				|  |  | -  useEffect(() => {
 | 
	
		
			
				|  |  | -    const listener = (event: MouseEvent) => {
 | 
	
		
			
				|  |  | -      if (!ref.current) {
 | 
	
		
			
				|  |  | -        return;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      if (
 | 
	
		
			
				|  |  | -        event.target instanceof Element &&
 | 
	
		
			
				|  |  | -        (ref.current.contains(event.target) ||
 | 
	
		
			
				|  |  | -          !document.body.contains(event.target))
 | 
	
		
			
				|  |  | -      ) {
 | 
	
		
			
				|  |  | -        return;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      cb(event);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -    document.addEventListener("pointerdown", listener, false);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return () => {
 | 
	
		
			
				|  |  | -      document.removeEventListener("pointerdown", listener);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -  }, [ref, cb]);
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const LibraryMenuItems = ({
 | 
	
		
			
				|  |  | -  libraryItems,
 | 
	
		
			
				|  |  | -  onRemoveFromLibrary,
 | 
	
		
			
				|  |  | -  onAddToLibrary,
 | 
	
		
			
				|  |  | -  onInsertShape,
 | 
	
		
			
				|  |  | -  pendingElements,
 | 
	
		
			
				|  |  | -  theme,
 | 
	
		
			
				|  |  | -  setAppState,
 | 
	
		
			
				|  |  | -  setLibraryItems,
 | 
	
		
			
				|  |  | -  libraryReturnUrl,
 | 
	
		
			
				|  |  | -  focusContainer,
 | 
	
		
			
				|  |  | -  library,
 | 
	
		
			
				|  |  | -  files,
 | 
	
		
			
				|  |  | -  id,
 | 
	
		
			
				|  |  | -}: {
 | 
	
		
			
				|  |  | -  libraryItems: LibraryItems;
 | 
	
		
			
				|  |  | -  pendingElements: LibraryItem;
 | 
	
		
			
				|  |  | -  onRemoveFromLibrary: (index: number) => void;
 | 
	
		
			
				|  |  | -  onInsertShape: (elements: LibraryItem) => void;
 | 
	
		
			
				|  |  | -  onAddToLibrary: (elements: LibraryItem) => void;
 | 
	
		
			
				|  |  | -  theme: AppState["theme"];
 | 
	
		
			
				|  |  | -  files: BinaryFiles;
 | 
	
		
			
				|  |  | -  setAppState: React.Component<any, AppState>["setState"];
 | 
	
		
			
				|  |  | -  setLibraryItems: (library: LibraryItems) => void;
 | 
	
		
			
				|  |  | -  libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
 | 
	
		
			
				|  |  | -  focusContainer: () => void;
 | 
	
		
			
				|  |  | -  library: Library;
 | 
	
		
			
				|  |  | -  id: string;
 | 
	
		
			
				|  |  | -}) => {
 | 
	
		
			
				|  |  | -  const isMobile = useIsMobile();
 | 
	
		
			
				|  |  | -  const numCells = libraryItems.length + (pendingElements.length > 0 ? 1 : 0);
 | 
	
		
			
				|  |  | -  const CELLS_PER_ROW = isMobile ? 4 : 6;
 | 
	
		
			
				|  |  | -  const numRows = Math.max(1, Math.ceil(numCells / CELLS_PER_ROW));
 | 
	
		
			
				|  |  | -  const rows = [];
 | 
	
		
			
				|  |  | -  let addedPendingElements = false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const referrer =
 | 
	
		
			
				|  |  | -    libraryReturnUrl || window.location.origin + window.location.pathname;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  rows.push(
 | 
	
		
			
				|  |  | -    <div className="layer-ui__library-header" key="library-header">
 | 
	
		
			
				|  |  | -      <ToolButton
 | 
	
		
			
				|  |  | -        key="import"
 | 
	
		
			
				|  |  | -        type="button"
 | 
	
		
			
				|  |  | -        title={t("buttons.load")}
 | 
	
		
			
				|  |  | -        aria-label={t("buttons.load")}
 | 
	
		
			
				|  |  | -        icon={load}
 | 
	
		
			
				|  |  | -        onClick={() => {
 | 
	
		
			
				|  |  | -          importLibraryFromJSON(library)
 | 
	
		
			
				|  |  | -            .then(() => {
 | 
	
		
			
				|  |  | -              // Close and then open to get the libraries updated
 | 
	
		
			
				|  |  | -              setAppState({ isLibraryOpen: false });
 | 
	
		
			
				|  |  | -              setAppState({ isLibraryOpen: true });
 | 
	
		
			
				|  |  | -            })
 | 
	
		
			
				|  |  | -            .catch(muteFSAbortError)
 | 
	
		
			
				|  |  | -            .catch((error) => {
 | 
	
		
			
				|  |  | -              setAppState({ errorMessage: error.message });
 | 
	
		
			
				|  |  | -            });
 | 
	
		
			
				|  |  | -        }}
 | 
	
		
			
				|  |  | -      />
 | 
	
		
			
				|  |  | -      {!!libraryItems.length && (
 | 
	
		
			
				|  |  | -        <>
 | 
	
		
			
				|  |  | -          <ToolButton
 | 
	
		
			
				|  |  | -            key="export"
 | 
	
		
			
				|  |  | -            type="button"
 | 
	
		
			
				|  |  | -            title={t("buttons.export")}
 | 
	
		
			
				|  |  | -            aria-label={t("buttons.export")}
 | 
	
		
			
				|  |  | -            icon={exportFile}
 | 
	
		
			
				|  |  | -            onClick={() => {
 | 
	
		
			
				|  |  | -              saveLibraryAsJSON(library)
 | 
	
		
			
				|  |  | -                .catch(muteFSAbortError)
 | 
	
		
			
				|  |  | -                .catch((error) => {
 | 
	
		
			
				|  |  | -                  setAppState({ errorMessage: error.message });
 | 
	
		
			
				|  |  | -                });
 | 
	
		
			
				|  |  | -            }}
 | 
	
		
			
				|  |  | -          />
 | 
	
		
			
				|  |  | -          <ToolButton
 | 
	
		
			
				|  |  | -            key="reset"
 | 
	
		
			
				|  |  | -            type="button"
 | 
	
		
			
				|  |  | -            title={t("buttons.resetLibrary")}
 | 
	
		
			
				|  |  | -            aria-label={t("buttons.resetLibrary")}
 | 
	
		
			
				|  |  | -            icon={trash}
 | 
	
		
			
				|  |  | -            onClick={() => {
 | 
	
		
			
				|  |  | -              if (window.confirm(t("alerts.resetLibrary"))) {
 | 
	
		
			
				|  |  | -                library.resetLibrary();
 | 
	
		
			
				|  |  | -                setLibraryItems([]);
 | 
	
		
			
				|  |  | -                focusContainer();
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -            }}
 | 
	
		
			
				|  |  | -          />
 | 
	
		
			
				|  |  | -        </>
 | 
	
		
			
				|  |  | -      )}
 | 
	
		
			
				|  |  | -      <a
 | 
	
		
			
				|  |  | -        href={`https://libraries.excalidraw.com?target=${
 | 
	
		
			
				|  |  | -          window.name || "_blank"
 | 
	
		
			
				|  |  | -        }&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}`}
 | 
	
		
			
				|  |  | -        target="_excalidraw_libraries"
 | 
	
		
			
				|  |  | -      >
 | 
	
		
			
				|  |  | -        {t("labels.libraries")}
 | 
	
		
			
				|  |  | -      </a>
 | 
	
		
			
				|  |  | -    </div>,
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  for (let row = 0; row < numRows; row++) {
 | 
	
		
			
				|  |  | -    const y = CELLS_PER_ROW * row;
 | 
	
		
			
				|  |  | -    const children = [];
 | 
	
		
			
				|  |  | -    for (let x = 0; x < CELLS_PER_ROW; x++) {
 | 
	
		
			
				|  |  | -      const shouldAddPendingElements: boolean =
 | 
	
		
			
				|  |  | -        pendingElements.length > 0 &&
 | 
	
		
			
				|  |  | -        !addedPendingElements &&
 | 
	
		
			
				|  |  | -        y + x >= libraryItems.length;
 | 
	
		
			
				|  |  | -      addedPendingElements = addedPendingElements || shouldAddPendingElements;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      children.push(
 | 
	
		
			
				|  |  | -        <Stack.Col key={x}>
 | 
	
		
			
				|  |  | -          <LibraryUnit
 | 
	
		
			
				|  |  | -            elements={libraryItems[y + x]}
 | 
	
		
			
				|  |  | -            files={files}
 | 
	
		
			
				|  |  | -            pendingElements={
 | 
	
		
			
				|  |  | -              shouldAddPendingElements ? pendingElements : undefined
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            onRemoveFromLibrary={onRemoveFromLibrary.bind(null, y + x)}
 | 
	
		
			
				|  |  | -            onClick={
 | 
	
		
			
				|  |  | -              shouldAddPendingElements
 | 
	
		
			
				|  |  | -                ? onAddToLibrary.bind(null, pendingElements)
 | 
	
		
			
				|  |  | -                : onInsertShape.bind(null, libraryItems[y + x])
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          />
 | 
	
		
			
				|  |  | -        </Stack.Col>,
 | 
	
		
			
				|  |  | -      );
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    rows.push(
 | 
	
		
			
				|  |  | -      <Stack.Row align="center" gap={1} key={row}>
 | 
	
		
			
				|  |  | -        {children}
 | 
	
		
			
				|  |  | -      </Stack.Row>,
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return (
 | 
	
		
			
				|  |  | -    <Stack.Col align="start" gap={1} className="layer-ui__library-items">
 | 
	
		
			
				|  |  | -      {rows}
 | 
	
		
			
				|  |  | -    </Stack.Col>
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const LibraryMenu = ({
 | 
	
		
			
				|  |  | -  onClickOutside,
 | 
	
		
			
				|  |  | -  onInsertShape,
 | 
	
		
			
				|  |  | -  pendingElements,
 | 
	
		
			
				|  |  | -  onAddToLibrary,
 | 
	
		
			
				|  |  | -  theme,
 | 
	
		
			
				|  |  | -  setAppState,
 | 
	
		
			
				|  |  | -  files,
 | 
	
		
			
				|  |  | -  libraryReturnUrl,
 | 
	
		
			
				|  |  | -  focusContainer,
 | 
	
		
			
				|  |  | -  library,
 | 
	
		
			
				|  |  | -  id,
 | 
	
		
			
				|  |  | -}: {
 | 
	
		
			
				|  |  | -  pendingElements: LibraryItem;
 | 
	
		
			
				|  |  | -  onClickOutside: (event: MouseEvent) => void;
 | 
	
		
			
				|  |  | -  onInsertShape: (elements: LibraryItem) => void;
 | 
	
		
			
				|  |  | -  onAddToLibrary: () => void;
 | 
	
		
			
				|  |  | -  theme: AppState["theme"];
 | 
	
		
			
				|  |  | -  files: BinaryFiles;
 | 
	
		
			
				|  |  | -  setAppState: React.Component<any, AppState>["setState"];
 | 
	
		
			
				|  |  | -  libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
 | 
	
		
			
				|  |  | -  focusContainer: () => void;
 | 
	
		
			
				|  |  | -  library: Library;
 | 
	
		
			
				|  |  | -  id: string;
 | 
	
		
			
				|  |  | -}) => {
 | 
	
		
			
				|  |  | -  const ref = useRef<HTMLDivElement | null>(null);
 | 
	
		
			
				|  |  | -  useOnClickOutside(ref, (event) => {
 | 
	
		
			
				|  |  | -    // If click on the library icon, do nothing.
 | 
	
		
			
				|  |  | -    if ((event.target as Element).closest(".ToolIcon_type_button__library")) {
 | 
	
		
			
				|  |  | -      return;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    onClickOutside(event);
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const [libraryItems, setLibraryItems] = useState<LibraryItems>([]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const [loadingState, setIsLoading] = useState<
 | 
	
		
			
				|  |  | -    "preloading" | "loading" | "ready"
 | 
	
		
			
				|  |  | -  >("preloading");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const loadingTimerRef = useRef<number | null>(null);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  useEffect(() => {
 | 
	
		
			
				|  |  | -    Promise.race([
 | 
	
		
			
				|  |  | -      new Promise((resolve) => {
 | 
	
		
			
				|  |  | -        loadingTimerRef.current = window.setTimeout(() => {
 | 
	
		
			
				|  |  | -          resolve("loading");
 | 
	
		
			
				|  |  | -        }, 100);
 | 
	
		
			
				|  |  | -      }),
 | 
	
		
			
				|  |  | -      library.loadLibrary().then((items) => {
 | 
	
		
			
				|  |  | -        setLibraryItems(items);
 | 
	
		
			
				|  |  | -        setIsLoading("ready");
 | 
	
		
			
				|  |  | -      }),
 | 
	
		
			
				|  |  | -    ]).then((data) => {
 | 
	
		
			
				|  |  | -      if (data === "loading") {
 | 
	
		
			
				|  |  | -        setIsLoading("loading");
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    return () => {
 | 
	
		
			
				|  |  | -      clearTimeout(loadingTimerRef.current!);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -  }, [library]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const removeFromLibrary = useCallback(
 | 
	
		
			
				|  |  | -    async (indexToRemove) => {
 | 
	
		
			
				|  |  | -      const items = await library.loadLibrary();
 | 
	
		
			
				|  |  | -      const nextItems = items.filter((_, index) => index !== indexToRemove);
 | 
	
		
			
				|  |  | -      library.saveLibrary(nextItems).catch((error) => {
 | 
	
		
			
				|  |  | -        setLibraryItems(items);
 | 
	
		
			
				|  |  | -        setAppState({ errorMessage: t("alerts.errorRemovingFromLibrary") });
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -      setLibraryItems(nextItems);
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    [library, setAppState],
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const addToLibrary = useCallback(
 | 
	
		
			
				|  |  | -    async (elements: LibraryItem) => {
 | 
	
		
			
				|  |  | -      if (elements.some((element) => element.type === "image")) {
 | 
	
		
			
				|  |  | -        return setAppState({
 | 
	
		
			
				|  |  | -          errorMessage: "Support for adding images to the library coming soon!",
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      const items = await library.loadLibrary();
 | 
	
		
			
				|  |  | -      const nextItems = [...items, elements];
 | 
	
		
			
				|  |  | -      onAddToLibrary();
 | 
	
		
			
				|  |  | -      library.saveLibrary(nextItems).catch((error) => {
 | 
	
		
			
				|  |  | -        setLibraryItems(items);
 | 
	
		
			
				|  |  | -        setAppState({ errorMessage: t("alerts.errorAddingToLibrary") });
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -      setLibraryItems(nextItems);
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    [onAddToLibrary, library, setAppState],
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return loadingState === "preloading" ? null : (
 | 
	
		
			
				|  |  | -    <Island padding={1} ref={ref} className="layer-ui__library">
 | 
	
		
			
				|  |  | -      {loadingState === "loading" ? (
 | 
	
		
			
				|  |  | -        <div className="layer-ui__library-message">
 | 
	
		
			
				|  |  | -          {t("labels.libraryLoadingMessage")}
 | 
	
		
			
				|  |  | -        </div>
 | 
	
		
			
				|  |  | -      ) : (
 | 
	
		
			
				|  |  | -        <LibraryMenuItems
 | 
	
		
			
				|  |  | -          libraryItems={libraryItems}
 | 
	
		
			
				|  |  | -          onRemoveFromLibrary={removeFromLibrary}
 | 
	
		
			
				|  |  | -          onAddToLibrary={addToLibrary}
 | 
	
		
			
				|  |  | -          onInsertShape={onInsertShape}
 | 
	
		
			
				|  |  | -          pendingElements={pendingElements}
 | 
	
		
			
				|  |  | -          setAppState={setAppState}
 | 
	
		
			
				|  |  | -          setLibraryItems={setLibraryItems}
 | 
	
		
			
				|  |  | -          libraryReturnUrl={libraryReturnUrl}
 | 
	
		
			
				|  |  | -          focusContainer={focusContainer}
 | 
	
		
			
				|  |  | -          library={library}
 | 
	
		
			
				|  |  | -          theme={theme}
 | 
	
		
			
				|  |  | -          files={files}
 | 
	
		
			
				|  |  | -          id={id}
 | 
	
		
			
				|  |  | -        />
 | 
	
		
			
				|  |  | -      )}
 | 
	
		
			
				|  |  | -    </Island>
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  const LayerUI = ({
 | 
	
		
			
				|  |  |    actionManager,
 | 
	
		
			
				|  |  |    appState,
 | 
	
	
		
			
				|  | @@ -561,12 +249,15 @@ const LayerUI = ({
 | 
	
		
			
				|  |  |      </Section>
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  const closeLibrary = useCallback(
 | 
	
		
			
				|  |  | -    (event) => {
 | 
	
		
			
				|  |  | -      setAppState({ isLibraryOpen: false });
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    [setAppState],
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | +  const closeLibrary = useCallback(() => {
 | 
	
		
			
				|  |  | +    const isDialogOpen = !!document.querySelector(".Dialog");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Prevent closing if any dialog is open
 | 
	
		
			
				|  |  | +    if (isDialogOpen) {
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    setAppState({ isLibraryOpen: false });
 | 
	
		
			
				|  |  | +  }, [setAppState]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const deselectItems = useCallback(() => {
 | 
	
		
			
				|  |  |      setAppState({
 | 
	
	
		
			
				|  | @@ -578,7 +269,7 @@ const LayerUI = ({
 | 
	
		
			
				|  |  |    const libraryMenu = appState.isLibraryOpen ? (
 | 
	
		
			
				|  |  |      <LibraryMenu
 | 
	
		
			
				|  |  |        pendingElements={getSelectedElements(elements, appState)}
 | 
	
		
			
				|  |  | -      onClickOutside={closeLibrary}
 | 
	
		
			
				|  |  | +      onClose={closeLibrary}
 | 
	
		
			
				|  |  |        onInsertShape={onInsertElements}
 | 
	
		
			
				|  |  |        onAddToLibrary={deselectItems}
 | 
	
		
			
				|  |  |        setAppState={setAppState}
 | 
	
	
		
			
				|  | @@ -588,6 +279,7 @@ const LayerUI = ({
 | 
	
		
			
				|  |  |        theme={appState.theme}
 | 
	
		
			
				|  |  |        files={files}
 | 
	
		
			
				|  |  |        id={id}
 | 
	
		
			
				|  |  | +      appState={appState}
 | 
	
		
			
				|  |  |      />
 | 
	
		
			
				|  |  |    ) : null;
 | 
	
		
			
				|  |  |  
 |