@ai-matrx/meet 0.11.36 → 0.11.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -243,6 +243,19 @@ function normalizeDeviceError(error, operation) {
243
243
  }
244
244
  }
245
245
 
246
+ // src/core/leave.ts
247
+ var DEFAULT_LEAVE_POLICY = { hostLeavePrompt: "leave_or_end", endConfirm: false };
248
+ function leaveChoices(args) {
249
+ if (args.role !== "host") return ["leave"];
250
+ switch (args.policy.hostLeavePrompt) {
251
+ case "must_assign_or_end":
252
+ return args.othersPresent ? ["assign_and_leave", "end_for_all"] : ["leave", "end_for_all"];
253
+ case "leave_only":
254
+ case "leave_or_end":
255
+ return ["leave", "end_for_all"];
256
+ }
257
+ }
258
+
246
259
  // src/core/tokens.ts
247
260
  var MEET_ROUTES = {
248
261
  token: "/api/v1/meet/token",
@@ -1219,16 +1232,20 @@ function useRoom() {
1219
1232
  async () => requireEngine(engine, "toggleCamera").setCameraEnabled(!(local?.cameraEnabled ?? false)),
1220
1233
  [engine, local]
1221
1234
  ),
1222
- toggleScreenShare: (0, import_react5.useCallback)(
1223
- async () => requireEngine(engine, "toggleScreenShare").setScreenShareEnabled(
1224
- !(local?.screenSharing ?? false)
1225
- ),
1226
- [engine, local]
1227
- ),
1228
- toggleHand: (0, import_react5.useCallback)(
1229
- async () => requireEngine(engine, "toggleHand").raiseHand(!(local?.handRaised ?? false)),
1230
- [engine, local]
1231
- ),
1235
+ toggleScreenShare: (0, import_react5.useCallback)(async () => {
1236
+ const on = !(local?.screenSharing ?? false);
1237
+ await requireEngine(engine, "toggleScreenShare").setScreenShareEnabled(on);
1238
+ const sharing = host?.store.snapshot().participants.find((p) => p.isLocal)?.screenSharing ?? false;
1239
+ if (host !== null && sharing === on) {
1240
+ await host.inRoom.moderate({ action: "present", on }).catch(() => void 0);
1241
+ }
1242
+ }, [engine, host, local]),
1243
+ // S8: a hand is SERVER state (`/moderate raise_hand · lower_hand`, server time), replicated
1244
+ // back as the `matrx.hand` attribute — no client sets its own hand on the wire.
1245
+ toggleHand: (0, import_react5.useCallback)(async () => {
1246
+ if (host === null) throw noRuntime("toggleHand");
1247
+ await host.inRoom.moderate({ action: local?.handRaised === true ? "lower_hand" : "raise_hand" });
1248
+ }, [host, local]),
1232
1249
  react: (0, import_react5.useCallback)(
1233
1250
  async (emoji) => requireEngine(engine, "react").react(emoji),
1234
1251
  [engine]
@@ -1357,6 +1374,31 @@ function useWaiting() {
1357
1374
  askAgain: (0, import_react5.useCallback)(async () => requireSession(session, "askAgain").askAgain(), [session])
1358
1375
  };
1359
1376
  }
1377
+ function useLeave() {
1378
+ const host = useMeetHost();
1379
+ const snapshot = useMeetSnapshot();
1380
+ const session = host?.meetings ?? null;
1381
+ const engine = host?.engine ?? null;
1382
+ const policy = snapshot?.leavePolicy ?? DEFAULT_LEAVE_POLICY;
1383
+ const participants = snapshot?.participants ?? [];
1384
+ const me = participants.find((p) => p.isLocal);
1385
+ const candidates = participants.filter((p) => !p.isLocal && !p.isAgent && p.role !== "viewer");
1386
+ const choices = leaveChoices({ policy, role: me?.role ?? null, othersPresent: candidates.length > 0 });
1387
+ return {
1388
+ choices,
1389
+ policy,
1390
+ candidates,
1391
+ leave: (0, import_react5.useCallback)(async () => requireEngine(engine, "leave").leave(), [engine]),
1392
+ endForAll: (0, import_react5.useCallback)(async () => requireSession(session, "endForAll").hostLeave("end_for_all"), [session]),
1393
+ assignAndLeave: (0, import_react5.useCallback)(
1394
+ async (person) => {
1395
+ await requireSession(session, "assignAndLeave").hostLeave({ assignTo: String(person.identity) });
1396
+ await requireEngine(engine, "leave").leave();
1397
+ },
1398
+ [session, engine]
1399
+ )
1400
+ };
1401
+ }
1360
1402
  function useRecording() {
1361
1403
  const host = useMeetHost();
1362
1404
  const snapshot = useMeetSnapshot();
@@ -3521,19 +3563,75 @@ function ControlBar({ onLeave }) {
3521
3563
  ] }) : null
3522
3564
  ] }) }) : null
3523
3565
  ] }),
3524
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3525
- ControlButton,
3566
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LeaveControl, { onLeave })
3567
+ ] })
3568
+ ] });
3569
+ }
3570
+ var LEAVE_WORDS = {
3571
+ leave_or_end: { leave: "Leave call", assign_and_leave: "Assign a new host", end_for_all: "End call for everyone" },
3572
+ must_assign_or_end: { leave: "Leave meeting", assign_and_leave: "Assign a new host", end_for_all: "End meeting for all" },
3573
+ leave_only: { leave: "Leave", assign_and_leave: "Assign a new host", end_for_all: "End meeting" }
3574
+ };
3575
+ function LeaveControl({ onLeave }) {
3576
+ const leave = useLeave();
3577
+ const [open, setOpen] = (0, import_react10.useState)("none");
3578
+ const [failure, setFailure] = (0, import_react10.useState)(null);
3579
+ const words = LEAVE_WORDS[leave.policy.hostLeavePrompt];
3580
+ const run = (work, leaving) => {
3581
+ setFailure(null);
3582
+ void work().then(() => {
3583
+ setOpen("none");
3584
+ if (leaving) onLeave?.();
3585
+ }).catch((error) => setFailure(error instanceof Error ? error.message : String(error)));
3586
+ };
3587
+ const leaveNow = () => run(leave.leave, true);
3588
+ const endNow = () => run(leave.endForAll, false);
3589
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "mx-meet__anchor", children: [
3590
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3591
+ ControlButton,
3592
+ {
3593
+ label: "Leave",
3594
+ danger: true,
3595
+ active: open !== "none",
3596
+ onClick: () => {
3597
+ if (leave.choices.length === 1 && leave.choices[0] === "leave") leaveNow();
3598
+ else setOpen(open === "none" ? "menu" : "none");
3599
+ },
3600
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PhoneOffIcon, {})
3601
+ }
3602
+ ),
3603
+ open !== "none" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Popover, { label: open === "assign" ? words.assign_and_leave : "Leave", onClose: () => setOpen("none"), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__menu", "data-meet-leave-menu": leave.policy.hostLeavePrompt, children: [
3604
+ open === "menu" ? leave.choices.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3605
+ "button",
3526
3606
  {
3527
- label: "Leave",
3528
- danger: true,
3607
+ type: "button",
3608
+ className: choice === "end_for_all" ? "mx-meet__menu-item mx-meet__menu-item--danger" : "mx-meet__menu-item",
3529
3609
  onClick: () => {
3530
- void room.leave();
3531
- onLeave?.();
3610
+ if (choice === "leave") leaveNow();
3611
+ else if (choice === "assign_and_leave") setOpen("assign");
3612
+ else if (leave.policy.endConfirm) setOpen("confirm");
3613
+ else endNow();
3532
3614
  },
3533
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PhoneOffIcon, {})
3534
- }
3535
- )
3536
- ] })
3615
+ children: words[choice]
3616
+ },
3617
+ choice
3618
+ )) : null,
3619
+ open === "assign" ? leave.candidates.map((person) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3620
+ "button",
3621
+ {
3622
+ type: "button",
3623
+ className: "mx-meet__menu-item",
3624
+ onClick: () => run(() => leave.assignAndLeave(person), true),
3625
+ children: person.displayName
3626
+ },
3627
+ String(person.identity)
3628
+ )) : null,
3629
+ open === "confirm" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3630
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__menu-item mx-meet__menu-item--danger", onClick: endNow, children: words.end_for_all }),
3631
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__menu-item", onClick: () => setOpen("menu"), children: "Cancel" })
3632
+ ] }) : null,
3633
+ failure !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__menu-note", role: "alert", children: failure }) : null
3634
+ ] }) }) : null
3537
3635
  ] });
3538
3636
  }
3539
3637
  function useUnreadChat(open) {