1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

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

This commit is contained in:
David Luzar 2024-09-11 19:26:01 +02:00 committed by GitHub
parent fd39712ba6
commit 813f9b702e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 65 additions and 85 deletions

@ -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;
} }

@ -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,

@ -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 && ( <DefaultSidebar.TabTriggers>
<div <Sidebar.TabTrigger tab={CANVAS_SEARCH_TAB}>
style={{ {searchIcon}
color: "var(--color-primary)", </Sidebar.TabTrigger>
fontSize: "1.2em", <Sidebar.TabTrigger tab={LIBRARY_SIDEBAR_TAB}>
fontWeight: "bold", {LibraryIcon}
textOverflow: "ellipsis", </Sidebar.TabTrigger>
overflow: "hidden", </DefaultSidebar.TabTriggers>
whiteSpace: "nowrap", {rest.__fallback && <DefaultSidebarTabTriggersTunnel.Out />}
paddingRight: "1em",
}}
>
{t("toolBar.library")}
</div>
)}
<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>

@ -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");

@ -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 (
<> <DefaultSidebar
{appState.openSidebar?.name === SEARCH_SIDEBAR.name && ( __fallback
<SearchSidebar /> onDock={(docked) => {
)} trackEvent(
<DefaultSidebar "sidebar",
__fallback `toggleDock (${docked ? "dock" : "undock"})`,
onDock={(docked) => { `(${device.editor.isMobile ? "mobile" : "desktop"})`,
trackEvent( );
"sidebar", }}
`toggleDock (${docked ? "dock" : "undock"})`, />
`(${device.editor.isMobile ? "mobile" : "desktop"})`,
);
}}
/>
</>
); );
}; };

@ -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>
);
};

@ -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",

@ -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",

@ -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();