Przeglądaj źródła

feat: merge search sidebar back to default sidebar (#8497)

David Luzar 10 miesięcy temu
rodzic
commit
813f9b702e

+ 8 - 2
excalidraw-app/data/LocalData.ts

@@ -20,7 +20,10 @@ import {
   get,
   get,
 } from "idb-keyval";
 } from "idb-keyval";
 import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
 import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
-import { SEARCH_SIDEBAR } from "../../packages/excalidraw/constants";
+import {
+  CANVAS_SEARCH_TAB,
+  DEFAULT_SIDEBAR,
+} from "../../packages/excalidraw/constants";
 import type { LibraryPersistedData } from "../../packages/excalidraw/data/library";
 import type { LibraryPersistedData } from "../../packages/excalidraw/data/library";
 import type { ImportedDataState } from "../../packages/excalidraw/data/types";
 import type { ImportedDataState } from "../../packages/excalidraw/data/types";
 import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
 import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
@@ -69,7 +72,10 @@ const saveDataStateToLocalStorage = (
   try {
   try {
     const _appState = clearAppStateForLocalStorage(appState);
     const _appState = clearAppStateForLocalStorage(appState);
 
 
-    if (_appState.openSidebar?.name === SEARCH_SIDEBAR.name) {
+    if (
+      _appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
+      _appState.openSidebar.tab === CANVAS_SEARCH_TAB
+    ) {
       _appState.openSidebar = null;
       _appState.openSidebar = null;
     }
     }
 
 

+ 7 - 3
packages/excalidraw/actions/actionToggleSearchMenu.ts

@@ -3,7 +3,7 @@ import { register } from "./register";
 import type { AppState } from "../types";
 import type { AppState } from "../types";
 import { searchIcon } from "../components/icons";
 import { searchIcon } from "../components/icons";
 import { StoreAction } from "../store";
 import { StoreAction } from "../store";
-import { CLASSES, SEARCH_SIDEBAR } from "../constants";
+import { CANVAS_SEARCH_TAB, CLASSES, DEFAULT_SIDEBAR } from "../constants";
 
 
 export const actionToggleSearchMenu = register({
 export const actionToggleSearchMenu = register({
   name: "searchMenu",
   name: "searchMenu",
@@ -17,7 +17,10 @@ export const actionToggleSearchMenu = register({
     predicate: (appState) => appState.gridModeEnabled,
     predicate: (appState) => appState.gridModeEnabled,
   },
   },
   perform(elements, appState, _, app) {
   perform(elements, appState, _, app) {
-    if (appState.openSidebar?.name === SEARCH_SIDEBAR.name) {
+    if (
+      appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
+      appState.openSidebar.tab === CANVAS_SEARCH_TAB
+    ) {
       const searchInput =
       const searchInput =
         app.excalidrawContainerValue.container?.querySelector<HTMLInputElement>(
         app.excalidrawContainerValue.container?.querySelector<HTMLInputElement>(
           `.${CLASSES.SEARCH_MENU_INPUT_WRAPPER} input`,
           `.${CLASSES.SEARCH_MENU_INPUT_WRAPPER} input`,
@@ -31,13 +34,14 @@ export const actionToggleSearchMenu = register({
       }
       }
 
 
       searchInput?.focus();
       searchInput?.focus();
+      searchInput?.select();
       return false;
       return false;
     }
     }
 
 
     return {
     return {
       appState: {
       appState: {
         ...appState,
         ...appState,
-        openSidebar: { name: SEARCH_SIDEBAR.name },
+        openSidebar: { name: DEFAULT_SIDEBAR.name, tab: CANVAS_SEARCH_TAB },
         openDialog: null,
         openDialog: null,
       },
       },
       storeAction: StoreAction.NONE,
       storeAction: StoreAction.NONE,

+ 25 - 20
packages/excalidraw/components/DefaultSidebar.tsx

@@ -1,5 +1,9 @@
 import clsx from "clsx";
 import clsx from "clsx";
-import { DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_TAB } from "../constants";
+import {
+  CANVAS_SEARCH_TAB,
+  DEFAULT_SIDEBAR,
+  LIBRARY_SIDEBAR_TAB,
+} from "../constants";
 import { useTunnels } from "../context/tunnels";
 import { useTunnels } from "../context/tunnels";
 import { useUIAppState } from "../context/ui-appState";
 import { useUIAppState } from "../context/ui-appState";
 import type { MarkOptional, Merge } from "../utility-types";
 import type { MarkOptional, Merge } from "../utility-types";
@@ -10,7 +14,8 @@ import { LibraryMenu } from "./LibraryMenu";
 import type { SidebarProps, SidebarTriggerProps } from "./Sidebar/common";
 import type { SidebarProps, SidebarTriggerProps } from "./Sidebar/common";
 import { Sidebar } from "./Sidebar/Sidebar";
 import { Sidebar } from "./Sidebar/Sidebar";
 import "../components/dropdownMenu/DropdownMenu.scss";
 import "../components/dropdownMenu/DropdownMenu.scss";
-import { t } from "../i18n";
+import { SearchMenu } from "./SearchMenu";
+import { LibraryIcon, searchIcon } from "./icons";
 
 
 const DefaultSidebarTrigger = withInternalFallback(
 const DefaultSidebarTrigger = withInternalFallback(
   "DefaultSidebarTrigger",
   "DefaultSidebarTrigger",
@@ -66,16 +71,20 @@ export const DefaultSidebar = Object.assign(
 
 
       const { DefaultSidebarTabTriggersTunnel } = useTunnels();
       const { DefaultSidebarTabTriggersTunnel } = useTunnels();
 
 
+      const isForceDocked = appState.openSidebar?.tab === CANVAS_SEARCH_TAB;
+
       return (
       return (
         <Sidebar
         <Sidebar
           {...rest}
           {...rest}
           name={"default"}
           name={"default"}
           className={clsx("default-sidebar", className)}
           className={clsx("default-sidebar", className)}
-          docked={docked ?? appState.defaultSidebarDockedPreference}
+          docked={
+            isForceDocked || (docked ?? appState.defaultSidebarDockedPreference)
+          }
           onDock={
           onDock={
             // `onDock=false` disables docking.
             // `onDock=false` disables docking.
             // if `docked` passed, but no onDock passed, disable manual docking.
             // if `docked` passed, but no onDock passed, disable manual docking.
-            onDock === false || (!onDock && docked != null)
+            isForceDocked || onDock === false || (!onDock && docked != null)
               ? undefined
               ? undefined
               : // compose to allow the host app to listen on default behavior
               : // compose to allow the host app to listen on default behavior
                 composeEventHandlers(onDock, (docked) => {
                 composeEventHandlers(onDock, (docked) => {
@@ -85,26 +94,22 @@ export const DefaultSidebar = Object.assign(
         >
         >
           <Sidebar.Tabs>
           <Sidebar.Tabs>
             <Sidebar.Header>
             <Sidebar.Header>
-              {rest.__fallback && (
-                <div
-                  style={{
-                    color: "var(--color-primary)",
-                    fontSize: "1.2em",
-                    fontWeight: "bold",
-                    textOverflow: "ellipsis",
-                    overflow: "hidden",
-                    whiteSpace: "nowrap",
-                    paddingRight: "1em",
-                  }}
-                >
-                  {t("toolBar.library")}
-                </div>
-              )}
-              <DefaultSidebarTabTriggersTunnel.Out />
+              <DefaultSidebar.TabTriggers>
+                <Sidebar.TabTrigger tab={CANVAS_SEARCH_TAB}>
+                  {searchIcon}
+                </Sidebar.TabTrigger>
+                <Sidebar.TabTrigger tab={LIBRARY_SIDEBAR_TAB}>
+                  {LibraryIcon}
+                </Sidebar.TabTrigger>
+              </DefaultSidebar.TabTriggers>
+              {rest.__fallback && <DefaultSidebarTabTriggersTunnel.Out />}
             </Sidebar.Header>
             </Sidebar.Header>
             <Sidebar.Tab tab={LIBRARY_SIDEBAR_TAB}>
             <Sidebar.Tab tab={LIBRARY_SIDEBAR_TAB}>
               <LibraryMenu />
               <LibraryMenu />
             </Sidebar.Tab>
             </Sidebar.Tab>
+            <Sidebar.Tab tab={CANVAS_SEARCH_TAB}>
+              <SearchMenu />
+            </Sidebar.Tab>
             {children}
             {children}
           </Sidebar.Tabs>
           </Sidebar.Tabs>
         </Sidebar>
         </Sidebar>

+ 3 - 2
packages/excalidraw/components/HintViewer.tsx

@@ -13,7 +13,7 @@ import { isEraserActive } from "../appState";
 import "./HintViewer.scss";
 import "./HintViewer.scss";
 import { isNodeInFlowchart } from "../element/flowchart";
 import { isNodeInFlowchart } from "../element/flowchart";
 import { isGridModeEnabled } from "../snapping";
 import { isGridModeEnabled } from "../snapping";
-import { SEARCH_SIDEBAR } from "../constants";
+import { CANVAS_SEARCH_TAB, DEFAULT_SIDEBAR } from "../constants";
 
 
 interface HintViewerProps {
 interface HintViewerProps {
   appState: UIAppState;
   appState: UIAppState;
@@ -32,7 +32,8 @@ const getHints = ({
   const multiMode = appState.multiElement !== null;
   const multiMode = appState.multiElement !== null;
 
 
   if (
   if (
-    appState.openSidebar?.name === SEARCH_SIDEBAR.name &&
+    appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
+    appState.openSidebar.tab === CANVAS_SEARCH_TAB &&
     appState.searchMatches?.length
     appState.searchMatches?.length
   ) {
   ) {
     return t("hints.dismissSearch");
     return t("hints.dismissSearch");

+ 13 - 20
packages/excalidraw/components/LayerUI.tsx

@@ -5,7 +5,6 @@ import {
   CLASSES,
   CLASSES,
   DEFAULT_SIDEBAR,
   DEFAULT_SIDEBAR,
   LIBRARY_SIDEBAR_WIDTH,
   LIBRARY_SIDEBAR_WIDTH,
-  SEARCH_SIDEBAR,
   TOOL_TYPE,
   TOOL_TYPE,
 } from "../constants";
 } from "../constants";
 import { showSelectedShapeActions } from "../element";
 import { showSelectedShapeActions } from "../element";
@@ -54,9 +53,6 @@ import { LibraryIcon } from "./icons";
 import { UIAppStateContext } from "../context/ui-appState";
 import { UIAppStateContext } from "../context/ui-appState";
 import { DefaultSidebar } from "./DefaultSidebar";
 import { DefaultSidebar } from "./DefaultSidebar";
 import { EyeDropper, activeEyeDropperAtom } from "./EyeDropper";
 import { EyeDropper, activeEyeDropperAtom } from "./EyeDropper";
-
-import "./LayerUI.scss";
-import "./Toolbar.scss";
 import { mutateElement } from "../element/mutateElement";
 import { mutateElement } from "../element/mutateElement";
 import { ShapeCache } from "../scene/ShapeCache";
 import { ShapeCache } from "../scene/ShapeCache";
 import Scene from "../scene/Scene";
 import Scene from "../scene/Scene";
@@ -64,7 +60,9 @@ import { LaserPointerButton } from "./LaserPointerButton";
 import { TTDDialog } from "./TTDDialog/TTDDialog";
 import { TTDDialog } from "./TTDDialog/TTDDialog";
 import { Stats } from "./Stats";
 import { Stats } from "./Stats";
 import { actionToggleStats } from "../actions";
 import { actionToggleStats } from "../actions";
-import { SearchSidebar } from "./SearchSidebar";
+
+import "./LayerUI.scss";
+import "./Toolbar.scss";
 
 
 interface LayerUIProps {
 interface LayerUIProps {
   actionManager: ActionManager;
   actionManager: ActionManager;
@@ -365,21 +363,16 @@ const LayerUI = ({
 
 
   const renderSidebars = () => {
   const renderSidebars = () => {
     return (
     return (
-      <>
-        {appState.openSidebar?.name === SEARCH_SIDEBAR.name && (
-          <SearchSidebar />
-        )}
-        <DefaultSidebar
-          __fallback
-          onDock={(docked) => {
-            trackEvent(
-              "sidebar",
-              `toggleDock (${docked ? "dock" : "undock"})`,
-              `(${device.editor.isMobile ? "mobile" : "desktop"})`,
-            );
-          }}
-        />
-      </>
+      <DefaultSidebar
+        __fallback
+        onDock={(docked) => {
+          trackEvent(
+            "sidebar",
+            `toggleDock (${docked ? "dock" : "undock"})`,
+            `(${device.editor.isMobile ? "mobile" : "desktop"})`,
+          );
+        }}
+      />
     );
     );
   };
   };
 
 

+ 0 - 29
packages/excalidraw/components/SearchSidebar.tsx

@@ -1,29 +0,0 @@
-import { SEARCH_SIDEBAR } from "../constants";
-import { t } from "../i18n";
-import { SearchMenu } from "./SearchMenu";
-import { Sidebar } from "./Sidebar/Sidebar";
-
-export const SearchSidebar = () => {
-  return (
-    <Sidebar name={SEARCH_SIDEBAR.name} docked>
-      <Sidebar.Tabs>
-        <Sidebar.Header>
-          <div
-            style={{
-              color: "var(--color-primary)",
-              fontSize: "1.2em",
-              fontWeight: "bold",
-              textOverflow: "ellipsis",
-              overflow: "hidden",
-              whiteSpace: "nowrap",
-              paddingRight: "1em",
-            }}
-          >
-            {t("search.title")}
-          </div>
-        </Sidebar.Header>
-        <SearchMenu />
-      </Sidebar.Tabs>
-    </Sidebar>
-  );
-};

+ 1 - 4
packages/excalidraw/constants.ts

@@ -377,16 +377,13 @@ export const DEFAULT_ELEMENT_PROPS: {
 };
 };
 
 
 export const LIBRARY_SIDEBAR_TAB = "library";
 export const LIBRARY_SIDEBAR_TAB = "library";
+export const CANVAS_SEARCH_TAB = "search";
 
 
 export const DEFAULT_SIDEBAR = {
 export const DEFAULT_SIDEBAR = {
   name: "default",
   name: "default",
   defaultTab: LIBRARY_SIDEBAR_TAB,
   defaultTab: LIBRARY_SIDEBAR_TAB,
 } as const;
 } as const;
 
 
-export const SEARCH_SIDEBAR = {
-  name: "search",
-};
-
 export const LIBRARY_DISABLED_TYPES = new Set([
 export const LIBRARY_DISABLED_TYPES = new Set([
   "iframe",
   "iframe",
   "embeddable",
   "embeddable",

+ 1 - 1
packages/excalidraw/locales/en.json

@@ -167,7 +167,7 @@
     "noMatch": "No matches found...",
     "noMatch": "No matches found...",
     "singleResult": "result",
     "singleResult": "result",
     "multipleResults": "results",
     "multipleResults": "results",
-    "placeholder": "Find text..."
+    "placeholder": "Find text on canvas..."
   },
   },
   "buttons": {
   "buttons": {
     "clearReset": "Reset the canvas",
     "clearReset": "Reset the canvas",

+ 7 - 4
packages/excalidraw/tests/search.test.tsx

@@ -1,7 +1,7 @@
 import React from "react";
 import React from "react";
 import { act, render, waitFor } from "./test-utils";
 import { act, render, waitFor } from "./test-utils";
 import { Excalidraw } from "../index";
 import { Excalidraw } from "../index";
-import { CLASSES, SEARCH_SIDEBAR } from "../constants";
+import { CANVAS_SEARCH_TAB, CLASSES, DEFAULT_SIDEBAR } from "../constants";
 import { Keyboard } from "./helpers/ui";
 import { Keyboard } from "./helpers/ui";
 import { KEYS } from "../keys";
 import { KEYS } from "../keys";
 import { updateTextEditor } from "./queries/dom";
 import { updateTextEditor } from "./queries/dom";
@@ -34,7 +34,8 @@ describe("search", () => {
       Keyboard.keyPress(KEYS.F);
       Keyboard.keyPress(KEYS.F);
     });
     });
     expect(h.app.state.openSidebar).not.toBeNull();
     expect(h.app.state.openSidebar).not.toBeNull();
-    expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
 
 
     const searchInput = await querySearchInput();
     const searchInput = await querySearchInput();
     expect(searchInput.matches(":focus")).toBe(true);
     expect(searchInput.matches(":focus")).toBe(true);
@@ -78,7 +79,8 @@ describe("search", () => {
       Keyboard.keyPress(KEYS.F);
       Keyboard.keyPress(KEYS.F);
     });
     });
     expect(h.app.state.openSidebar).not.toBeNull();
     expect(h.app.state.openSidebar).not.toBeNull();
-    expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
 
 
     const searchInput = await querySearchInput();
     const searchInput = await querySearchInput();
 
 
@@ -122,7 +124,8 @@ describe("search", () => {
       Keyboard.keyPress(KEYS.F);
       Keyboard.keyPress(KEYS.F);
     });
     });
     expect(h.app.state.openSidebar).not.toBeNull();
     expect(h.app.state.openSidebar).not.toBeNull();
-    expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
+    expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
 
 
     const searchInput = await querySearchInput();
     const searchInput = await querySearchInput();