diff options
| author | kj_sh604 | 2026-03-15 16:19:35 -0400 |
|---|---|---|
| committer | kj_sh604 | 2026-03-15 16:19:35 -0400 |
| commit | 6ec259a0e71174651bae95d4628138bf6fd68742 (patch) | |
| tree | 5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/PropertiesPopover.tsx | |
| parent | 16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff) | |
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/PropertiesPopover.tsx')
| -rw-r--r-- | packages/excalidraw/components/PropertiesPopover.tsx | 96 |
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> + ); + }, +); |
