diff options
Diffstat (limited to 'packages/excalidraw/components/DefaultSidebar.tsx')
| -rw-r--r-- | packages/excalidraw/components/DefaultSidebar.tsx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/packages/excalidraw/components/DefaultSidebar.tsx b/packages/excalidraw/components/DefaultSidebar.tsx new file mode 100644 index 0000000..70b0c2d --- /dev/null +++ b/packages/excalidraw/components/DefaultSidebar.tsx @@ -0,0 +1,121 @@ +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, + }, +); |
