43f4ceb45d
Phase C.1 of the protocol-gaps roadmap, gate-green (693 tests). Generalizes the Element Call widget host into a general room-widget feature: - StateEvent.Widget + widgetsPanelAtom + useRoomWidgets (WidgetParser). - RoomWidgetView: sandboxed-iframe host via ClientWidgetApi with a conservative GeneralWidgetDriver (approves only benign display caps — no room-event send/read/to-device). Blocks same-origin widget URLs (sandbox breakout guard). - WidgetsPanel: list / open / add / remove, PL-gated on im.vector.modular.widgets, https + non-same-origin URL validation. Mounted like the media gallery (header toggle + 3-way content-panel exclusivity + mobile full-screen overlay). - Tested URL/capability/id helpers. Requires the prod CSP frame-src widening (matrix repo) for external widgets. v1 cuts (capability consent prompt, Jitsi/sticker types, user widgets) noted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
22 lines
848 B
TypeScript
22 lines
848 B
TypeScript
import { Room } from 'matrix-js-sdk';
|
|
import { useMemo } from 'react';
|
|
import { Widget, WidgetParser, IStateEvent } from 'matrix-widget-api';
|
|
import { StateEvent } from '../../../../types/matrix/room';
|
|
import { useRoomState } from '../../../hooks/useRoomState';
|
|
|
|
/**
|
|
* All valid `im.vector.modular.widgets` room widgets, reactive on room state.
|
|
* `WidgetParser` drops empty/removed (`{}`) and malformed entries.
|
|
*/
|
|
export const useRoomWidgets = (room: Room): Widget[] => {
|
|
const state = useRoomState(room);
|
|
return useMemo(() => {
|
|
const widgetEvents = state.get(StateEvent.Widget);
|
|
if (!widgetEvents) return [];
|
|
const stateEvents = Array.from(widgetEvents.values()).map(
|
|
(event) => event.getEffectiveEvent() as unknown as IStateEvent,
|
|
);
|
|
return WidgetParser.parseWidgetsFromRoomState(stateEvents);
|
|
}, [state]);
|
|
};
|