{result.items.map((userId) => {
const username = `${getMxIdLocalPart(userId)}`;
const userServer = getMxIdServer(userId);
diff --git a/src/app/components/join-address-prompt/JoinAddressPrompt.tsx b/src/app/components/join-address-prompt/JoinAddressPrompt.tsx
index d6a6478d2..fc33f55ca 100644
--- a/src/app/components/join-address-prompt/JoinAddressPrompt.tsx
+++ b/src/app/components/join-address-prompt/JoinAddressPrompt.tsx
@@ -1,4 +1,5 @@
-import { FormEventHandler, useState } from 'react';
+import type { FormEventHandler } from 'react';
+import { useState } from 'react';
import FocusTrap from 'focus-trap-react';
import {
Dialog,
diff --git a/src/app/components/knock-room-prompt/KnockRoomPrompt.tsx b/src/app/components/knock-room-prompt/KnockRoomPrompt.tsx
index a7948e9ab..5974cb0f6 100644
--- a/src/app/components/knock-room-prompt/KnockRoomPrompt.tsx
+++ b/src/app/components/knock-room-prompt/KnockRoomPrompt.tsx
@@ -1,4 +1,5 @@
-import { useCallback, useEffect, FormEventHandler } from 'react';
+import type { FormEventHandler } from 'react';
+import { useCallback, useEffect } from 'react';
import FocusTrap from 'focus-trap-react';
import {
Dialog,
@@ -17,7 +18,7 @@ import {
Button,
Spinner,
} from 'folds';
-import { MatrixError } from '$types/matrix-sdk';
+import type { MatrixError } from '$types/matrix-sdk';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
diff --git a/src/app/components/leave-room-prompt/LeaveRoomPrompt.tsx b/src/app/components/leave-room-prompt/LeaveRoomPrompt.tsx
index 36cdd89de..d9b97f0fc 100644
--- a/src/app/components/leave-room-prompt/LeaveRoomPrompt.tsx
+++ b/src/app/components/leave-room-prompt/LeaveRoomPrompt.tsx
@@ -16,7 +16,7 @@ import {
Button,
Spinner,
} from 'folds';
-import { MatrixError } from '$types/matrix-sdk';
+import type { MatrixError } from '$types/matrix-sdk';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { stopPropagation } from '$utils/keyboard';
diff --git a/src/app/components/leave-space-prompt/LeaveSpacePrompt.tsx b/src/app/components/leave-space-prompt/LeaveSpacePrompt.tsx
index 5bee7af26..c6aef838d 100644
--- a/src/app/components/leave-space-prompt/LeaveSpacePrompt.tsx
+++ b/src/app/components/leave-space-prompt/LeaveSpacePrompt.tsx
@@ -16,7 +16,7 @@ import {
Button,
Spinner,
} from 'folds';
-import { MatrixError } from '$types/matrix-sdk';
+import type { MatrixError } from '$types/matrix-sdk';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { stopPropagation } from '$utils/keyboard';
diff --git a/src/app/components/media/Image.tsx b/src/app/components/media/Image.tsx
index 29990e99e..6970c70bb 100644
--- a/src/app/components/media/Image.tsx
+++ b/src/app/components/media/Image.tsx
@@ -1,4 +1,5 @@
-import { ImgHTMLAttributes, forwardRef } from 'react';
+import type { ImgHTMLAttributes } from 'react';
+import { forwardRef } from 'react';
import classNames from 'classnames';
import * as css from './media.css';
diff --git a/src/app/components/media/MediaControls.tsx b/src/app/components/media/MediaControls.tsx
index 2360b9f96..313f138e3 100644
--- a/src/app/components/media/MediaControls.tsx
+++ b/src/app/components/media/MediaControls.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import { Box, as } from 'folds';
export type MediaControlProps = {
diff --git a/src/app/components/media/Video.tsx b/src/app/components/media/Video.tsx
index c28efcaa3..b27b4d0e8 100644
--- a/src/app/components/media/Video.tsx
+++ b/src/app/components/media/Video.tsx
@@ -1,10 +1,11 @@
-import { VideoHTMLAttributes, forwardRef, useEffect, useRef } from 'react';
+import type { VideoHTMLAttributes } from 'react';
+import { forwardRef, useEffect, useRef } from 'react';
import classNames from 'classnames';
import * as css from './media.css';
export const Video = forwardRef
>(
({ className, ...props }, ref) => (
- // eslint-disable-next-line jsx-a11y/media-has-caption
+ // oxlint-disable-next-line jsx-a11y/media-has-caption
)
);
diff --git a/src/app/components/member-tile/MemberTile.tsx b/src/app/components/member-tile/MemberTile.tsx
index e30c226c7..f6cb1cc94 100644
--- a/src/app/components/member-tile/MemberTile.tsx
+++ b/src/app/components/member-tile/MemberTile.tsx
@@ -1,6 +1,6 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import { as, Avatar, Box, Icon, Icons, Text } from 'folds';
-import { MatrixClient, Room, RoomMember } from '$types/matrix-sdk';
+import type { MatrixClient, Room, RoomMember } from '$types/matrix-sdk';
import { getMemberDisplayName } from '$utils/room';
import { getMxIdLocalPart } from '$utils/matrix';
import { useSableCosmetics } from '$hooks/useSableCosmetics';
diff --git a/src/app/components/message/FileHeader.tsx b/src/app/components/message/FileHeader.tsx
index 36d8adeb1..92c41d37e 100644
--- a/src/app/components/message/FileHeader.tsx
+++ b/src/app/components/message/FileHeader.tsx
@@ -1,6 +1,7 @@
import { Badge, Box, Icon, IconButton, Icons, Spinner, Text, as, toRem } from 'folds';
-import { ReactNode, useCallback } from 'react';
-import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
+import type { ReactNode } from 'react';
+import { useCallback } from 'react';
+import type { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import FileSaver from 'file-saver';
import { mimeTypeToExt } from '$utils/mimeTypes';
import { useMatrixClient } from '$hooks/useMatrixClient';
diff --git a/src/app/components/message/MsgTypeRenderers.tsx b/src/app/components/message/MsgTypeRenderers.tsx
index d52cdc5e1..399228cc2 100644
--- a/src/app/components/message/MsgTypeRenderers.tsx
+++ b/src/app/components/message/MsgTypeRenderers.tsx
@@ -1,9 +1,10 @@
-import { CSSProperties, ReactNode, useMemo } from 'react';
+import type { CSSProperties, ReactNode } from 'react';
+import { useMemo } from 'react';
import { Box, Chip, Icon, Icons, Text, toRem } from 'folds';
-import { IContent, IPreviewUrlResponse } from '$types/matrix-sdk';
+import type { IContent, IPreviewUrlResponse } from '$types/matrix-sdk';
import { JUMBO_EMOJI_REG, URL_REG } from '$utils/regex';
import { trimReplyFromBody } from '$utils/room';
-import {
+import type {
IAudioContent,
IAudioInfo,
IEncryptedFile,
@@ -14,6 +15,8 @@ import {
IThumbnailContent,
IVideoContent,
IVideoInfo,
+} from '$types/matrix/common';
+import {
MATRIX_SPOILER_PROPERTY_NAME,
MATRIX_SPOILER_REASON_PROPERTY_NAME,
} from '$types/matrix/common';
@@ -21,7 +24,7 @@ import { FALLBACK_MIMETYPE, getBlobSafeMimeType } from '$utils/mimeTypes';
import { parseGeoUri, scaleYDimension } from '$utils/common';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
-import { PerMessageProfileBeeperFormat } from '$hooks/usePerMessageProfile';
+import type { PerMessageProfileBeeperFormat } from '$hooks/usePerMessageProfile';
import { Attachment, AttachmentBox, AttachmentContent, AttachmentHeader } from './attachment';
import { FileHeader, FileDownloadButton } from './FileHeader';
import {
@@ -34,6 +37,10 @@ import {
import { MessageTextBody } from './layout';
import { unwrapForwardedContent } from './modals/MessageForward';
+interface BundleContent extends IPreviewUrlResponse {
+ matched_url: string;
+}
+
export function MBadEncrypted() {
return (
@@ -138,13 +145,12 @@ export function MText({
if (!body && !customBody) return ;
- let bundleContent: object[] | undefined;
+ let bundleContent: BundleContent[] | undefined;
const urlsMatch = trimmedBody.match(URL_REG);
let urls = urlsMatch ? [...new Set(urlsMatch)] : undefined;
- bundleContent = content['com.beeper.linkpreviews'] as object[];
- bundleContent = bundleContent?.filter((bundle) => !!urls?.includes((bundle as any).matched_url));
- if (renderUrlsPreview && bundleContent)
- urls = bundleContent.map((bundle) => (bundle as any).matched_url);
+ bundleContent = content['com.beeper.linkpreviews'] as BundleContent[];
+ bundleContent = bundleContent?.filter((bundle) => !!urls?.includes(bundle.matched_url));
+ if (renderUrlsPreview && bundleContent) urls = bundleContent.map((bundle) => bundle.matched_url);
if ((content['com.beeper.per_message_profile'] as PerMessageProfileBeeperFormat)?.has_fallback) {
// unwrap per-message profile fallback if present
@@ -227,11 +233,11 @@ export function MEmote({
const trimmedBody = trimReplyFromBody(body);
const isJumbo = JUMBO_EMOJI_REG.test(trimmedBody);
- let bundleContent: object[] | undefined;
+ let bundleContent: BundleContent[] | undefined;
const urlsMatch = trimmedBody.match(URL_REG);
const urls = urlsMatch ? [...new Set(urlsMatch)] : undefined;
- bundleContent = content['com.beeper.linkpreviews'] as object[];
- bundleContent = bundleContent?.filter((bundle) => !!urls?.includes((bundle as any).matched_url));
+ bundleContent = content['com.beeper.linkpreviews'] as BundleContent[];
+ bundleContent = bundleContent?.filter((bundle) => !!urls?.includes(bundle.matched_url));
return (
<>
@@ -279,11 +285,11 @@ export function MNotice({
const trimmedBody = trimReplyFromBody(body);
const isJumbo = JUMBO_EMOJI_REG.test(trimmedBody);
- let bundleContent: object[] | undefined;
+ let bundleContent: BundleContent[] | undefined;
const urlsMatch = trimmedBody.match(URL_REG);
const urls = urlsMatch ? [...new Set(urlsMatch)] : undefined;
- bundleContent = content['com.beeper.linkpreviews'] as object[];
- bundleContent = bundleContent?.filter((bundle) => !!urls?.includes((bundle as any).matched_url));
+ bundleContent = content['com.beeper.linkpreviews'] as BundleContent[];
+ bundleContent = bundleContent?.filter((bundle) => !!urls?.includes(bundle.matched_url));
return (
<>
diff --git a/src/app/components/message/Reaction.tsx b/src/app/components/message/Reaction.tsx
index 155de11f4..c6d212ec4 100644
--- a/src/app/components/message/Reaction.tsx
+++ b/src/app/components/message/Reaction.tsx
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { Box, Icon, Icons, Text, as } from 'folds';
import classNames from 'classnames';
-import { MatrixClient, MatrixEvent, Room } from '$types/matrix-sdk';
+import type { MatrixClient, MatrixEvent, Room } from '$types/matrix-sdk';
import { getHexcodeForEmoji, getShortcodeFor } from '$plugins/emoji';
import { getMemberDisplayName } from '$utils/room';
import { eventWithShortcode, getMxIdLocalPart, mxcUrlToHttp } from '$utils/matrix';
diff --git a/src/app/components/message/RenderBody.tsx b/src/app/components/message/RenderBody.tsx
index 8b83dff99..415984d13 100644
--- a/src/app/components/message/RenderBody.tsx
+++ b/src/app/components/message/RenderBody.tsx
@@ -1,12 +1,17 @@
-import { MouseEventHandler, useEffect, useState } from 'react';
-import parse, { HTMLReactParserOptions } from 'html-react-parser';
+import type { KeyboardEventHandler, MouseEventHandler } from 'react';
+import { useEffect, useState } from 'react';
+import type { HTMLReactParserOptions } from 'html-react-parser';
+import parse from 'html-react-parser';
import Linkify from 'linkify-react';
-import { find, Opts } from 'linkifyjs';
-import { PopOut, RectCords, Text, Tooltip, TooltipProvider, toRem } from 'folds';
+import type { Opts } from 'linkifyjs';
+import { find } from 'linkifyjs';
+import type { RectCords } from 'folds';
+import { PopOut, Text, Tooltip, TooltipProvider, toRem } from 'folds';
import { sanitizeCustomHtml } from '$utils/sanitize';
import { highlightText, scaleSystemEmoji } from '$plugins/react-custom-html-parser';
import { useRoomAbbreviationsContext } from '$hooks/useRoomAbbreviations';
-import { splitByAbbreviations, TextSegment } from '$utils/abbreviations';
+import type { TextSegment } from '$utils/abbreviations';
+import { splitByAbbreviations } from '$utils/abbreviations';
import { MessageEmptyContent } from './content';
function getRenderedBodyText(text: string, highlightRegex?: RegExp): (string | JSX.Element)[] {
@@ -64,9 +69,14 @@ function splitBodyTextByAbbreviations(
);
}
- return segments.length > 0
- ? segments.map((segment, index) => ({ ...segment, id: `txt-${index}` }))
- : [{ id: 'txt-0', text }];
+ if (segments.length === 0) {
+ return [{ id: 'txt-0', text }];
+ }
+ const result = segments as TextSegment[];
+ for (let i = 0; i < result.length; i += 1) {
+ result[i]!.id = `txt-${i}`;
+ }
+ return result;
}
type AbbreviationTermProps = {
@@ -76,10 +86,20 @@ type AbbreviationTermProps = {
function AbbreviationTerm({ text, definition }: AbbreviationTermProps) {
const [anchor, setAnchor] = useState();
+ const toggleAnchor = (target: HTMLElement) => {
+ setAnchor((prev) => (prev ? undefined : target.getBoundingClientRect()));
+ };
+
const handleClick: MouseEventHandler = (e) => {
- if (e.currentTarget === null) return;
e.stopPropagation();
- setAnchor((prev) => (prev ? undefined : e.currentTarget?.getBoundingClientRect()));
+ toggleAnchor(e.currentTarget);
+ };
+
+ const handleKeyDown: KeyboardEventHandler = (e) => {
+ if (e.key !== 'Enter' && e.key !== ' ') return;
+ e.preventDefault();
+ e.stopPropagation();
+ toggleAnchor(e.currentTarget);
};
// On mobile, tapping an abbreviation pins the tooltip open.
@@ -101,10 +121,12 @@ function AbbreviationTerm({ text, definition }: AbbreviationTermProps) {
<>
{(triggerRef) => (
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
}
onClick={handleClick}
+ onKeyDown={handleKeyDown}
+ role="button"
+ tabIndex={0}
style={{ textDecoration: 'underline dotted', cursor: 'help' }}
>
{text}
diff --git a/src/app/components/message/Reply.test.tsx b/src/app/components/message/Reply.test.tsx
index 1d57a4645..9c7975a16 100644
--- a/src/app/components/message/Reply.test.tsx
+++ b/src/app/components/message/Reply.test.tsx
@@ -2,9 +2,12 @@ import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { Reply } from './Reply';
+/* oxlint-disable typescript/no-explicit-any */
+
const { mockUseRoomEvent, mockInvalidateQueries } = vi.hoisted(() => ({
- mockUseRoomEvent: vi.fn(),
- mockInvalidateQueries: vi.fn(),
+ mockUseRoomEvent:
+ vi.fn<(_room: unknown, _replyEventId: unknown, _getFromLocalTimeline: unknown) => unknown>(),
+ mockInvalidateQueries: vi.fn<() => Promise>(),
}));
vi.mock('@tanstack/react-query', () => ({
@@ -14,7 +17,7 @@ vi.mock('@tanstack/react-query', () => ({
}));
vi.mock('jotai', async (importActual) => {
- const actual = await importActual();
+ const actual = (await importActual()) as object;
return {
...actual,
useAtomValue: () => ({}),
@@ -28,7 +31,7 @@ vi.mock('react-i18next', () => ({
}));
vi.mock('$hooks/useRoomEvent', () => ({
- useRoomEvent: (...args: unknown[]) => mockUseRoomEvent(...args),
+ useRoomEvent: (...args: unknown[]) => mockUseRoomEvent(args[0], args[1], args[2]),
}));
vi.mock('$hooks/useSableCosmetics', () => ({
@@ -53,7 +56,7 @@ vi.mock('$hooks/useMatrixClient', () => ({
}));
vi.mock('$hooks/useMemberEventParser', () => ({
- useMemberEventParser: () => vi.fn(),
+ useMemberEventParser: () => vi.fn<() => unknown>(),
}));
vi.mock('$hooks/useMentionClickHandler', () => ({
@@ -65,7 +68,7 @@ vi.mock('$features/settings/useSettingsLinkBaseUrl', () => ({
}));
vi.mock('$utils/room', async (importActual) => {
- const actual = await importActual();
+ const actual = (await importActual()) as object;
return {
...actual,
getMemberDisplayName: () => 'Alice',
@@ -112,7 +115,7 @@ describe('Reply', () => {
});
it('does not render unresolved mxc images as raw browser img tags in reply previews', () => {
- const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn<() => void>());
mockUseRoomEvent.mockReturnValue(
createReplyEvent(
diff --git a/src/app/components/message/Reply.tsx b/src/app/components/message/Reply.tsx
index 331ef043a..46537cd4d 100644
--- a/src/app/components/message/Reply.tsx
+++ b/src/app/components/message/Reply.tsx
@@ -1,6 +1,8 @@
-import { Box, Chip, Icon, IconSrc, Icons, Text, as, color, toRem } from 'folds';
-import { EventTimelineSet, IMentions, Room, SessionMembershipData } from '$types/matrix-sdk';
-import { MouseEventHandler, ReactNode, useCallback, useMemo } from 'react';
+import type { IconSrc } from 'folds';
+import { Box, Chip, Icon, Icons, Text, as, color, toRem } from 'folds';
+import type { EventTimelineSet, IMentions, Room, SessionMembershipData } from '$types/matrix-sdk';
+import type { MouseEventHandler, ReactNode } from 'react';
+import { useCallback, useMemo } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import classNames from 'classnames';
import parse from 'html-react-parser';
@@ -24,7 +26,7 @@ import { useIgnoredUsers } from '$hooks/useIgnoredUsers';
import { nicknamesAtom } from '$state/nicknames';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { useMemberEventParser } from '$hooks/useMemberEventParser';
-import { StateEvent, MessageEvent } from '$types/matrix/room';
+
import { useMentionClickHandler } from '$hooks/useMentionClickHandler';
import { useTranslation } from 'react-i18next';
import * as customHtmlCss from '$styles/CustomHtml.css';
@@ -37,6 +39,7 @@ import {
} from './content';
import * as css from './Reply.css';
import { LinePlaceholder } from './placeholder';
+import { EventType } from '$types/matrix-sdk';
type ReplyLayoutProps = {
userColor?: string;
@@ -192,7 +195,7 @@ export const Reply = as<'div', ReplyProps>(
} else if (hasPlainTextReply) {
const strippedBody = trimReplyFromBody(body).replaceAll(/(?:\r\n|\r|\n)/g, ' ');
bodyJSX = scaleSystemEmoji(strippedBody);
- } else if (eventType === StateEvent.RoomMember && !!replyEvent) {
+ } else if (eventType === EventType.RoomMember && !!replyEvent) {
const parsedMemberEvent = parseMemberEvent(replyEvent);
image = parsedMemberEvent.icon;
mentioned = false;
@@ -202,20 +205,20 @@ export const Reply = as<'div', ReplyProps>(
{parsedMemberEvent.body}{' '}
);
- } else if (eventType === StateEvent.RoomName) {
+ } else if (eventType === EventType.RoomName) {
image = Icons.Hash;
bodyJSX = t('Organisms.RoomCommon.changed_room_name');
- } else if (eventType === StateEvent.RoomTopic) {
+ } else if (eventType === EventType.RoomTopic) {
image = Icons.Hash;
bodyJSX = ' changed room topic';
- } else if (eventType === StateEvent.RoomAvatar) {
+ } else if (eventType === EventType.RoomAvatar) {
image = Icons.Hash;
bodyJSX = ' changed room avatar';
- } else if (eventType === StateEvent.GroupCallMemberPrefix && !!replyEvent) {
+ } else if (eventType === EventType.GroupCallMemberPrefix && !!replyEvent) {
const callJoined = replyEvent.getContent().application;
image = callJoined ? Icons.Phone : Icons.PhoneDown;
bodyJSX = callJoined ? ' joined the call' : ' ended the call';
- } else if (eventType === StateEvent.RoomPinnedEvents && replyEvent) {
+ } else if (eventType === EventType.RoomPinnedEvents && replyEvent) {
const { pinned } = replyEvent.getContent();
const prevPinned = replyEvent.getPrevContent().pinned;
const pinsAdded =
@@ -267,7 +270,7 @@ export const Reply = as<'div', ReplyProps>(
mentioned={mentioned}
username={
sender &&
- eventType !== StateEvent.RoomMember && (
+ eventType !== EventType.RoomMember && (
{getMemberDisplayName(room, sender, nicknames) ?? getMxIdLocalPart(sender)}
@@ -299,7 +302,9 @@ export const Reply = as<'div', ReplyProps>(
before={}
onClick={(evt) => {
evt.stopPropagation();
- queryClient.invalidateQueries({ queryKey: [room.roomId, replyEventId] });
+ queryClient.invalidateQueries({
+ queryKey: [room.roomId, replyEventId],
+ });
}}
/>
)}
diff --git a/src/app/components/message/Time.tsx b/src/app/components/message/Time.tsx
index dc190d93d..75b7aa422 100644
--- a/src/app/components/message/Time.tsx
+++ b/src/app/components/message/Time.tsx
@@ -1,4 +1,4 @@
-import { ComponentProps } from 'react';
+import type { ComponentProps } from 'react';
import { Text, as, Tooltip, TooltipProvider } from 'folds';
import {
timeDayMonYear,
diff --git a/src/app/components/message/attachment/Attachment.css.ts b/src/app/components/message/attachment/Attachment.css.ts
index dad95f616..d98b7fb61 100644
--- a/src/app/components/message/attachment/Attachment.css.ts
+++ b/src/app/components/message/attachment/Attachment.css.ts
@@ -1,5 +1,6 @@
import { style } from '@vanilla-extract/css';
-import { RecipeVariants, recipe } from '@vanilla-extract/recipes';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
import { DefaultReset, color, config, toRem } from 'folds';
export const Attachment = recipe({
diff --git a/src/app/components/message/content/AudioContent.tsx b/src/app/components/message/content/AudioContent.tsx
index fb0f2bef9..f20bbca64 100644
--- a/src/app/components/message/content/AudioContent.tsx
+++ b/src/app/components/message/content/AudioContent.tsx
@@ -1,13 +1,14 @@
-/* eslint-disable jsx-a11y/media-has-caption */
-import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
+/* oxlint-disable jsx-a11y/media-has-caption */
+import type { ReactNode } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import { Badge, Chip, Icon, IconButton, Icons, ProgressBar, Spinner, Text, toRem } from 'folds';
-import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
+import type { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import { Range } from 'react-range';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
-import { IAudioInfo } from '$types/matrix/common';
+import type { IAudioInfo } from '$types/matrix/common';
+import type { PlayTimeCallback } from '$hooks/media';
import {
- PlayTimeCallback,
useMediaLoading,
useMediaPlay,
useMediaPlayTimeCallback,
@@ -103,9 +104,12 @@ export function AudioContent({
min={0}
max={duration || 1}
values={[currentTime]}
- onChange={(values) => seek(values[0])}
+ onChange={(values) => seek(values[0] ?? 0)}
renderTrack={(params) => {
- const { key, ...restProps } = params.props as any;
+ const { key, ...restProps } = params.props as unknown as {
+ key?: string;
+ [key: string]: unknown;
+ };
return (
{params.children}
@@ -122,18 +126,22 @@ export function AudioContent({
);
}}
renderThumb={(params) => {
- const { key, style, ...restProps } = params.props as any;
+ const { key, style, ...restProps } = params.props as unknown as {
+ key?: unknown;
+ style?: Record
;
+ [key: string]: unknown;
+ };
return (
)}
style={{
- ...style,
+ ...(style as Record),
zIndex: 0,
}}
/>
@@ -180,9 +188,12 @@ export function AudioContent({
min={0}
max={1}
values={[volume]}
- onChange={(values) => setVolume(values[0])}
+ onChange={(values) => setVolume(values[0] ?? 1)}
renderTrack={(params) => {
- const { key, ...restProps } = params.props as any;
+ const { key, ...restProps } = params.props as unknown as {
+ key?: string;
+ [key: string]: unknown;
+ };
return (
{params.children}
@@ -199,18 +210,22 @@ export function AudioContent({
);
}}
renderThumb={(params) => {
- const { key, style, ...restProps } = params.props as any;
+ const { key, style, ...restProps } = params.props as unknown as {
+ key?: unknown;
+ style?: Record
;
+ [key: string]: unknown;
+ };
return (
)}
style={{
- ...style,
+ ...(style as Record),
zIndex: 0,
}}
/>
diff --git a/src/app/components/message/content/EventContent.tsx b/src/app/components/message/content/EventContent.tsx
index 35449e1ba..ac058985c 100644
--- a/src/app/components/message/content/EventContent.tsx
+++ b/src/app/components/message/content/EventContent.tsx
@@ -1,5 +1,6 @@
-import { Box, Icon, IconSrc } from 'folds';
-import { ReactNode } from 'react';
+import type { IconSrc } from 'folds';
+import { Box, Icon } from 'folds';
+import type { ReactNode } from 'react';
import { MessageLayout } from '$state/settings';
import { BubbleLayout, CompactLayout, ModernLayout } from '$components/message/layout';
@@ -12,9 +13,9 @@ export type EventContentProps = {
export function EventContent({ messageLayout, time, iconSrc, content }: EventContentProps) {
const beforeJSX = (
- {messageLayout === MessageLayout.Compact && time}
+ {messageLayout === (MessageLayout.Compact as number) && time}
@@ -26,14 +27,14 @@ export function EventContent({ messageLayout, time, iconSrc, content }: EventCon
const msgContentJSX = (
{content}
- {messageLayout !== MessageLayout.Compact && time}
+ {messageLayout !== (MessageLayout.Compact as number) && time}
);
- if (messageLayout === MessageLayout.Compact) {
+ if (messageLayout === (MessageLayout.Compact as number)) {
return {msgContentJSX};
}
- if (messageLayout === MessageLayout.Bubble) {
+ if (messageLayout === (MessageLayout.Bubble as number)) {
return (
{msgContentJSX}
diff --git a/src/app/components/message/content/FileContent.tsx b/src/app/components/message/content/FileContent.tsx
index af802d46b..73b11613f 100644
--- a/src/app/components/message/content/FileContent.tsx
+++ b/src/app/components/message/content/FileContent.tsx
@@ -1,4 +1,5 @@
-import { ReactNode, useCallback, useState } from 'react';
+import type { ReactNode } from 'react';
+import { useCallback, useState } from 'react';
import {
Box,
Button,
@@ -15,9 +16,9 @@ import {
as,
} from 'folds';
import FileSaver from 'file-saver';
-import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
+import type { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import FocusTrap from 'focus-trap-react';
-import { IFileInfo } from '$types/matrix/common';
+import type { IFileInfo } from '$types/matrix/common';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { bytesToSize } from '$utils/common';
@@ -109,7 +110,7 @@ export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: Rea
evt.stopPropagation()}
+ onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
>
{renderViewer({
name: body,
@@ -198,7 +199,7 @@ export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: Read
evt.stopPropagation()}
+ onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
>
{renderViewer({
name: body,
diff --git a/src/app/components/message/content/ImageContent.tsx b/src/app/components/message/content/ImageContent.tsx
index 60cb9cb09..d5d9ccc41 100644
--- a/src/app/components/message/content/ImageContent.tsx
+++ b/src/app/components/message/content/ImageContent.tsx
@@ -1,4 +1,5 @@
-import { ReactNode, useCallback, useEffect, useState } from 'react';
+import type { ReactNode } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import {
Badge,
Box,
@@ -22,8 +23,9 @@ import {
import classNames from 'classnames';
import { BlurhashCanvas } from 'react-blurhash';
import FocusTrap from 'focus-trap-react';
-import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
-import { IImageInfo, MATRIX_BLUR_HASH_PROPERTY_NAME } from '$types/matrix/common';
+import type { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
+import type { IImageInfo } from '$types/matrix/common';
+import { MATRIX_BLUR_HASH_PROPERTY_NAME } from '$types/matrix/common';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { bytesToSize } from '$utils/common';
@@ -151,7 +153,7 @@ export const ImageContent = as<'div', ImageContentProps>(
evt.stopPropagation()}
+ onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
>
{renderViewer({
src: srcState.data,
diff --git a/src/app/components/message/content/ThumbnailContent.tsx b/src/app/components/message/content/ThumbnailContent.tsx
index 2d0510bed..53e27002f 100644
--- a/src/app/components/message/content/ThumbnailContent.tsx
+++ b/src/app/components/message/content/ThumbnailContent.tsx
@@ -1,5 +1,6 @@
-import { ReactNode, useCallback, useEffect } from 'react';
-import { IThumbnailContent } from '$types/matrix/common';
+import type { ReactNode } from 'react';
+import { useCallback, useEffect } from 'react';
+import type { IThumbnailContent } from '$types/matrix/common';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { decryptFile, downloadEncryptedMedia, mxcUrlToHttp } from '$utils/matrix';
diff --git a/src/app/components/message/content/VideoContent.tsx b/src/app/components/message/content/VideoContent.tsx
index 71613c598..51658ebf5 100644
--- a/src/app/components/message/content/VideoContent.tsx
+++ b/src/app/components/message/content/VideoContent.tsx
@@ -1,4 +1,5 @@
-import { ReactNode, useCallback, useEffect, useState } from 'react';
+import type { ReactNode } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import {
Badge,
Box,
@@ -17,12 +18,9 @@ import {
} from 'folds';
import classNames from 'classnames';
import { BlurhashCanvas } from 'react-blurhash';
-import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
-import {
- IThumbnailContent,
- IVideoInfo,
- MATRIX_BLUR_HASH_PROPERTY_NAME,
-} from '$types/matrix/common';
+import type { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
+import type { IThumbnailContent, IVideoInfo } from '$types/matrix/common';
+import { MATRIX_BLUR_HASH_PROPERTY_NAME } from '$types/matrix/common';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { bytesToSize, millisecondsToMinutesAndSeconds } from '$utils/common';
diff --git a/src/app/components/message/layout/Bubble.tsx b/src/app/components/message/layout/Bubble.tsx
index 21120da47..27ab97bac 100644
--- a/src/app/components/message/layout/Bubble.tsx
+++ b/src/app/components/message/layout/Bubble.tsx
@@ -1,6 +1,7 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import classNames from 'classnames';
-import { Box, ContainerColor, as, color } from 'folds';
+import type { ContainerColor } from 'folds';
+import { Box, as, color } from 'folds';
import * as css from './layout.css';
type BubbleArrowProps = {
diff --git a/src/app/components/message/layout/Compact.tsx b/src/app/components/message/layout/Compact.tsx
index e9015ab96..a5422bb0d 100644
--- a/src/app/components/message/layout/Compact.tsx
+++ b/src/app/components/message/layout/Compact.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import { Box, as } from 'folds';
import * as css from './layout.css';
diff --git a/src/app/components/message/layout/Modern.tsx b/src/app/components/message/layout/Modern.tsx
index e73e93013..6c21b07ab 100644
--- a/src/app/components/message/layout/Modern.tsx
+++ b/src/app/components/message/layout/Modern.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import { Box, as } from 'folds';
import * as css from './layout.css';
diff --git a/src/app/components/message/layout/layout.css.ts b/src/app/components/message/layout/layout.css.ts
index ee423ca2c..e30e4c8c3 100644
--- a/src/app/components/message/layout/layout.css.ts
+++ b/src/app/components/message/layout/layout.css.ts
@@ -1,5 +1,6 @@
import { createVar, keyframes, style, styleVariants } from '@vanilla-extract/css';
-import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
import { DefaultReset, color, config, toRem } from 'folds';
export const StickySection = style({
diff --git a/src/app/components/message/modals/MessageDelete.tsx b/src/app/components/message/modals/MessageDelete.tsx
index 666895102..7e4fba5be 100644
--- a/src/app/components/message/modals/MessageDelete.tsx
+++ b/src/app/components/message/modals/MessageDelete.tsx
@@ -1,5 +1,6 @@
-import { FormEventHandler, MouseEvent, useCallback, useEffect } from 'react';
-import { Room, MatrixEvent } from '$types/matrix-sdk';
+import type { FormEventHandler, MouseEvent } from 'react';
+import { useCallback, useEffect } from 'react';
+import type { Room, MatrixEvent } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import {
Box,
diff --git a/src/app/components/message/modals/MessageEditHistory.tsx b/src/app/components/message/modals/MessageEditHistory.tsx
index 9581aa419..f806b61ae 100644
--- a/src/app/components/message/modals/MessageEditHistory.tsx
+++ b/src/app/components/message/modals/MessageEditHistory.tsx
@@ -1,5 +1,5 @@
-import { MouseEvent } from 'react';
-import { Room, MatrixEvent } from '$types/matrix-sdk';
+import type { MouseEvent } from 'react';
+import type { Room, MatrixEvent } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import { MenuItem, Icon, Icons, Text } from 'folds';
import { getEventEdits } from '$utils/room';
diff --git a/src/app/components/message/modals/MessageForward.tsx b/src/app/components/message/modals/MessageForward.tsx
index 133dc940e..94df68049 100644
--- a/src/app/components/message/modals/MessageForward.tsx
+++ b/src/app/components/message/modals/MessageForward.tsx
@@ -17,7 +17,8 @@ import {
as,
} from 'folds';
import { useAtomValue, useSetAtom } from 'jotai';
-import { JoinRule, MatrixEvent, Room } from '$types/matrix-sdk';
+import type { MatrixEvent, Room } from '$types/matrix-sdk';
+import { JoinRule, EventType } from '$types/matrix-sdk';
import { useEffect, useMemo, useState } from 'react';
import { allRoomsAtom } from '$state/room-list/roomList';
import { useAllJoinedRoomsSet, useGetRoom } from '$hooks/useGetRoom';
@@ -25,7 +26,7 @@ import { factoryRoomIdByActivity } from '$utils/sort';
import * as css from '$features/room/message/styles.css';
import { sanitizeCustomHtml, sanitizeText } from '$utils/sanitize';
import { getStateEvents } from '$utils/room';
-import { StateEvent } from '$types/matrix/room';
+
import { createDebugLogger } from '$utils/debugLogger';
import * as Sentry from '@sentry/react';
@@ -115,7 +116,7 @@ export function MessageForwardInternal({
// detect if it's a public room or not
const joinRule = room.getJoinRule() ?? JoinRule.Invite;
- const parentSpaceIds = getStateEvents(room, StateEvent.SpaceParent)
+ const parentSpaceIds = getStateEvents(room, EventType.SpaceParent)
.map((e) => e.getStateKey())
.filter((id): id is string => Boolean(id));
@@ -265,7 +266,7 @@ export function MessageForwardInternal({
};
}
- const msgtype = String(originalContent.msgtype ?? 'unknown');
+ const msgtype = originalContent.msgtype ?? 'unknown';
debugLog.info('ui', 'Forwarding message', {
sourceRoomId: room.roomId,
targetRoomId: targetRoom.roomId,
diff --git a/src/app/components/message/modals/MessageReactions.tsx b/src/app/components/message/modals/MessageReactions.tsx
index f2fa7a5bd..a2fbae286 100644
--- a/src/app/components/message/modals/MessageReactions.tsx
+++ b/src/app/components/message/modals/MessageReactions.tsx
@@ -1,5 +1,5 @@
-import { MouseEvent } from 'react';
-import { Room, Relations } from '$types/matrix-sdk';
+import type { MouseEvent } from 'react';
+import type { Room, Relations } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import { Icon, Icons, Text, MenuItem } from 'folds';
import { modalAtom, ModalType } from '$state/modal';
diff --git a/src/app/components/message/modals/MessageReadRecipts.tsx b/src/app/components/message/modals/MessageReadRecipts.tsx
index 6642627c0..6dfec9849 100644
--- a/src/app/components/message/modals/MessageReadRecipts.tsx
+++ b/src/app/components/message/modals/MessageReadRecipts.tsx
@@ -1,5 +1,5 @@
-import { MouseEvent } from 'react';
-import { Room } from '$types/matrix-sdk';
+import type { MouseEvent } from 'react';
+import type { Room } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import { MenuItem, Icon, Icons, Text } from 'folds';
import { modalAtom, ModalType } from '$state/modal';
diff --git a/src/app/components/message/modals/MessageReport.tsx b/src/app/components/message/modals/MessageReport.tsx
index 71cf03cc5..1d1357ddf 100644
--- a/src/app/components/message/modals/MessageReport.tsx
+++ b/src/app/components/message/modals/MessageReport.tsx
@@ -1,5 +1,6 @@
-import { FormEventHandler, MouseEvent, useCallback, useEffect } from 'react';
-import { Room, MatrixEvent } from '$types/matrix-sdk';
+import type { FormEventHandler, MouseEvent } from 'react';
+import { useCallback, useEffect } from 'react';
+import type { Room, MatrixEvent } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import {
Box,
diff --git a/src/app/components/message/modals/MessageSource.tsx b/src/app/components/message/modals/MessageSource.tsx
index eff8e1e58..6d186a780 100644
--- a/src/app/components/message/modals/MessageSource.tsx
+++ b/src/app/components/message/modals/MessageSource.tsx
@@ -1,5 +1,5 @@
-import { MouseEvent } from 'react';
-import { Room, MatrixEvent } from '$types/matrix-sdk';
+import type { MouseEvent } from 'react';
+import type { Room, MatrixEvent } from '$types/matrix-sdk';
import { useSetAtom } from 'jotai';
import { MenuItem, Icon, Icons, Text } from 'folds';
import { TextViewer } from '$components/text-viewer';
@@ -38,15 +38,15 @@ type MessageSourceInternalProps = {
onClose: () => void;
};
-export function MessageSourceInternal({ room, mEvent, onClose }: MessageSourceInternalProps) {
- const getContent = (evt: MatrixEvent) =>
- evt.isEncrypted()
- ? {
- [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
- [`<== ORIGINAL_EVENT ==>`]: evt.event,
- }
- : evt.event;
+const getContent = (evt: MatrixEvent) =>
+ evt.isEncrypted()
+ ? {
+ [`<== DECRYPTED_EVENT ==>`]: evt.getEffectiveEvent(),
+ [`<== ORIGINAL_EVENT ==>`]: evt.event,
+ }
+ : evt.event;
+export function MessageSourceInternal({ room, mEvent, onClose }: MessageSourceInternalProps) {
const getText = (): string => {
const evtId = mEvent.getId()!;
const evtTimeline = room.getTimelineForEvent(evtId);
diff --git a/src/app/components/message/placeholder/CompactPlaceholder.tsx b/src/app/components/message/placeholder/CompactPlaceholder.tsx
index c6e6dda00..f96d79497 100644
--- a/src/app/components/message/placeholder/CompactPlaceholder.tsx
+++ b/src/app/components/message/placeholder/CompactPlaceholder.tsx
@@ -1,5 +1,6 @@
import { useMemo } from 'react';
-import { as, ContainerColor, toRem } from 'folds';
+import type { ContainerColor } from 'folds';
+import { as, toRem } from 'folds';
import { randomNumberBetween } from '$utils/common';
import { CompactLayout } from '$components/message/layout';
import { LinePlaceholder } from './LinePlaceholder';
diff --git a/src/app/components/message/placeholder/DefaultPlaceholder.tsx b/src/app/components/message/placeholder/DefaultPlaceholder.tsx
index 444990ac6..7e9438e90 100644
--- a/src/app/components/message/placeholder/DefaultPlaceholder.tsx
+++ b/src/app/components/message/placeholder/DefaultPlaceholder.tsx
@@ -1,12 +1,18 @@
-import { CSSProperties, useMemo } from 'react';
-import { Avatar, Box, ContainerColor, as, color, toRem } from 'folds';
+import type { CSSProperties } from 'react';
+import { useMemo } from 'react';
+import type { ContainerColor } from 'folds';
+import { Avatar, Box, as, color, toRem } from 'folds';
import { randomNumberBetween } from '$utils/common';
import { ModernLayout } from '$components/message/layout';
import { LinePlaceholder } from './LinePlaceholder';
const contentMargin: CSSProperties = { marginTop: toRem(3) };
-export const DefaultPlaceholder = as<'div', { variant?: ContainerColor }>(
+type DefaultPlaceholderProps = {
+ variant?: ContainerColor;
+};
+
+export const DefaultPlaceholder = as<'div', DefaultPlaceholderProps>(
({ variant, ...props }, ref) => {
const nameSize = useMemo(() => randomNumberBetween(40, 100), []);
const msgSize = useMemo(() => randomNumberBetween(80, 200), []);
@@ -18,7 +24,9 @@ export const DefaultPlaceholder = as<'div', { variant?: ContainerColor }>(
ref={ref}
before={
}
diff --git a/src/app/components/message/placeholder/LinePlaceholder.css.ts b/src/app/components/message/placeholder/LinePlaceholder.css.ts
index 34ad76a3e..aefc3c655 100644
--- a/src/app/components/message/placeholder/LinePlaceholder.css.ts
+++ b/src/app/components/message/placeholder/LinePlaceholder.css.ts
@@ -1,6 +1,8 @@
-import { ComplexStyleRule } from '@vanilla-extract/css';
-import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
-import { ContainerColor, DefaultReset, color, config, toRem } from 'folds';
+import type { ComplexStyleRule } from '@vanilla-extract/css';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
+import type { ContainerColor } from 'folds';
+import { DefaultReset, color, config, toRem } from 'folds';
const getVariant = (variant: ContainerColor): ComplexStyleRule => ({
backgroundColor: color[variant].Container,
diff --git a/src/app/components/nav/NavCategory.tsx b/src/app/components/nav/NavCategory.tsx
index 7285330f0..8c87f84de 100644
--- a/src/app/components/nav/NavCategory.tsx
+++ b/src/app/components/nav/NavCategory.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import { as } from 'folds';
import classNames from 'classnames';
import * as css from './styles.css';
diff --git a/src/app/components/nav/NavCategoryHeader.tsx b/src/app/components/nav/NavCategoryHeader.tsx
index 1d4152fc9..9c09ca186 100644
--- a/src/app/components/nav/NavCategoryHeader.tsx
+++ b/src/app/components/nav/NavCategoryHeader.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import classNames from 'classnames';
import { Header, as } from 'folds';
import * as css from './styles.css';
diff --git a/src/app/components/nav/NavEmptyLayout.tsx b/src/app/components/nav/NavEmptyLayout.tsx
index 25b69380b..6b110cac7 100644
--- a/src/app/components/nav/NavEmptyLayout.tsx
+++ b/src/app/components/nav/NavEmptyLayout.tsx
@@ -1,5 +1,5 @@
import { Box, config } from 'folds';
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
export function NavEmptyCenter({ children }: { children: ReactNode }) {
return (
diff --git a/src/app/components/nav/NavItem.tsx b/src/app/components/nav/NavItem.tsx
index 68a967f6f..673baea9d 100644
--- a/src/app/components/nav/NavItem.tsx
+++ b/src/app/components/nav/NavItem.tsx
@@ -1,24 +1,22 @@
import classNames from 'classnames';
-import { ComponentProps, forwardRef } from 'react';
+import type { ComponentProps } from 'react';
+import { forwardRef } from 'react';
import { Link } from 'react-router-dom';
import { as } from 'folds';
import * as css from './styles.css';
-export const NavItem = as<
- 'div',
- {
- highlight?: boolean;
- } & css.RoomSelectorVariants
->(({ as: AsNavItem = 'div', className, highlight, variant, radii, children, ...props }, ref) => (
-
- {children}
-
-));
+export const NavItem = as<'div', { highlight?: boolean } & css.RoomSelectorVariants>(
+ ({ as: AsNavItem = 'div', className, highlight, variant, radii, children, ...props }, ref) => (
+
+ {children}
+
+ )
+);
export const NavLink = forwardRef>(
({ className, ...props }, ref) => (
diff --git a/src/app/components/nav/NavItemContent.tsx b/src/app/components/nav/NavItemContent.tsx
index eaf8f113e..a6aa6e985 100644
--- a/src/app/components/nav/NavItemContent.tsx
+++ b/src/app/components/nav/NavItemContent.tsx
@@ -1,4 +1,4 @@
-import { ComponentProps } from 'react';
+import type { ComponentProps } from 'react';
import { Text, as } from 'folds';
import classNames from 'classnames';
import * as css from './styles.css';
diff --git a/src/app/components/nav/NavItemOptions.tsx b/src/app/components/nav/NavItemOptions.tsx
index a735781e5..1929dfff2 100644
--- a/src/app/components/nav/NavItemOptions.tsx
+++ b/src/app/components/nav/NavItemOptions.tsx
@@ -1,4 +1,4 @@
-import { ComponentProps } from 'react';
+import type { ComponentProps } from 'react';
import { Box, as } from 'folds';
import classNames from 'classnames';
import * as css from './styles.css';
diff --git a/src/app/components/nav/styles.css.ts b/src/app/components/nav/styles.css.ts
index 48b2a4d34..f72d3fe38 100644
--- a/src/app/components/nav/styles.css.ts
+++ b/src/app/components/nav/styles.css.ts
@@ -1,6 +1,9 @@
-import { ComplexStyleRule, createVar, style } from '@vanilla-extract/css';
-import { RecipeVariants, recipe } from '@vanilla-extract/recipes';
-import { ContainerColor, DefaultReset, Disabled, RadiiVariant, color, config, toRem } from 'folds';
+import type { ComplexStyleRule } from '@vanilla-extract/css';
+import { createVar, style } from '@vanilla-extract/css';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
+import type { ContainerColor } from 'folds';
+import { DefaultReset, Disabled, RadiiVariant, color, config, toRem } from 'folds';
export const NavCategory = style([
DefaultReset,
diff --git a/src/app/components/notification-banner/NotificationBanner.tsx b/src/app/components/notification-banner/NotificationBanner.tsx
index b574e3585..4476e8389 100644
--- a/src/app/components/notification-banner/NotificationBanner.tsx
+++ b/src/app/components/notification-banner/NotificationBanner.tsx
@@ -1,8 +1,10 @@
import { useAtom } from 'jotai';
-import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
+import type { ReactNode } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import { Box, Icon, IconButton, Icons, Text } from 'folds';
import { createLogger } from '$utils/debug';
-import { inAppBannerAtom, InAppBannerNotification } from '$state/sessions';
+import type { InAppBannerNotification } from '$state/sessions';
+import { inAppBannerAtom } from '$state/sessions';
import * as css from './NotificationBanner.css';
const log = createLogger('NotificationBanner');
diff --git a/src/app/components/page/Page.tsx b/src/app/components/page/Page.tsx
index b481df637..c6bb22d44 100644
--- a/src/app/components/page/Page.tsx
+++ b/src/app/components/page/Page.tsx
@@ -1,4 +1,4 @@
-import { ComponentProps, MutableRefObject, ReactNode } from 'react';
+import type { ComponentProps, MutableRefObject, ReactNode } from 'react';
import { Box, Header, Line, Scroll, Text, as } from 'folds';
import classNames from 'classnames';
import { ContainerColor } from '$styles/ContainerColor.css';
diff --git a/src/app/components/page/style.css.ts b/src/app/components/page/style.css.ts
index bd14cd583..d35fa651d 100644
--- a/src/app/components/page/style.css.ts
+++ b/src/app/components/page/style.css.ts
@@ -1,5 +1,6 @@
import { style } from '@vanilla-extract/css';
-import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
import { DefaultReset, color, config, toRem } from 'folds';
export const PageNav = recipe({
diff --git a/src/app/components/password-input/PasswordInput.tsx b/src/app/components/password-input/PasswordInput.tsx
index d1fdea246..d859af8d7 100644
--- a/src/app/components/password-input/PasswordInput.tsx
+++ b/src/app/components/password-input/PasswordInput.tsx
@@ -1,4 +1,5 @@
-import { ComponentProps, forwardRef } from 'react';
+import type { ComponentProps } from 'react';
+import { forwardRef } from 'react';
import { Icon, IconButton, Input, config, Icons } from 'folds';
import { UseStateProvider } from '$components/UseStateProvider';
diff --git a/src/app/components/power/PowerSelector.tsx b/src/app/components/power/PowerSelector.tsx
index 23188aeae..8d4d61876 100644
--- a/src/app/components/power/PowerSelector.tsx
+++ b/src/app/components/power/PowerSelector.tsx
@@ -1,7 +1,10 @@
-import { forwardRef, MouseEventHandler, ReactNode, useState } from 'react';
+import type { MouseEventHandler, ReactNode } from 'react';
+import { forwardRef, useState } from 'react';
import FocusTrap from 'focus-trap-react';
-import { Box, config, Menu, MenuItem, PopOut, Scroll, Text, toRem, RectCords } from 'folds';
-import { getPowers, PowerLevelTags } from '$hooks/usePowerLevelTags';
+import type { RectCords } from 'folds';
+import { Box, config, Menu, MenuItem, PopOut, Scroll, Text, toRem } from 'folds';
+import type { PowerLevelTags } from '$hooks/usePowerLevelTags';
+import { getPowers } from '$hooks/usePowerLevelTags';
import { stopPropagation } from '$utils/keyboard';
import { PowerColorBadge } from './PowerColorBadge';
@@ -33,11 +36,11 @@ export const PowerSelector = forwardRef(
aria-pressed={selected}
radii="300"
onClick={selected ? undefined : () => onChange(power)}
- before={}
+ before={}
after={{power}}
>
- {tag.name}
+ {tag!.name}
);
diff --git a/src/app/components/power/style.css.ts b/src/app/components/power/style.css.ts
index 60737f8cb..d0ccc88fc 100644
--- a/src/app/components/power/style.css.ts
+++ b/src/app/components/power/style.css.ts
@@ -1,5 +1,6 @@
import { createVar, style } from '@vanilla-extract/css';
-import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
+import type { RecipeVariants } from '@vanilla-extract/recipes';
+import { recipe } from '@vanilla-extract/recipes';
import { color, config, DefaultReset, toRem } from 'folds';
export const PowerColorBadge = style({
diff --git a/src/app/components/presence/Presence.tsx b/src/app/components/presence/Presence.tsx
index e6ac463bb..88543b7f6 100644
--- a/src/app/components/presence/Presence.tsx
+++ b/src/app/components/presence/Presence.tsx
@@ -1,16 +1,7 @@
-import {
- as,
- Badge,
- Box,
- color,
- ContainerColor,
- MainColor,
- Text,
- Tooltip,
- TooltipProvider,
- toRem,
-} from 'folds';
-import { ReactNode, useId } from 'react';
+import type { ContainerColor, MainColor } from 'folds';
+import { as, Badge, Box, color, Text, Tooltip, TooltipProvider, toRem } from 'folds';
+import type { ReactNode } from 'react';
+import { useId } from 'react';
import { Presence, usePresenceLabel } from '$hooks/useUserPresence';
import * as css from './styles.css';
diff --git a/src/app/components/room-avatar/AvatarImage.tsx b/src/app/components/room-avatar/AvatarImage.tsx
index 1e4cb0d0a..f322bce0e 100644
--- a/src/app/components/room-avatar/AvatarImage.tsx
+++ b/src/app/components/room-avatar/AvatarImage.tsx
@@ -1,5 +1,6 @@
import { AvatarImage as FoldsAvatarImage } from 'folds';
-import { ReactEventHandler, useState, useEffect } from 'react';
+import type { ReactEventHandler } from 'react';
+import { useState, useEffect } from 'react';
import bgColorImg from '$utils/bgColorImg';
import { settingsAtom } from '$state/settings';
import { useSetting } from '$state/hooks/settings';
diff --git a/src/app/components/room-avatar/RoomAvatar.tsx b/src/app/components/room-avatar/RoomAvatar.tsx
index 33f9f6881..fa8acd4e5 100644
--- a/src/app/components/room-avatar/RoomAvatar.tsx
+++ b/src/app/components/room-avatar/RoomAvatar.tsx
@@ -1,6 +1,7 @@
-import { JoinRule } from '$types/matrix-sdk';
+import type { JoinRule } from '$types/matrix-sdk';
import { AvatarFallback, Icon, Icons, color } from 'folds';
-import { ComponentProps, ReactNode, forwardRef, useEffect, useState } from 'react';
+import type { ComponentProps, ReactNode } from 'react';
+import { forwardRef, useEffect, useState } from 'react';
import { getRoomIconSrc } from '$utils/room';
import colorMXID from '$utils/colorMXID';
import * as css from './RoomAvatar.css';
diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx
index 7f9046d77..ed905872e 100644
--- a/src/app/components/room-card/RoomCard.tsx
+++ b/src/app/components/room-card/RoomCard.tsx
@@ -1,5 +1,7 @@
-import { ReactNode, useCallback, useRef, useState } from 'react';
-import { JoinRule, MatrixError, Room } from '$types/matrix-sdk';
+import type { ReactNode } from 'react';
+import { useCallback, useRef, useState } from 'react';
+import type { MatrixError, Room } from '$types/matrix-sdk';
+import { JoinRule, EventType, RoomType } from '$types/matrix-sdk';
import {
Avatar,
Badge,
@@ -24,7 +26,7 @@ import { nameInitials } from '$utils/common';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
import { onEnterOrSpace, stopPropagation } from '$utils/keyboard';
-import { RoomType, StateEvent } from '$types/matrix/room';
+
import { useJoinedRoomId } from '$hooks/useJoinedRoomId';
import { useElementSizeObserver } from '$hooks/useElementSizeObserver';
import { getRoomAvatarUrl, getStateEvent } from '$utils/room';
@@ -173,7 +175,7 @@ export const RoomCard = as<'div', RoomCardProps>(
const joinedRoomId = useJoinedRoomId(allRooms, roomIdOrAlias);
const joinedRoom = mx.getRoom(joinedRoomId);
const [topicEvent, setTopicEvent] = useState(() =>
- joinedRoom ? getStateEvent(joinedRoom, StateEvent.RoomTopic) : undefined
+ joinedRoom ? getStateEvent(joinedRoom, EventType.RoomTopic) : undefined
);
const [knocking, setKnocking] = useState(false);
const fallbackName = getMxIdLocalPart(roomIdOrAlias) ?? roomIdOrAlias;
@@ -195,9 +197,9 @@ export const RoomCard = as<'div', RoomCardProps>(
if (
joinedRoom &&
event.getRoomId() === joinedRoom.roomId &&
- event.getType() === StateEvent.RoomTopic
+ event.getType() === (EventType.RoomTopic as string)
) {
- setTopicEvent(getStateEvent(joinedRoom, StateEvent.RoomTopic));
+ setTopicEvent(getStateEvent(joinedRoom, EventType.RoomTopic));
}
},
[joinedRoom]
diff --git a/src/app/components/room-intro/RoomIntro.tsx b/src/app/components/room-intro/RoomIntro.tsx
index 3ad39546f..cd993fb38 100644
--- a/src/app/components/room-intro/RoomIntro.tsx
+++ b/src/app/components/room-intro/RoomIntro.tsx
@@ -1,8 +1,9 @@
import { useCallback, useEffect, useState } from 'react';
import { Avatar, Box, Button, Icon, Icons, Spinner, Text, as } from 'folds';
-import { Room } from '$types/matrix-sdk';
+import type { Room } from '$types/matrix-sdk';
import { useAtomValue } from 'jotai';
-import { IRoomCreateContent, Membership, StateEvent } from '$types/matrix/room';
+import type { IRoomCreateContent } from '$types/matrix/room';
+
import { getMemberDisplayName, getStateEvent } from '$utils/room';
import { nicknamesAtom } from '$state/nicknames';
import { useMatrixClient } from '$hooks/useMatrixClient';
@@ -20,6 +21,7 @@ import { RoomAvatar } from '$components/room-avatar';
import { InviteUserPrompt } from '$components/invite-user-prompt';
import { InfoCard } from '$components/info-card';
import { DirectInvitePrompt } from '$components/direct-invite-prompt';
+import { EventType, KnownMembership } from '$types/matrix-sdk';
export type RoomIntroProps = {
room: Room;
@@ -35,7 +37,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
const [invitePrompt, setInvitePrompt] = useState(false);
const [directInvitePrompt, setDirectInvitePrompt] = useState(false);
- const createEvent = getStateEvent(room, StateEvent.RoomCreate);
+ const createEvent = getStateEvent(room, EventType.RoomCreate);
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
const name = useRoomName(room);
const topic = useRoomTopic(room);
@@ -133,7 +135,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
)}
{typeof prevRoomId === 'string' &&
- (mx.getRoom(prevRoomId)?.getMyMembership() === Membership.Join ? (
+ (mx.getRoom(prevRoomId)?.getMyMembership() === KnownMembership.Join ? (
{showMisc && miscSelector}
),
- [miscSelector, miscDataIndex, showMisc, unknownFields]
+ [miscSelector, miscDataIndex, selectedUnknownField, showMisc, unknownFields]
);
return (
@@ -328,7 +333,7 @@ function UserExtendedSection({
}}
>
@@ -372,6 +377,10 @@ export function UserRoomProfile({ userId, initialProfile }: Readonly
{ignored && }
- {member && membership === Membership.Ban && (
+ {member && membership === bannedMembership && (
)}
{member &&
- membership === Membership.Leave &&
+ membership === leftMembership &&
member.events.member &&
member.events.member.getSender() !== userId && (
)}
- {member && membership === Membership.Invite && (
+ {member && membership === invitedMembership && (
diff --git a/src/app/components/virtualizer/VirtualTile.tsx b/src/app/components/virtualizer/VirtualTile.tsx
index b92add55a..6e998c1fe 100644
--- a/src/app/components/virtualizer/VirtualTile.tsx
+++ b/src/app/components/virtualizer/VirtualTile.tsx
@@ -1,4 +1,4 @@
-import { VirtualItem } from '@tanstack/react-virtual';
+import type { VirtualItem } from '@tanstack/react-virtual';
import { as } from 'folds';
import classNames from 'classnames';
import * as css from './style.css';
diff --git a/src/app/cs-api.ts b/src/app/cs-api.ts
index 42d689b98..636d0ec53 100644
--- a/src/app/cs-api.ts
+++ b/src/app/cs-api.ts
@@ -86,7 +86,7 @@ export const autoDiscovery = async (
];
}
- if (/^https?:\/\//.test(baseUrl) === false) {
+ if (!/^https?:\/\//.test(baseUrl)) {
return [
{
host,
diff --git a/src/app/features/add-existing/AddExisting.tsx b/src/app/features/add-existing/AddExisting.tsx
index 50cfc6717..1a589ced4 100644
--- a/src/app/features/add-existing/AddExisting.tsx
+++ b/src/app/features/add-existing/AddExisting.tsx
@@ -19,17 +19,11 @@ import {
Spinner,
Text,
} from 'folds';
-import {
- ChangeEventHandler,
- MouseEventHandler,
- useCallback,
- useMemo,
- useRef,
- useState,
-} from 'react';
+import type { ChangeEventHandler, MouseEventHandler } from 'react';
+import { useCallback, useMemo, useRef, useState } from 'react';
import { useAtomValue } from 'jotai';
import { useVirtualizer } from '@tanstack/react-virtual';
-import { Room } from '$types/matrix-sdk';
+import type { Room, StateEvents } from '$types/matrix-sdk';
import { stopPropagation } from '$utils/keyboard';
import { useDirects, useRooms, useSpaces } from '$state/hooks/roomList';
import { useMatrixClient } from '$hooks/useMatrixClient';
@@ -43,13 +37,15 @@ import { RoomAvatar, RoomIcon } from '$components/room-avatar';
import { nameInitials } from '$utils/common';
import { useMediaAuthentication } from '$hooks/useMediaAuthentication';
import { factoryRoomIdByAtoZ } from '$utils/sort';
-import { SearchItemStrGetter, useAsyncSearch, UseAsyncSearchOptions } from '$hooks/useAsyncSearch';
+import type { SearchItemStrGetter, UseAsyncSearchOptions } from '$hooks/useAsyncSearch';
+import { useAsyncSearch } from '$hooks/useAsyncSearch';
import { highlightText, makeHighlightRegex } from '$plugins/react-custom-html-parser';
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
-import { StateEvent } from '$types/matrix/room';
+
import { getViaServers } from '$plugins/via-servers';
import { rateLimitedActions } from '$utils/matrix';
import { useAlive } from '$hooks/useAlive';
+import { EventType } from '$types/matrix-sdk';
const SEARCH_OPTS: UseAsyncSearchOptions = {
limit: 500,
@@ -114,7 +110,7 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM
return rIds
.filter((rId) => rId !== parentId && !isAncestor(rId, parentId))
- .sort(factoryRoomIdByAtoZ(mx));
+ .toSorted(factoryRoomIdByAtoZ(mx));
}, [space, spaces, rooms, directs, mx, parentId, isAncestor]);
const getRoomNameStr: SearchItemStrGetter = useCallback(
@@ -158,12 +154,12 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM
await mx.sendStateEvent(
parentId,
- StateEvent.SpaceChild as any,
+ EventType.SpaceChild,
{
auto_join: false,
suggested: false,
via,
- },
+ } as StateEvents[typeof EventType.SpaceChild],
room.roomId
);
});
@@ -237,7 +233,11 @@ export function AddExistingModal({ parentId, space, requestClose }: AddExistingM
>
{vItems.map((vItem) => {
const roomId = items[vItem.index];
+ if (!roomId) return null;
const room = getRoom(roomId);
if (!room) return null;
const selectedItem = selected?.includes(roomId);
diff --git a/src/app/features/bug-report/BugReportModal.tsx b/src/app/features/bug-report/BugReportModal.tsx
index 168d7b972..ee7d263bd 100644
--- a/src/app/features/bug-report/BugReportModal.tsx
+++ b/src/app/features/bug-report/BugReportModal.tsx
@@ -237,7 +237,10 @@ function BugReportModal() {
Report an Issue
@@ -248,7 +251,10 @@ function BugReportModal() {
@@ -449,7 +455,10 @@ function BugReportModal() {
as="label"
gap="200"
alignItems="Center"
- style={{ cursor: 'pointer', paddingLeft: config.space.S400 }}
+ style={{
+ cursor: 'pointer',
+ paddingLeft: config.space.S400,
+ }}
>
{Array.from(stateKeyToEvents.keys())
- .sort()
+ .toSorted()
.map((stateKey) => (
{Array.from(accountData.keys())
- .sort()
+ .toSorted()
.map((type) => (