web/modal: don't capture input in context menu modal

This commit is contained in:
Tulir Asokan 2024-12-29 17:30:27 +02:00
parent f83b914af0
commit 08a1712850
5 changed files with 38 additions and 15 deletions

View file

@ -13,7 +13,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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 = <ModalCloseContext value={onClickWrapper}>{state.content}</ModalCloseContext>
@ -68,6 +71,7 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
</div>
</div>
}
if (state.captureInput !== false) {
modal = <div
className={`overlay modal ${state.dimmed ? "dimmed" : ""}`}
onClick={onClickWrapper}
@ -77,6 +81,9 @@ const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
>
{content}
</div>
} else {
modal = content
}
}
return <ModalContext value={openModal}>
{children}

View file

@ -32,6 +32,7 @@ export interface ModalState {
boxClass?: string
innerBoxClass?: string
onClose?: () => void
captureInput?: boolean
}
type openModal = (state: ModalState) => void

View file

@ -107,9 +107,21 @@ const TimelineEvent = ({ evt, prevEvt, disableMenu, smallReplies }: TimelineEven
return
}
mouseEvt.preventDefault()
if (window.hackyOpenEventContextMenu === evt.event_id) {
window.closeModal()
window.hackyOpenEventContextMenu = undefined
} else {
openModal({
content: <EventFixedMenu evt={evt} roomCtx={roomCtx} />,
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

View file

@ -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;

View file

@ -14,5 +14,7 @@ declare global {
mainScreenContext: MainScreenContextFields
openLightbox: (params: { src: string, alt: string }) => void
gcSettings: GCSettings
hackyOpenEventContextMenu?: string
closeModal: () => void
}
}