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"