diff --git a/src/app/components/presence/PresenceRingAvatar.tsx b/src/app/components/presence/PresenceRingAvatar.tsx
index f18a90406..3fde97214 100644
--- a/src/app/components/presence/PresenceRingAvatar.tsx
+++ b/src/app/components/presence/PresenceRingAvatar.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import React, { CSSProperties } from 'react';
import { color } from 'folds';
import { Presence, useUserPresence } from '../../hooks/useUserPresence';
@@ -12,7 +12,7 @@ function presenceRingColor(presence: Presence | undefined, status?: string): str
type PresenceRingAvatarProps = {
userId: string;
- children: ReactNode;
+ children: React.ReactElement<{ style?: CSSProperties }>;
};
export function PresenceRingAvatar({ userId, children }: PresenceRingAvatarProps) {
@@ -21,16 +21,14 @@ export function PresenceRingAvatar({ userId, children }: PresenceRingAvatarProps
if (!ringColor) return <>{children}>;
- return (
-
- {children}
-
- );
+ // Apply outline directly to the child so it follows the child's actual border-radius.
+ // outline follows border-radius in Chrome 94+, Firefox 88+, Safari 16.4+.
+ // This avoids the mismatch of a circular wrapper around a rounded-square avatar.
+ return React.cloneElement(children, {
+ style: {
+ ...children.props.style,
+ outline: `2px solid ${ringColor}`,
+ outlineOffset: '2px',
+ },
+ });
}
diff --git a/src/app/features/room/message/EditHistoryModal.tsx b/src/app/features/room/message/EditHistoryModal.tsx
index 53daeb892..562ea61ce 100644
--- a/src/app/features/room/message/EditHistoryModal.tsx
+++ b/src/app/features/room/message/EditHistoryModal.tsx
@@ -72,9 +72,14 @@ function renderContent(source: Record): ReactNode {
}
function getOriginalContent(evt: MatrixEvent): ReactNode {
- // mEvent.getContent() returns the SDK-applied post-edit content.
- // Read the raw server event to get the actual original pre-edit text.
- const raw = (evt.event as { content?: Record }).content ?? {};
+ // For E2EE events, evt.event.content is the ciphertext (no body field) — "(no text)" bug.
+ // getClearContent() returns the decrypted original content, bypassing _replacingEvent,
+ // so it gives us the pre-edit body even when the SDK has an edit applied.
+ // For unencrypted events, getClearContent() returns null, so we fall back to event.content.
+ const raw =
+ (evt.getClearContent() as Record | null) ??
+ (evt.event as { content?: Record }).content ??
+ {};
return renderContent(raw);
}