From ffcc2e13d83130d6a58b5a0da78012dc25550fff Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 19 Sep 2025 13:53:58 +1000 Subject: [PATCH] remove refactored popups --- .../components/LinearElementTypePopup.tsx | 122 ----------------- .../components/SelectionTypePopup.tsx | 122 ----------------- .../excalidraw/components/ShapeTypePopup.tsx | 123 ------------------ 3 files changed, 367 deletions(-) delete mode 100644 packages/excalidraw/components/LinearElementTypePopup.tsx delete mode 100644 packages/excalidraw/components/SelectionTypePopup.tsx delete mode 100644 packages/excalidraw/components/ShapeTypePopup.tsx diff --git a/packages/excalidraw/components/LinearElementTypePopup.tsx b/packages/excalidraw/components/LinearElementTypePopup.tsx deleted file mode 100644 index ccb4c978e..000000000 --- a/packages/excalidraw/components/LinearElementTypePopup.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; - -import { CLASSES, capitalizeString } from "@excalidraw/common"; -import { trackEvent } from "../analytics"; -import { t } from "../i18n"; -import { ToolButton } from "./ToolButton"; -import { ArrowIcon, LineIcon } from "./icons"; - -import type { AppClassProperties } from "../types"; - -import "./ConvertElementTypePopup.scss"; - -const LINEAR_ELEMENT_TYPES = [ - { type: "arrow", icon: ArrowIcon }, - { type: "line", icon: LineIcon }, -] as const; - -type LinearElementType = "arrow" | "line"; - -type LinearElementTypePopupProps = { - app: AppClassProperties; - triggerElement: HTMLElement | null; - isOpen: boolean; - onClose: () => void; - currentType: LinearElementType; - onChange?: (type: LinearElementType) => void; -}; - -export const LinearElementTypePopup = ({ - app, - triggerElement, - isOpen, - onClose, - onChange, - currentType, -}: LinearElementTypePopupProps) => { - const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 }); - const panelRef = useRef(null); - - useEffect(() => { - if (!isOpen || !triggerElement) { - return; - } - - const updatePosition = () => { - const triggerRect = triggerElement.getBoundingClientRect(); - const panelRect = panelRef.current?.getBoundingClientRect(); - const panelWidth = panelRect?.width ?? 0; - const panelHeight = panelRect?.height ?? 0; - setPanelPosition({ - x: triggerRect.x + triggerRect.width / 2 - panelWidth / 2, - y: triggerRect.top - panelHeight - 16, - }); - }; - - updatePosition(); - - const handleClick = (event: MouseEvent) => { - const target = event.target as Node | null; - const panelEl = panelRef.current; - const triggerEl = triggerElement; - if (!target) { - onClose(); - return; - } - const clickedInsidePanel = !!panelEl && panelEl.contains(target); - const clickedTrigger = !!triggerEl && triggerEl.contains(target); - if (!clickedInsidePanel && !clickedTrigger) { - onClose(); - } - }; - - // use capture to ensure we run before potential re-renders hide elements - document.addEventListener("pointerdown", handleClick, true); - document.addEventListener("pointerup", handleClick, true); - - return () => { - document.removeEventListener("pointerdown", handleClick, true); - document.removeEventListener("pointerup", handleClick, true); - }; - }, [isOpen, triggerElement, onClose]); - - if (!isOpen) return null; - - return ( -
- {LINEAR_ELEMENT_TYPES.map(({ type, icon }) => ( - { - if (app.state.activeTool.type !== type) { - trackEvent("toolbar", type, "ui"); - } - app.setActiveTool({ type: type as any }); - onChange?.(type); - // Intentionally NOT calling onClose here; popup should stay open - // until user clicks outside trigger or popup per requirements. - }} - /> - ))} -
- ); -}; diff --git a/packages/excalidraw/components/SelectionTypePopup.tsx b/packages/excalidraw/components/SelectionTypePopup.tsx deleted file mode 100644 index 6923bec21..000000000 --- a/packages/excalidraw/components/SelectionTypePopup.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; - -import { CLASSES, capitalizeString } from "@excalidraw/common"; -import { trackEvent } from "../analytics"; -import { t } from "../i18n"; -import { ToolButton } from "./ToolButton"; -import { SelectionIcon, LassoIcon } from "./icons"; - -import type { AppClassProperties } from "../types"; - -import "./ConvertElementTypePopup.scss"; - -const SELECTION_TYPES = [ - { type: "selection", icon: SelectionIcon }, - { type: "lasso", icon: LassoIcon }, -] as const; - -type SelectionType = "selection" | "lasso"; - -type SelectionTypePopupProps = { - app: AppClassProperties; - triggerElement: HTMLElement | null; - isOpen: boolean; - onClose: () => void; - currentType: SelectionType; - onChange?: (type: SelectionType) => void; -}; - -export const SelectionTypePopup = ({ - app, - triggerElement, - isOpen, - onClose, - onChange, - currentType, -}: SelectionTypePopupProps) => { - const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 }); - const panelRef = useRef(null); - - useEffect(() => { - if (!isOpen || !triggerElement) { - return; - } - - const updatePosition = () => { - const triggerRect = triggerElement.getBoundingClientRect(); - const panelRect = panelRef.current?.getBoundingClientRect(); - const panelWidth = panelRect?.width ?? 0; - const panelHeight = panelRect?.height ?? 0; - setPanelPosition({ - x: triggerRect.x + triggerRect.width / 2 - panelWidth / 2, - y: triggerRect.top - panelHeight - 16, - }); - }; - - updatePosition(); - - const handleClick = (event: MouseEvent) => { - const target = event.target as Node | null; - const panelEl = panelRef.current; - const triggerEl = triggerElement; - if (!target) { - onClose(); - return; - } - const clickedInsidePanel = !!panelEl && panelEl.contains(target); - const clickedTrigger = !!triggerEl && triggerEl.contains(target); - if (!clickedInsidePanel && !clickedTrigger) { - onClose(); - } - }; - - // use capture to ensure we run before potential re-renders hide elements - document.addEventListener("pointerdown", handleClick, true); - document.addEventListener("pointerup", handleClick, true); - - return () => { - document.removeEventListener("pointerdown", handleClick, true); - document.removeEventListener("pointerup", handleClick, true); - }; - }, [isOpen, triggerElement, onClose]); - - if (!isOpen) return null; - - return ( -
- {SELECTION_TYPES.map(({ type, icon }) => ( - { - if (app.state.activeTool.type !== type) { - trackEvent("toolbar", type, "ui"); - } - app.setActiveTool({ type: type as any }); - onChange?.(type); - // Intentionally NOT calling onClose here; popup should stay open - // until user clicks outside trigger or popup per requirements. - }} - /> - ))} -
- ); -}; diff --git a/packages/excalidraw/components/ShapeTypePopup.tsx b/packages/excalidraw/components/ShapeTypePopup.tsx deleted file mode 100644 index 5f0b0626e..000000000 --- a/packages/excalidraw/components/ShapeTypePopup.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; - -import { CLASSES, capitalizeString } from "@excalidraw/common"; -import { trackEvent } from "../analytics"; -import { t } from "../i18n"; -import { ToolButton } from "./ToolButton"; -import { DiamondIcon, EllipseIcon, RectangleIcon } from "./icons"; - -import type { AppClassProperties } from "../types"; - -import "./ConvertElementTypePopup.scss"; - -const GAP_HORIZONTAL = 44; -const GAP_VERTICAL = -94; - -const GENERIC_SHAPES = [ - { type: "rectangle", icon: RectangleIcon }, - { type: "diamond", icon: DiamondIcon }, - { type: "ellipse", icon: EllipseIcon }, -] as const; - -type ShapeTypePopupProps = { - app: AppClassProperties; - triggerElement: HTMLElement | null; - isOpen: boolean; - onClose: () => void; - currentType: string; - onChange?: (type: "rectangle" | "diamond" | "ellipse") => void; -}; - -export const ShapeTypePopup = ({ - app, - triggerElement, - isOpen, - onClose, - onChange, - currentType, -}: ShapeTypePopupProps) => { - const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 }); - const panelRef = useRef(null); - - useEffect(() => { - if (!isOpen || !triggerElement) { - return; - } - - const updatePosition = () => { - const triggerRect = triggerElement.getBoundingClientRect(); - const panelRect = panelRef.current?.getBoundingClientRect(); - const panelWidth = panelRect?.width ?? 0; - const panelHeight = panelRect?.height ?? 0; - setPanelPosition({ - x: triggerRect.x + triggerRect.width / 2 - panelWidth / 2, - y: triggerRect.top - panelHeight - 16, - }); - }; - - updatePosition(); - - // Outside click handling (capture pointer events for reliability on mobile) - const handlePointer = (event: PointerEvent) => { - const target = event.target as Node | null; - const panelEl = panelRef.current; - const triggerEl = triggerElement; - if (!target) { - onClose(); - return; - } - const insidePanel = !!panelEl && panelEl.contains(target); - const onTrigger = !!triggerEl && triggerEl.contains(target); - if (!insidePanel && !onTrigger) { - onClose(); - } - }; - document.addEventListener("pointerdown", handlePointer, true); - document.addEventListener("pointerup", handlePointer, true); - return () => { - document.removeEventListener("pointerdown", handlePointer, true); - document.removeEventListener("pointerup", handlePointer, true); - }; - }, [isOpen, triggerElement, onClose]); - - if (!isOpen) { - return null; - } - - return ( -
- {GENERIC_SHAPES.map(({ type, icon }) => ( - { - if (app.state.activeTool.type !== type) { - trackEvent("toolbar", type, "ui"); - } - app.setActiveTool({ type: type as any }); - onChange?.(type); - // Do NOT close here; keep popup open until user clicks outside (parity with SelectionTypePopup) - }} - /> - ))} -
- ); -};