feat(a11y,perf): comprehensive icon button labels, toolbar a11y, timeline binary search
A11y C-1: aria-label on 30+ remaining icon-only buttons across:
- settings panels (close, reset, info, expand, remove, undo)
- editor toolbar (bold, italic, underline, strike, code, spoiler,
blockquote, code block, ordered/unordered list, headings 1-3)
- auth stages (cancel buttons in SSO, Password stages)
- device verification (cancel buttons)
- password input (show/hide toggle with dynamic label)
- event readers, account data editor close buttons
- global emoji packs (add/remove buttons)
Perf-5: Replace O(N×T) getTimelineAndBaseIndex scan with precomputed binary
search (timelineSegments useMemo) — O(log T) per visible message render
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -546,6 +546,17 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
||||
const timelineRef = React.useRef(timeline);
|
||||
timelineRef.current = timeline;
|
||||
const eventsLength = getTimelinesEventsCount(timeline.linkedTimelines);
|
||||
|
||||
// Perf-5: precompute base offsets once per linkedTimelines change instead of O(N×T) scan
|
||||
const timelineSegments = useMemo<Array<[number, number, EventTimeline]>>(() => {
|
||||
let base = 0;
|
||||
return timeline.linkedTimelines.map((t) => {
|
||||
const len = t.getEvents().length;
|
||||
const seg: [number, number, EventTimeline] = [base, len, t];
|
||||
base += len;
|
||||
return seg;
|
||||
});
|
||||
}, [timeline.linkedTimelines]);
|
||||
const liveTimelineLinked =
|
||||
timeline.linkedTimelines[timeline.linkedTimelines.length - 1] === getLiveTimeline(room);
|
||||
const canPaginateBack =
|
||||
@@ -1809,7 +1820,20 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
||||
let newDivider = false;
|
||||
let dayDivider = false;
|
||||
const eventRenderer = (item: number) => {
|
||||
const [eventTimeline, baseIndex] = getTimelineAndBaseIndex(timeline.linkedTimelines, item);
|
||||
// Perf-5: O(T) → O(log T) via precomputed segments
|
||||
let eventTimeline: EventTimeline | undefined;
|
||||
let baseIndex = 0;
|
||||
{
|
||||
let lo = 0;
|
||||
let hi = timelineSegments.length - 1;
|
||||
while (lo <= hi) {
|
||||
const mid = (lo + hi) >>> 1;
|
||||
const [base, len] = timelineSegments[mid];
|
||||
if (item < base) { hi = mid - 1; }
|
||||
else if (item >= base + len) { lo = mid + 1; }
|
||||
else { eventTimeline = timelineSegments[mid][2]; baseIndex = base; break; }
|
||||
}
|
||||
}
|
||||
if (!eventTimeline) return null;
|
||||
const timelineSet = eventTimeline?.getTimelineSet();
|
||||
const mEvent = getTimelineEvent(eventTimeline, getTimelineRelativeIndex(item, baseIndex));
|
||||
|
||||
Reference in New Issue
Block a user