From 08a1712850c97f475dde7aa540c3a6f32f907ddb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 29 Dec 2024 17:30:27 +0200 Subject: [PATCH] web/modal: don't capture input in context menu modal --- web/src/ui/modal/Modal.tsx | 31 ++++++++++++++++----------- web/src/ui/modal/contexts.ts | 1 + web/src/ui/timeline/TimelineEvent.tsx | 18 +++++++++++++--- web/src/ui/timeline/menu/index.css | 1 + web/src/vite-env.d.ts | 2 ++ 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/web/src/ui/modal/Modal.tsx b/web/src/ui/modal/Modal.tsx index 83a1176..1fc3ab6 100644 --- a/web/src/ui/modal/Modal.tsx +++ b/web/src/ui/modal/Modal.tsx @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import React, { JSX, useCallback, useLayoutEffect, useReducer, useRef } from "react" +import React, { JSX, useCallback, useEffect, useLayoutEffect, useReducer, useRef } from "react" import { ModalCloseContext, ModalContext, ModalState } from "./contexts.ts" const ModalWrapper = ({ children }: { children: React.ReactNode }) => { @@ -40,7 +40,7 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => { evt.stopPropagation() } const openModal = useCallback((newState: ModalState) => { - if (!history.state?.modal) { + if (!history.state?.modal && newState.captureInput !== false) { history.pushState({ ...(history.state ?? {}), modal: true }, "") } setState(newState) @@ -50,6 +50,9 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => { if (wrapperRef.current && (!document.activeElement || !wrapperRef.current.contains(document.activeElement))) { wrapperRef.current.focus() } + }, [state]) + useEffect(() => { + window.closeModal = onClickWrapper const listener = (evt: PopStateEvent) => { if (!evt.state?.modal) { setState(null) @@ -57,7 +60,7 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => { } window.addEventListener("popstate", listener) return () => window.removeEventListener("popstate", listener) - }, [state]) + }, []) let modal: JSX.Element | null = null if (state) { let content = {state.content} @@ -68,15 +71,19 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => { } - modal =
- {content} -
+ if (state.captureInput !== false) { + modal =
+ {content} +
+ } else { + modal = content + } } return {children} diff --git a/web/src/ui/modal/contexts.ts b/web/src/ui/modal/contexts.ts index e7fa7c7..dad5963 100644 --- a/web/src/ui/modal/contexts.ts +++ b/web/src/ui/modal/contexts.ts @@ -32,6 +32,7 @@ export interface ModalState { boxClass?: string innerBoxClass?: string onClose?: () => void + captureInput?: boolean } type openModal = (state: ModalState) => void diff --git a/web/src/ui/timeline/TimelineEvent.tsx b/web/src/ui/timeline/TimelineEvent.tsx index 760428e..38b15d7 100644 --- a/web/src/ui/timeline/TimelineEvent.tsx +++ b/web/src/ui/timeline/TimelineEvent.tsx @@ -107,9 +107,21 @@ const TimelineEvent = ({ evt, prevEvt, disableMenu, smallReplies }: TimelineEven return } mouseEvt.preventDefault() - openModal({ - content: , - }) + if (window.hackyOpenEventContextMenu === evt.event_id) { + window.closeModal() + window.hackyOpenEventContextMenu = undefined + } else { + openModal({ + content: , + captureInput: false, + onClose: () => { + if (window.hackyOpenEventContextMenu === evt.event_id) { + window.hackyOpenEventContextMenu = undefined + } + }, + }) + window.hackyOpenEventContextMenu = evt.event_id + } } const memberEvt = useRoomMember(client, roomCtx.store, evt.sender) const memberEvtContent = memberEvt?.content as MemberEventContent | undefined diff --git a/web/src/ui/timeline/menu/index.css b/web/src/ui/timeline/menu/index.css index 2750816..535273b 100644 --- a/web/src/ui/timeline/menu/index.css +++ b/web/src/ui/timeline/menu/index.css @@ -28,6 +28,7 @@ div.event-fixed-menu { box-sizing: border-box; justify-content: right; flex-direction: row-reverse; + overflow-x: auto; > button { width: 3rem; diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts index ceffa1a..9cef2d8 100644 --- a/web/src/vite-env.d.ts +++ b/web/src/vite-env.d.ts @@ -14,5 +14,7 @@ declare global { mainScreenContext: MainScreenContextFields openLightbox: (params: { src: string, alt: string }) => void gcSettings: GCSettings + hackyOpenEventContextMenu?: string + closeModal: () => void } }