PTT fixes, TDS expansions, performance hooks, state event renderers

PTT fixes (BUG-7/8/9):
- BUG-7: Fix isEditable to use ownerDocument.body (works in EC iframe context)
- BUG-8: Release mic if callEmbed changes during active PTT (cleanup fn)
- BUG-9: Wire iframe blur/focus listeners for stuck-mic prevention

PiP bug fix (BUG-11):
- Track prevPipMode ref so position only resets when first entering pip mode,
  not on every callVisible change (user drag position preserved)

GIF improvements (BUG-15):
- Show user-visible error text in toolbar on GIF send failure
- Also surface size-limit rejection with a 4-second auto-clearing message

Performance:
- useInterval: replace useMemo with useEffect for setInterval (React StrictMode safe)
- usePan: add unmount cleanup effect to remove document mousemove/mouseup listeners

Feature: timeline state event renderers (low effort, high value):
- Added renderers for RoomEncryption, RoomJoinRules, RoomGuestAccess, RoomCanonicalAlias
- These were silently falling through to the hidden-events fallback

TDS (Lotus Terminal Design System):
- Fix: correct 8 escaped template literals in GIF picker light-mode block
- Add data-emoji-board attribute to EmojiBoardLayout for stable CSS targeting
- Add Tooltip panel styles (dark + light mode)
- Add Switch toggle styles (dark + light mode)
- Add Spinner stroke colors (dark + light mode)
- Add EmojiBoard panel styles (dark + light mode)
- Add PopOut/Menu/floating panel styles (dark + light mode)
This commit is contained in:
Lotus Bot
2026-05-19 16:45:02 -04:00
parent 63e1085984
commit 2b2619145c
8 changed files with 241 additions and 38 deletions
+5 -18
View File
@@ -1,24 +1,11 @@
import { useEffect, useMemo } from 'react';
import { useEffect, useRef } from 'react';
export type IntervalCallback = () => void;
/**
* @param callback interval callback.
* @param ms interval time in milliseconds. negative value will stop the interval.
* @returns interval id or undefined if not running.
*/
export const useInterval = (callback: IntervalCallback, ms: number): number | undefined => {
const id = useMemo(() => {
export const useInterval = (callback: IntervalCallback, ms: number): void => {
useEffect(() => {
if (ms < 0) return undefined;
return window.setInterval(callback, ms);
const id = window.setInterval(callback, ms);
return () => window.clearInterval(id);
}, [callback, ms]);
useEffect(
() => () => {
window.clearInterval(id);
},
[id]
);
return id;
};
+7
View File
@@ -54,6 +54,13 @@ export const usePan = (active: boolean) => {
if (!active) setPan(INITIAL_PAN);
}, [active]);
// Clean up document listeners if component unmounts during an active drag
useEffect(() => () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return {
pan,
cursor,