ux: reply null state, location error feedback, retry send, reaction keyboard nav
CI / Build & Quality Checks (push) Successful in 10m17s
CI / Build & Quality Checks (push) Successful in 10m17s
- Reply: distinguish loading (placeholder) from not-found (null) — show "Original message not available" instead of a stuck loading bar - RoomInput: geolocation errors now surface inline (denied / timed out / unsupported); location button shows Spinner during fetch and is disabled - Message menu: Retry Send + Cancel Message items appear when a message is in NOT_SENT or CANCELLED state, calling mx.resendEvent / cancelPendingEvent - ReactionViewer: sidebar gains role=listbox / role=option and ArrowUp/Down keyboard navigation between reactions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
||||
OverlayCenter,
|
||||
PopOut,
|
||||
Scroll,
|
||||
Spinner,
|
||||
Text,
|
||||
config,
|
||||
toRem,
|
||||
@@ -183,8 +184,13 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
|
||||
const [toolbar, setToolbar] = useSetting(settingsAtom, 'editorToolbar');
|
||||
const [locating, setLocating] = React.useState(false);
|
||||
const [locationError, setLocationError] = React.useState<string | null>(null);
|
||||
const handleShareLocation = () => {
|
||||
if (!navigator.geolocation) return;
|
||||
if (!navigator.geolocation) {
|
||||
setLocationError('Geolocation not supported.');
|
||||
setTimeout(() => setLocationError(null), 4000);
|
||||
return;
|
||||
}
|
||||
setLocating(true);
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => {
|
||||
@@ -197,7 +203,17 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
geo_uri: geoUri,
|
||||
} as any);
|
||||
},
|
||||
() => setLocating(false),
|
||||
(err) => {
|
||||
setLocating(false);
|
||||
const msg =
|
||||
err.code === 1
|
||||
? 'Location access denied.'
|
||||
: err.code === 3
|
||||
? 'Location timed out.'
|
||||
: 'Failed to get location.';
|
||||
setLocationError(msg);
|
||||
setTimeout(() => setLocationError(null), 4000);
|
||||
},
|
||||
{ timeout: 10000 },
|
||||
);
|
||||
};
|
||||
@@ -858,8 +874,22 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
{gifError}
|
||||
</Text>
|
||||
)}
|
||||
{locationError && (
|
||||
<Text
|
||||
size="T200"
|
||||
style={{
|
||||
color: 'var(--tc-danger-normal)',
|
||||
padding: '2px 6px',
|
||||
alignSelf: 'center',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{locationError}
|
||||
</Text>
|
||||
)}
|
||||
<IconButton
|
||||
onClick={handleShareLocation}
|
||||
disabled={locating}
|
||||
aria-label="Share location"
|
||||
variant="SurfaceVariant"
|
||||
size="300"
|
||||
@@ -867,17 +897,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
title="Share location"
|
||||
>
|
||||
{locating ? (
|
||||
<Text
|
||||
size="T200"
|
||||
style={{
|
||||
fontWeight: 800,
|
||||
fontSize: '10px',
|
||||
letterSpacing: '0.04em',
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
...
|
||||
</Text>
|
||||
<Spinner variant="Secondary" size="100" />
|
||||
) : (
|
||||
<Icon src={Icons.SpaceGlobe} size="100" />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user