diff --git a/web/src/App.tsx b/web/src/App.tsx
index 748115c..85b33b0 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -22,7 +22,7 @@ import WSClient from "./api/wsclient.ts"
import ClientContext from "./ui/ClientContext.ts"
import MainScreen from "./ui/MainScreen.tsx"
import { LoginScreen, VerificationScreen } from "./ui/login"
-import { LightboxWrapper } from "./ui/modal/Lightbox.tsx"
+import { LightboxWrapper } from "./ui/modal"
import { useEventAsState } from "./util/eventdispatcher.ts"
function makeRPCClient(): RPCClient {
diff --git a/web/src/ui/MainScreen.tsx b/web/src/ui/MainScreen.tsx
index f0a1b6d..2cfb2fc 100644
--- a/web/src/ui/MainScreen.tsx
+++ b/web/src/ui/MainScreen.tsx
@@ -24,7 +24,7 @@ import ClientContext from "./ClientContext.ts"
import MainScreenContext, { MainScreenContextFields } from "./MainScreenContext.ts"
import StylePreferences from "./StylePreferences.tsx"
import Keybindings from "./keybindings.ts"
-import { ModalWrapper } from "./modal/Modal.tsx"
+import { ModalWrapper } from "./modal"
import RightPanel, { RightPanelProps } from "./rightpanel/RightPanel.tsx"
import RoomList from "./roomlist/RoomList.tsx"
import RoomPreview, { RoomPreviewProps } from "./roomview/RoomPreview.tsx"
diff --git a/web/src/ui/composer/MessageComposer.tsx b/web/src/ui/composer/MessageComposer.tsx
index 701b07d..e11be36 100644
--- a/web/src/ui/composer/MessageComposer.tsx
+++ b/web/src/ui/composer/MessageComposer.tsx
@@ -33,7 +33,7 @@ import EmojiPicker from "../emojipicker/EmojiPicker.tsx"
import GIFPicker from "../emojipicker/GIFPicker.tsx"
import StickerPicker from "../emojipicker/StickerPicker.tsx"
import { keyToString } from "../keybindings.ts"
-import { ModalContext } from "../modal/Modal.tsx"
+import { ModalContext } from "../modal"
import { useRoomContext } from "../roomview/roomcontext.ts"
import { ReplyBody } from "../timeline/ReplyBody.tsx"
import type { AutocompleteQuery } from "./Autocompleter.tsx"
diff --git a/web/src/ui/emojipicker/EmojiPicker.tsx b/web/src/ui/emojipicker/EmojiPicker.tsx
index 940d371..3cac9f9 100644
--- a/web/src/ui/emojipicker/EmojiPicker.tsx
+++ b/web/src/ui/emojipicker/EmojiPicker.tsx
@@ -20,7 +20,7 @@ import { roomStateGUIDToString } from "@/api/types"
import { CATEGORY_FREQUENTLY_USED, Emoji, PartialEmoji, categories, useFilteredEmojis } from "@/util/emoji"
import { isMobileDevice } from "@/util/ismobile.ts"
import ClientContext from "../ClientContext.ts"
-import { ModalCloseContext } from "../modal/Modal.tsx"
+import { ModalCloseContext } from "../modal"
import { EmojiGroup } from "./EmojiGroup.tsx"
import renderEmoji from "./renderEmoji.tsx"
import useCategoryUnderline from "./useCategoryUnderline.ts"
diff --git a/web/src/ui/emojipicker/GIFPicker.tsx b/web/src/ui/emojipicker/GIFPicker.tsx
index f7ef45e..53648db 100644
--- a/web/src/ui/emojipicker/GIFPicker.tsx
+++ b/web/src/ui/emojipicker/GIFPicker.tsx
@@ -18,7 +18,7 @@ import { RoomStateStore, usePreference } from "@/api/statestore"
import { MediaMessageEventContent } from "@/api/types"
import { isMobileDevice } from "@/util/ismobile.ts"
import ClientContext from "../ClientContext.ts"
-import { ModalCloseContext } from "../modal/Modal.tsx"
+import { ModalCloseContext } from "../modal"
import { GIF, getTrendingGIFs, searchGIF } from "./gifsource.ts"
import CloseIcon from "@/icons/close.svg?react"
import SearchIcon from "@/icons/search.svg?react"
diff --git a/web/src/ui/emojipicker/StickerPicker.tsx b/web/src/ui/emojipicker/StickerPicker.tsx
index 2a3922c..2c6e0ce 100644
--- a/web/src/ui/emojipicker/StickerPicker.tsx
+++ b/web/src/ui/emojipicker/StickerPicker.tsx
@@ -20,7 +20,7 @@ import { roomStateGUIDToString } from "@/api/types"
import { Emoji, useFilteredEmojis } from "@/util/emoji"
import { isMobileDevice } from "@/util/ismobile.ts"
import ClientContext from "../ClientContext.ts"
-import { ModalCloseContext } from "../modal/Modal.tsx"
+import { ModalCloseContext } from "../modal"
import { EmojiGroup } from "./EmojiGroup.tsx"
import { MediaPickerProps } from "./GIFPicker.tsx"
import useCategoryUnderline from "./useCategoryUnderline.ts"
diff --git a/web/src/ui/modal/Lightbox.tsx b/web/src/ui/modal/Lightbox.tsx
index a6d9164..42bd070 100644
--- a/web/src/ui/modal/Lightbox.tsx
+++ b/web/src/ui/modal/Lightbox.tsx
@@ -13,8 +13,9 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { Component, createContext, createRef, useCallback, useLayoutEffect, useState } from "react"
+import React, { Component, createRef, useCallback, useLayoutEffect, useState } from "react"
import { keyToString } from "../keybindings.ts"
+import { LightboxContext, LightboxParams } from "./contexts.ts"
import CloseIcon from "@/icons/close.svg?react"
import DownloadIcon from "@/icons/download.svg?react"
import RotateLeftIcon from "@/icons/rotate-left.svg?react"
@@ -25,17 +26,7 @@ import "./Lightbox.css"
const isTouchDevice = window.ontouchstart !== undefined
-export interface LightboxParams {
- src: string
- alt: string
-}
-
-export type OpenLightboxType = (params: LightboxParams | React.MouseEvent) => void
-
-export const LightboxContext = createContext(() =>
- console.error("Tried to open lightbox without being inside context"))
-
-export const LightboxWrapper = ({ children }: { children: React.ReactNode }) => {
+const LightboxWrapper = ({ children }: { children: React.ReactNode }) => {
const [params, setParams] = useState(null)
const onOpen = useCallback((params: LightboxParams | React.MouseEvent) => {
if ((params as React.MouseEvent).target) {
@@ -224,3 +215,5 @@ export class Lightbox extends Component {
}
}
+
+export default LightboxWrapper
diff --git a/web/src/ui/modal/Modal.tsx b/web/src/ui/modal/Modal.tsx
index ee1229f..83a1176 100644
--- a/web/src/ui/modal/Modal.tsx
+++ b/web/src/ui/modal/Modal.tsx
@@ -13,25 +13,10 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { JSX, createContext, useCallback, useLayoutEffect, useReducer, useRef } from "react"
+import React, { JSX, useCallback, useLayoutEffect, useReducer, useRef } from "react"
+import { ModalCloseContext, ModalContext, ModalState } from "./contexts.ts"
-export interface ModalState {
- content: JSX.Element
- dimmed?: boolean
- boxed?: boolean
- boxClass?: string
- innerBoxClass?: string
- onClose?: () => void
-}
-
-type openModal = (state: ModalState) => void
-
-export const ModalContext = createContext(() =>
- console.error("Tried to open modal without being inside context"))
-
-export const ModalCloseContext = createContext<() => void>(() => {})
-
-export const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
+const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
const [state, setState] = useReducer((prevState: ModalState | null, newState: ModalState | null) => {
prevState?.onClose?.()
return newState
@@ -98,3 +83,5 @@ export const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
{modal}
}
+
+export default ModalWrapper
diff --git a/web/src/ui/modal/contexts.ts b/web/src/ui/modal/contexts.ts
new file mode 100644
index 0000000..e7fa7c7
--- /dev/null
+++ b/web/src/ui/modal/contexts.ts
@@ -0,0 +1,42 @@
+// gomuks - A Matrix client written in Go.
+// Copyright (C) 2024 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React, { JSX, createContext } from "react"
+
+export interface LightboxParams {
+ src: string
+ alt: string
+}
+
+export type OpenLightboxType = (params: LightboxParams | React.MouseEvent) => void
+
+export const LightboxContext = createContext(() =>
+ console.error("Tried to open lightbox without being inside context"))
+
+export interface ModalState {
+ content: JSX.Element
+ dimmed?: boolean
+ boxed?: boolean
+ boxClass?: string
+ innerBoxClass?: string
+ onClose?: () => void
+}
+
+type openModal = (state: ModalState) => void
+
+export const ModalContext = createContext(() =>
+ console.error("Tried to open modal without being inside context"))
+
+export const ModalCloseContext = createContext<() => void>(() => {})
diff --git a/web/src/ui/modal/index.ts b/web/src/ui/modal/index.ts
new file mode 100644
index 0000000..ea9c3f8
--- /dev/null
+++ b/web/src/ui/modal/index.ts
@@ -0,0 +1,3 @@
+export * from "./contexts.ts"
+export { default as ModalWrapper } from "./Modal.tsx"
+export { default as LightboxWrapper } from "./Lightbox.tsx"
diff --git a/web/src/ui/rightpanel/UserInfo.tsx b/web/src/ui/rightpanel/UserInfo.tsx
index 37e1313..4e93ec7 100644
--- a/web/src/ui/rightpanel/UserInfo.tsx
+++ b/web/src/ui/rightpanel/UserInfo.tsx
@@ -20,7 +20,7 @@ import { useRoomMember } from "@/api/statestore"
import { MemberEventContent, UserID, UserProfile } from "@/api/types"
import { getLocalpart } from "@/util/validation.ts"
import ClientContext from "../ClientContext.ts"
-import { LightboxContext } from "../modal/Lightbox.tsx"
+import { LightboxContext } from "../modal"
import { RoomContext } from "../roomview/roomcontext.ts"
import DeviceList from "./UserInfoDeviceList.tsx"
import UserInfoError from "./UserInfoError.tsx"
diff --git a/web/src/ui/roomview/RoomPreview.tsx b/web/src/ui/roomview/RoomPreview.tsx
index d72bd6f..dab8003 100644
--- a/web/src/ui/roomview/RoomPreview.tsx
+++ b/web/src/ui/roomview/RoomPreview.tsx
@@ -21,7 +21,7 @@ import { RoomID, RoomSummary } from "@/api/types"
import { getDisplayname, getServerName } from "@/util/validation.ts"
import ClientContext from "../ClientContext.ts"
import MainScreenContext from "../MainScreenContext.ts"
-import { LightboxContext } from "../modal/Lightbox.tsx"
+import { LightboxContext } from "../modal"
import MutualRooms from "../rightpanel/UserInfoMutualRooms.tsx"
import ErrorIcon from "@/icons/error.svg?react"
import GroupIcon from "@/icons/group.svg?react"
diff --git a/web/src/ui/roomview/RoomViewHeader.tsx b/web/src/ui/roomview/RoomViewHeader.tsx
index 4aa0f1d..8194cf8 100644
--- a/web/src/ui/roomview/RoomViewHeader.tsx
+++ b/web/src/ui/roomview/RoomViewHeader.tsx
@@ -18,8 +18,8 @@ import { getRoomAvatarURL } from "@/api/media.ts"
import { RoomStateStore } from "@/api/statestore"
import { useEventAsState } from "@/util/eventdispatcher.ts"
import MainScreenContext from "../MainScreenContext.ts"
-import { LightboxContext } from "../modal/Lightbox.tsx"
-import { ModalContext } from "../modal/Modal.tsx"
+import { LightboxContext } from "../modal"
+import { ModalContext } from "../modal"
import SettingsView from "../settings/SettingsView.tsx"
import BackIcon from "@/icons/back.svg?react"
import PeopleIcon from "@/icons/group.svg?react"
diff --git a/web/src/ui/settings/SettingsView.tsx b/web/src/ui/settings/SettingsView.tsx
index bb8a2d3..e2b6b86 100644
--- a/web/src/ui/settings/SettingsView.tsx
+++ b/web/src/ui/settings/SettingsView.tsx
@@ -29,8 +29,8 @@ import {
import { useEventAsState } from "@/util/eventdispatcher.ts"
import useEvent from "@/util/useEvent.ts"
import ClientContext from "../ClientContext.ts"
-import { LightboxContext } from "../modal/Lightbox.tsx"
-import { ModalCloseContext } from "../modal/Modal.tsx"
+import { LightboxContext } from "../modal"
+import { ModalCloseContext } from "../modal"
import JSONView from "../util/JSONView.tsx"
import Toggle from "../util/Toggle.tsx"
import CloseIcon from "@/icons/close.svg?react"
diff --git a/web/src/ui/timeline/TimelineEvent.tsx b/web/src/ui/timeline/TimelineEvent.tsx
index 7e34e18..4065934 100644
--- a/web/src/ui/timeline/TimelineEvent.tsx
+++ b/web/src/ui/timeline/TimelineEvent.tsx
@@ -21,7 +21,7 @@ import { isMobileDevice } from "@/util/ismobile.ts"
import { getDisplayname, isEventID } from "@/util/validation.ts"
import ClientContext from "../ClientContext.ts"
import MainScreenContext from "../MainScreenContext.ts"
-import { ModalContext } from "../modal/Modal.tsx"
+import { ModalContext } from "../modal"
import { useRoomContext } from "../roomview/roomcontext.ts"
import ReadReceipts from "./ReadReceipts.tsx"
import { ReplyIDBody } from "./ReplyBody.tsx"
diff --git a/web/src/ui/timeline/URLPreviews.tsx b/web/src/ui/timeline/URLPreviews.tsx
index 0103621..33df021 100644
--- a/web/src/ui/timeline/URLPreviews.tsx
+++ b/web/src/ui/timeline/URLPreviews.tsx
@@ -19,7 +19,7 @@ import { RoomStateStore, usePreference } from "@/api/statestore"
import { MemDBEvent, URLPreview } from "@/api/types"
import { ImageContainerSize, calculateMediaSize } from "@/util/mediasize"
import ClientContext from "../ClientContext"
-import { LightboxContext } from "../modal/Lightbox.tsx"
+import { LightboxContext } from "../modal"
import "./URLPreviews.css"
const URLPreviews = ({ event, room }: {
diff --git a/web/src/ui/timeline/content/MemberBody.tsx b/web/src/ui/timeline/content/MemberBody.tsx
index 292a9d0..e86ce34 100644
--- a/web/src/ui/timeline/content/MemberBody.tsx
+++ b/web/src/ui/timeline/content/MemberBody.tsx
@@ -16,7 +16,7 @@
import React, { use } from "react"
import { getAvatarURL } from "@/api/media.ts"
import { MemberEventContent, UserID } from "@/api/types"
-import { LightboxContext } from "../../modal/Lightbox.tsx"
+import { LightboxContext } from "../../modal"
import EventContentProps from "./props.ts"
function useChangeDescription(
diff --git a/web/src/ui/timeline/content/RoomAvatarBody.tsx b/web/src/ui/timeline/content/RoomAvatarBody.tsx
index d996bba..7878bbb 100644
--- a/web/src/ui/timeline/content/RoomAvatarBody.tsx
+++ b/web/src/ui/timeline/content/RoomAvatarBody.tsx
@@ -17,7 +17,7 @@ import { JSX, use } from "react"
import { getRoomAvatarURL } from "@/api/media.ts"
import { ContentURI, RoomAvatarEventContent } from "@/api/types"
import { ensureString } from "@/util/validation.ts"
-import { LightboxContext } from "../../modal/Lightbox.tsx"
+import { LightboxContext } from "../../modal"
import EventContentProps from "./props.ts"
const RoomAvatarBody = ({ event, sender, room }: EventContentProps) => {
diff --git a/web/src/ui/timeline/content/useMediaContent.tsx b/web/src/ui/timeline/content/useMediaContent.tsx
index 066091a..3661e1c 100644
--- a/web/src/ui/timeline/content/useMediaContent.tsx
+++ b/web/src/ui/timeline/content/useMediaContent.tsx
@@ -17,7 +17,7 @@ import React, { CSSProperties, JSX, use } from "react"
import { getEncryptedMediaURL, getMediaURL } from "@/api/media.ts"
import type { EventType, MediaMessageEventContent } from "@/api/types"
import { ImageContainerSize, calculateMediaSize, defaultVideoContainerSize } from "@/util/mediasize.ts"
-import { LightboxContext } from "../../modal/Lightbox.tsx"
+import { LightboxContext } from "../../modal"
import DownloadIcon from "@/icons/download.svg?react"
export const useMediaContent = (
diff --git a/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx b/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx
index ff3ed8b..9028a32 100644
--- a/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx
+++ b/web/src/ui/timeline/menu/ConfirmWithMessageModal.tsx
@@ -16,7 +16,7 @@
import React, { use, useState } from "react"
import { MemDBEvent } from "@/api/types"
import { isMobileDevice } from "@/util/ismobile.ts"
-import { ModalCloseContext } from "../../modal/Modal.tsx"
+import { ModalCloseContext } from "../../modal"
import TimelineEvent from "../TimelineEvent.tsx"
interface ConfirmWithMessageProps {
diff --git a/web/src/ui/timeline/menu/usePrimaryItems.tsx b/web/src/ui/timeline/menu/usePrimaryItems.tsx
index f570f40..1ebb0a9 100644
--- a/web/src/ui/timeline/menu/usePrimaryItems.tsx
+++ b/web/src/ui/timeline/menu/usePrimaryItems.tsx
@@ -19,7 +19,7 @@ import { MemDBEvent } from "@/api/types"
import { emojiToReactionContent } from "@/util/emoji"
import { useEventAsState } from "@/util/eventdispatcher.ts"
import EmojiPicker from "../../emojipicker/EmojiPicker.tsx"
-import { ModalCloseContext, ModalContext } from "../../modal/Modal.tsx"
+import { ModalCloseContext, ModalContext } from "../../modal"
import { RoomContextData } from "../../roomview/roomcontext.ts"
import { EventExtraMenu } from "./EventMenu.tsx"
import { getEncryption, getModalStyleFromButton, getPending, getPowerLevels } from "./util.ts"
diff --git a/web/src/ui/timeline/menu/useSecondaryItems.tsx b/web/src/ui/timeline/menu/useSecondaryItems.tsx
index 046aff4..f577aca 100644
--- a/web/src/ui/timeline/menu/useSecondaryItems.tsx
+++ b/web/src/ui/timeline/menu/useSecondaryItems.tsx
@@ -17,7 +17,7 @@ import { use } from "react"
import Client from "@/api/client.ts"
import { useRoomState } from "@/api/statestore"
import { MemDBEvent } from "@/api/types"
-import { ModalCloseContext, ModalContext } from "../../modal/Modal.tsx"
+import { ModalCloseContext, ModalContext } from "../../modal"
import { RoomContext, RoomContextData } from "../../roomview/roomcontext.ts"
import JSONView from "../../util/JSONView.tsx"
import ConfirmWithMessageModal from "./ConfirmWithMessageModal.tsx"