aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/PropertiesPopover.tsx
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:35 -0400
committerkj_sh6042026-03-15 16:19:35 -0400
commit6ec259a0e71174651bae95d4628138bf6fd68742 (patch)
tree5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/PropertiesPopover.tsx
parent16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff)
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/PropertiesPopover.tsx')
-rw-r--r--packages/excalidraw/components/PropertiesPopover.tsx96
1 files changed, 96 insertions, 0 deletions
diff --git a/packages/excalidraw/components/PropertiesPopover.tsx b/packages/excalidraw/components/PropertiesPopover.tsx
new file mode 100644
index 0000000..455af11
--- /dev/null
+++ b/packages/excalidraw/components/PropertiesPopover.tsx
@@ -0,0 +1,96 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import * as Popover from "@radix-ui/react-popover";
+
+import { useDevice } from "./App";
+import { Island } from "./Island";
+import { isInteractive } from "../utils";
+
+interface PropertiesPopoverProps {
+ className?: string;
+ container: HTMLDivElement | null;
+ children: ReactNode;
+ style?: object;
+ onClose: () => void;
+ onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
+ onPointerLeave?: React.PointerEventHandler<HTMLDivElement>;
+ onFocusOutside?: Popover.PopoverContentProps["onFocusOutside"];
+ onPointerDownOutside?: Popover.PopoverContentProps["onPointerDownOutside"];
+}
+
+export const PropertiesPopover = React.forwardRef<
+ HTMLDivElement,
+ PropertiesPopoverProps
+>(
+ (
+ {
+ className,
+ container,
+ children,
+ style,
+ onClose,
+ onKeyDown,
+ onFocusOutside,
+ onPointerLeave,
+ onPointerDownOutside,
+ },
+ ref,
+ ) => {
+ const device = useDevice();
+
+ return (
+ <Popover.Portal container={container}>
+ <Popover.Content
+ ref={ref}
+ className={clsx("focus-visible-none", className)}
+ data-prevent-outside-click
+ side={
+ device.editor.isMobile && !device.viewport.isLandscape
+ ? "bottom"
+ : "right"
+ }
+ align={
+ device.editor.isMobile && !device.viewport.isLandscape
+ ? "center"
+ : "start"
+ }
+ alignOffset={-16}
+ sideOffset={20}
+ style={{
+ zIndex: "var(--zIndex-popup)",
+ }}
+ onPointerLeave={onPointerLeave}
+ onKeyDown={onKeyDown}
+ onFocusOutside={onFocusOutside}
+ onPointerDownOutside={onPointerDownOutside}
+ onCloseAutoFocus={(e) => {
+ e.stopPropagation();
+ // prevents focusing the trigger
+ e.preventDefault();
+
+ // return focus to excalidraw container unless
+ // user focuses an interactive element, such as a button, or
+ // enters the text editor by clicking on canvas with the text tool
+ if (container && !isInteractive(document.activeElement)) {
+ container.focus();
+ }
+
+ onClose();
+ }}
+ >
+ <Island padding={3} style={style}>
+ {children}
+ </Island>
+ <Popover.Arrow
+ width={20}
+ height={10}
+ style={{
+ fill: "var(--popup-bg-color)",
+ filter: "drop-shadow(rgba(0, 0, 0, 0.05) 0px 3px 2px)",
+ }}
+ />
+ </Popover.Content>
+ </Popover.Portal>
+ );
+ },
+);