fix: comprehensive P0 quality pass — audit findings resolved

- ReportRoomModal: use mx.reportRoom() SDK method, fix undefined CSS vars
  (--mx-surface/border → folds color tokens), add role/aria-modal/aria-labelledby,
  accessible select/input labels, per-error-code messages, auto-close on success
- About.tsx: clickable matrix_id + email_address links (Text as="a"), AbortController
  cleanup, runtime JSON type guard, loading state, role display for all role values,
  remove classList theming hack, use mx.getHomeserverUrl()
- RoomViewHeader: useLocalRoomName for header title, useReportRoomSupported gate,
  hide Invite/Settings/Report for server notice rooms, isCreator guard on Report,
  FocusTrap returnFocusOnDeactivate on topic overlay, Server Notice chip tooltip
- RoomInput: replace raw <div> with folds <Box> for server notice read-only message
- EditHistoryModal: isRawEditEvent type guard, handle next_batch truncation,
  getVersionBody handles formatted_body (strips HTML for text display),
  role/aria-modal/aria-labelledby accessibility, guard for undefined eventId,
  use config.space tokens (remove var(--mx-spacing-*) strings)
- RoomNavItem: remove duplicate getExistingContent (use exported getLocalRoomNamesContent),
  maxLength={255} on rename input, fix FocusTrap nesting (renameDialog state moved to
  RoomNavItem_, RenameRoomDialog rendered outside menu, menu closes before dialog opens),
  pencil icon opacity via config.opacity.P300
- useRoomMeta: export getLocalRoomNamesContent for reuse
- RoomIntro: useLocalRoomName, formatted topic viewer with Overlay/FocusTrap/RoomTopicViewer
- CallRoomName: useLocalRoomName for consistent rename display in call overlay
- General.tsx: fix #980000/#FF6B00 hardcoded hex → color tokens/CSS vars, URL Preview
  capitalization, improved encrypted preview warning text + Warning chip, add
  description to plain urlPreview setting
- sanitize.ts: fix hex color regex to support 3/4/6/8 digit hex (CSS4 #RGBA, #RRGGBBAA)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 21:30:27 -04:00
parent 3db87db03f
commit 16dddcb9f0
11 changed files with 363 additions and 213 deletions
+42 -21
View File
@@ -1,4 +1,4 @@
import React, { FormEventHandler, useCallback, useState } from 'react';
import React, { FormEventHandler, useCallback, useEffect, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import {
Box,
@@ -16,7 +16,6 @@ import {
color,
Spinner,
} from 'folds';
import { Method } from 'matrix-js-sdk';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { stopPropagation } from '../../utils/keyboard';
@@ -42,17 +41,20 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
const [reportState, submitReport] = useAsyncCallback(
useCallback(
async (reason: string) => {
await mx.http.authedRequest(
Method.Post,
`/rooms/${encodeURIComponent(roomId)}/report`,
undefined,
{ reason },
);
await mx.reportRoom(roomId, reason);
},
[mx, roomId],
),
);
useEffect(() => {
if (reportState.status === AsyncStatus.Success) {
const timer = setTimeout(onClose, 1500);
return () => clearTimeout(timer);
}
return undefined;
}, [reportState.status, onClose]);
const handleSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
evt.preventDefault();
if (reportState.status === AsyncStatus.Loading || reportState.status === AsyncStatus.Success) {
@@ -61,12 +63,20 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
const target = evt.target as HTMLFormElement;
const reasonInput = target.elements.namedItem('reasonInput') as HTMLInputElement | null;
const reasonText = reasonInput?.value.trim() ?? '';
const fullReason = reasonText
? `[${CATEGORY_LABELS[category]}] ${reasonText}`
: `[${CATEGORY_LABELS[category]}]`;
const fullReason = `[${CATEGORY_LABELS[category]}] ${reasonText}`;
submitReport(fullReason);
};
const errcode = (reportState.status === AsyncStatus.Error
? (reportState.error as { errcode?: string })?.errcode
: undefined);
const errorMsg =
errcode === 'M_LIMIT_EXCEEDED'
? 'You are being rate limited. Please wait before reporting again.'
: errcode === 'M_FORBIDDEN'
? 'You cannot report this room.'
: 'Failed to submit report. Please try again.';
return (
<Overlay open backdrop={<OverlayBackdrop />}>
<OverlayCenter>
@@ -80,12 +90,15 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
>
<Box
as="form"
role="dialog"
aria-modal="true"
aria-labelledby="report-room-dialog-title"
onSubmit={handleSubmit}
direction="Column"
style={{
background: 'var(--mx-surface)',
background: color.Surface.Container,
borderRadius: config.radii.R400,
boxShadow: '0 8px 32px rgba(0,0,0,0.55)',
boxShadow: color.Other.Shadow,
width: '100%',
maxWidth: 420,
overflow: 'hidden',
@@ -100,7 +113,7 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
size="500"
>
<Box grow="Yes">
<Text size="H4">Report Room</Text>
<Text id="report-room-dialog-title" size="H4">Report Room</Text>
</Box>
<IconButton size="300" onClick={onClose} radii="300" aria-label="Close">
<Icon src={Icons.Cross} />
@@ -113,9 +126,11 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
</Text>
<Box direction="Column" gap="100">
<Text size="L400">Category</Text>
<Text as="label" htmlFor="report-category" size="L400">Category</Text>
<Box
as="select"
id="report-category"
aria-label="Report category"
value={category}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
setCategory(e.target.value as ReportCategory)
@@ -123,9 +138,9 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
style={{
padding: `${config.space.S200} ${config.space.S300}`,
borderRadius: config.radii.R300,
border: '1px solid var(--mx-border)',
background: 'var(--mx-bg-surface)',
color: 'var(--mx-c-surface-on)',
border: `1px solid ${color.Surface.ContainerLine}`,
background: color.Surface.Container,
color: color.Surface.OnContainer,
fontSize: 'inherit',
fontFamily: 'inherit',
width: '100%',
@@ -140,11 +155,17 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
</Box>
<Box direction="Column" gap="100">
<Text size="L400">Reason</Text>
<Input name="reasonInput" variant="Background" required />
<Text as="label" htmlFor="report-reason-input" size="L400">Reason</Text>
<Input
id="report-reason-input"
name="reasonInput"
aria-label="Reason for report"
variant="Background"
required
/>
{reportState.status === AsyncStatus.Error && (
<Text style={{ color: color.Critical.Main }} size="T300">
Failed to submit report. Please try again.
{errorMsg}
</Text>
)}
{reportState.status === AsyncStatus.Success && (