You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.8 KiB
TypeScript
122 lines
3.8 KiB
TypeScript
import clsx from "clsx";
|
|
import {
|
|
CANVAS_SEARCH_TAB,
|
|
DEFAULT_SIDEBAR,
|
|
LIBRARY_SIDEBAR_TAB,
|
|
} from "../constants";
|
|
import { useTunnels } from "../context/tunnels";
|
|
import { useUIAppState } from "../context/ui-appState";
|
|
import type { MarkOptional, Merge } from "../utility-types";
|
|
import { composeEventHandlers } from "../utils";
|
|
import { useExcalidrawSetAppState } from "./App";
|
|
import { withInternalFallback } from "./hoc/withInternalFallback";
|
|
import { LibraryMenu } from "./LibraryMenu";
|
|
import type { SidebarProps, SidebarTriggerProps } from "./Sidebar/common";
|
|
import { Sidebar } from "./Sidebar/Sidebar";
|
|
import "../components/dropdownMenu/DropdownMenu.scss";
|
|
import { SearchMenu } from "./SearchMenu";
|
|
import { LibraryIcon, searchIcon } from "./icons";
|
|
|
|
const DefaultSidebarTrigger = withInternalFallback(
|
|
"DefaultSidebarTrigger",
|
|
(
|
|
props: Omit<SidebarTriggerProps, "name"> &
|
|
React.HTMLAttributes<HTMLDivElement>,
|
|
) => {
|
|
const { DefaultSidebarTriggerTunnel } = useTunnels();
|
|
return (
|
|
<DefaultSidebarTriggerTunnel.In>
|
|
<Sidebar.Trigger
|
|
{...props}
|
|
className="default-sidebar-trigger"
|
|
name={DEFAULT_SIDEBAR.name}
|
|
/>
|
|
</DefaultSidebarTriggerTunnel.In>
|
|
);
|
|
},
|
|
);
|
|
DefaultSidebarTrigger.displayName = "DefaultSidebarTrigger";
|
|
|
|
const DefaultTabTriggers = ({ children }: { children: React.ReactNode }) => {
|
|
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
|
return (
|
|
<DefaultSidebarTabTriggersTunnel.In>
|
|
{children}
|
|
</DefaultSidebarTabTriggersTunnel.In>
|
|
);
|
|
};
|
|
DefaultTabTriggers.displayName = "DefaultTabTriggers";
|
|
|
|
export const DefaultSidebar = Object.assign(
|
|
withInternalFallback(
|
|
"DefaultSidebar",
|
|
({
|
|
children,
|
|
className,
|
|
onDock,
|
|
docked,
|
|
...rest
|
|
}: Merge<
|
|
MarkOptional<Omit<SidebarProps, "name">, "children">,
|
|
{
|
|
/** pass `false` to disable docking */
|
|
onDock?: SidebarProps["onDock"] | false;
|
|
}
|
|
>) => {
|
|
const appState = useUIAppState();
|
|
const setAppState = useExcalidrawSetAppState();
|
|
|
|
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
|
|
|
const isForceDocked = appState.openSidebar?.tab === CANVAS_SEARCH_TAB;
|
|
|
|
return (
|
|
<Sidebar
|
|
{...rest}
|
|
name="default"
|
|
key="default"
|
|
className={clsx("default-sidebar", className)}
|
|
docked={
|
|
isForceDocked || (docked ?? appState.defaultSidebarDockedPreference)
|
|
}
|
|
onDock={
|
|
// `onDock=false` disables docking.
|
|
// if `docked` passed, but no onDock passed, disable manual docking.
|
|
isForceDocked || onDock === false || (!onDock && docked != null)
|
|
? undefined
|
|
: // compose to allow the host app to listen on default behavior
|
|
composeEventHandlers(onDock, (docked) => {
|
|
setAppState({ defaultSidebarDockedPreference: docked });
|
|
})
|
|
}
|
|
>
|
|
<Sidebar.Tabs>
|
|
<Sidebar.Header>
|
|
<Sidebar.TabTriggers>
|
|
<Sidebar.TabTrigger tab={CANVAS_SEARCH_TAB}>
|
|
{searchIcon}
|
|
</Sidebar.TabTrigger>
|
|
<Sidebar.TabTrigger tab={LIBRARY_SIDEBAR_TAB}>
|
|
{LibraryIcon}
|
|
</Sidebar.TabTrigger>
|
|
<DefaultSidebarTabTriggersTunnel.Out />
|
|
</Sidebar.TabTriggers>
|
|
</Sidebar.Header>
|
|
<Sidebar.Tab tab={LIBRARY_SIDEBAR_TAB}>
|
|
<LibraryMenu />
|
|
</Sidebar.Tab>
|
|
<Sidebar.Tab tab={CANVAS_SEARCH_TAB}>
|
|
<SearchMenu />
|
|
</Sidebar.Tab>
|
|
{children}
|
|
</Sidebar.Tabs>
|
|
</Sidebar>
|
|
);
|
|
},
|
|
),
|
|
{
|
|
Trigger: DefaultSidebarTrigger,
|
|
TabTriggers: DefaultTabTriggers,
|
|
},
|
|
);
|