feat(lotus): layout, settings and reactions over the widget API (cinny #43)

The Lotus host drove these by clicking EC's hidden controls in our DOM and
read screenshare/layout state from it, which only works while the frame is
same-origin and breaks whenever a data-testid changes. New actions:

- toWidget io.lotus.set_layout { layout: "grid" | "spotlight" } → the layout
  switch view model's setLayout.
- toWidget io.lotus.open_settings { open?: boolean } → setSettingsOpen
  (toggle when `open` is omitted).
- toWidget io.lotus.toggle_reactions → a window event the reactions button
  listens for.
- fromWidget io.lotus.controls_state { screensharing, layout } on change; its
  arrival tells the host the fork supports the actions above.

Screensharing stays host-driven for now: getDisplayMedia needs the user's
click to reach this frame (Capability Delegation), which a widget message
doesn't carry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
Lotus CI
2026-09-24 22:16:24 -04:00
co-authored by Claude Opus 5.5
parent d8880daca5
commit 6beebd3ea7
6 changed files with 180 additions and 0 deletions
+21
View File
@@ -62,6 +62,24 @@ export enum LotusWidgetActions {
* else in the call (#39). Each fires at most once per share.
*/
ScreenshareNotice = "io.lotus.screenshare_notice",
/**
* toWidget: switch the call layout `{ layout: "grid" | "spotlight" }`
* (cinny #43 — replaces the host clicking EC's hidden layout radio).
*/
SetLayout = "io.lotus.set_layout",
/**
* toWidget: open EC's settings modal, or close it with `{ open: false }`;
* omit `open` to toggle (cinny #43).
*/
OpenSettings = "io.lotus.open_settings",
/** toWidget: toggle the reactions / raise-hand menu (cinny #43). */
ToggleReactions = "io.lotus.toggle_reactions",
/**
* fromWidget: `{ screensharing: boolean, layout: "grid" | "spotlight" | null }`
* whenever either changes (cinny #43), so the host stops reading EC's DOM for
* them. Its arrival also tells the host this fork supports the actions above.
*/
ControlsState = "io.lotus.controls_state",
}
/** toWidget Lotus actions that must be allow-listed in `initializeWidget`. */
@@ -72,4 +90,7 @@ export const LOTUS_TO_WIDGET_ACTIONS: LotusWidgetActions[] = [
LotusWidgetActions.Decorations,
LotusWidgetActions.SetDeafen,
LotusWidgetActions.SetAudioOutput,
LotusWidgetActions.SetLayout,
LotusWidgetActions.OpenSettings,
LotusWidgetActions.ToggleReactions,
];