@arbidocs/blocks 0.4.110 → 0.4.111

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.
Files changed (94) hide show
  1. package/dist/{NativeDocxEditor-WODZAURG.cjs → NativeDocxEditor-AQKRZBIU.cjs} +7 -7
  2. package/dist/{NativeDocxEditor-WODZAURG.cjs.map → NativeDocxEditor-AQKRZBIU.cjs.map} +1 -1
  3. package/dist/{NativeDocxEditor-4PY4YZYC.js → NativeDocxEditor-IN2HEO5I.js} +3 -3
  4. package/dist/{NativeDocxEditor-4PY4YZYC.js.map → NativeDocxEditor-IN2HEO5I.js.map} +1 -1
  5. package/dist/agents/index.cjs +207 -207
  6. package/dist/agents/index.js +2 -2
  7. package/dist/calendar/EventEditor.d.ts +1 -1
  8. package/dist/calendar/draft.d.ts +7 -1
  9. package/dist/calendar/index.cjs +58 -10
  10. package/dist/calendar/index.cjs.map +1 -1
  11. package/dist/calendar/index.d.ts +1 -1
  12. package/dist/calendar/index.js +56 -11
  13. package/dist/calendar/index.js.map +1 -1
  14. package/dist/calendar/types.d.ts +20 -0
  15. package/dist/calls/CallSidePanel.d.ts +16 -1
  16. package/dist/calls/ControlBar.d.ts +25 -3
  17. package/dist/calls/PreJoin.d.ts +6 -2
  18. package/dist/calls/cards.d.ts +6 -2
  19. package/dist/calls/index.cjs +1078 -47
  20. package/dist/calls/index.cjs.map +1 -1
  21. package/dist/calls/index.d.ts +4 -3
  22. package/dist/calls/index.js +1067 -51
  23. package/dist/calls/index.js.map +1 -1
  24. package/dist/calls/panels.d.ts +11 -0
  25. package/dist/calls/webinar/ChatPermissionSetting.d.ts +18 -0
  26. package/dist/calls/webinar/OnStageCheck.d.ts +23 -0
  27. package/dist/calls/webinar/QAPanel.d.ts +56 -0
  28. package/dist/calls/webinar/RaiseHandButton.d.ts +14 -0
  29. package/dist/calls/webinar/WebinarAudiencePanel.d.ts +23 -0
  30. package/dist/calls/webinar/WebinarViewer.d.ts +39 -0
  31. package/dist/calls/webinar/WebinarWaiting.d.ts +19 -0
  32. package/dist/calls/webinar/hooks.d.ts +13 -0
  33. package/dist/calls/webinar/index.d.ts +14 -0
  34. package/dist/calls/webinar/live.d.ts +43 -0
  35. package/dist/calls/webinar/types.d.ts +49 -0
  36. package/dist/{chunk-GKDWQLVU.js → chunk-2C7TCVQZ.js} +172 -121
  37. package/dist/chunk-2C7TCVQZ.js.map +1 -0
  38. package/dist/{chunk-54WBIVHV.cjs → chunk-2WO5L7YT.cjs} +5 -5
  39. package/dist/{chunk-54WBIVHV.cjs.map → chunk-2WO5L7YT.cjs.map} +1 -1
  40. package/dist/{chunk-A35KT2II.js → chunk-6Z7DLJU2.js} +3 -3
  41. package/dist/{chunk-A35KT2II.js.map → chunk-6Z7DLJU2.js.map} +1 -1
  42. package/dist/{chunk-VZKBI2KJ.cjs → chunk-FXUQZFAN.cjs} +3 -3
  43. package/dist/{chunk-VZKBI2KJ.cjs.map → chunk-FXUQZFAN.cjs.map} +1 -1
  44. package/dist/{chunk-SQNAJPNR.js → chunk-GFYGYME3.js} +3 -3
  45. package/dist/{chunk-SQNAJPNR.js.map → chunk-GFYGYME3.js.map} +1 -1
  46. package/dist/chunk-GICUGQNN.cjs +76 -0
  47. package/dist/chunk-GICUGQNN.cjs.map +1 -0
  48. package/dist/chunk-JJLMCV3T.js +73 -0
  49. package/dist/chunk-JJLMCV3T.js.map +1 -0
  50. package/dist/{chunk-W7ZDBPJ3.cjs → chunk-OR4CO743.cjs} +3 -3
  51. package/dist/{chunk-W7ZDBPJ3.cjs.map → chunk-OR4CO743.cjs.map} +1 -1
  52. package/dist/{chunk-PEHLUB52.js → chunk-Q6B77ZWZ.js} +3 -3
  53. package/dist/{chunk-PEHLUB52.js.map → chunk-Q6B77ZWZ.js.map} +1 -1
  54. package/dist/{chunk-ELDUWTRR.cjs → chunk-TF47ATYS.cjs} +4 -4
  55. package/dist/{chunk-ELDUWTRR.cjs.map → chunk-TF47ATYS.cjs.map} +1 -1
  56. package/dist/{chunk-JB32KYAH.js → chunk-WTM65ZNG.js} +3 -3
  57. package/dist/{chunk-JB32KYAH.js.map → chunk-WTM65ZNG.js.map} +1 -1
  58. package/dist/{chunk-2NIL2ASF.cjs → chunk-XIGWUDOD.cjs} +170 -119
  59. package/dist/chunk-XIGWUDOD.cjs.map +1 -0
  60. package/dist/collaboration/index.cjs +1 -1
  61. package/dist/collaboration/index.js +1 -1
  62. package/dist/connect/docx.cjs +6 -6
  63. package/dist/connect/docx.js +4 -4
  64. package/dist/connect/index.cjs +31 -31
  65. package/dist/connect/index.js +7 -7
  66. package/dist/docx/AgentUndo.d.ts +4 -0
  67. package/dist/docx/index.cjs +46 -46
  68. package/dist/docx/index.js +3 -3
  69. package/dist/files/index.cjs +1 -1
  70. package/dist/files/index.js +1 -1
  71. package/dist/index.cjs +332 -332
  72. package/dist/index.js +6 -6
  73. package/dist/settings/index.cjs +48 -102
  74. package/dist/settings/index.cjs.map +1 -1
  75. package/dist/settings/index.js +10 -70
  76. package/dist/settings/index.js.map +1 -1
  77. package/dist/workflow-canvas/index.cjs +9 -9
  78. package/dist/workflow-canvas/index.js +2 -2
  79. package/node_modules/@arbidocs/coedit/dist/commands.cjs +179 -9
  80. package/node_modules/@arbidocs/coedit/dist/commands.cjs.map +1 -1
  81. package/node_modules/@arbidocs/coedit/dist/commands.d.cts +81 -1
  82. package/node_modules/@arbidocs/coedit/dist/commands.d.ts +81 -1
  83. package/node_modules/@arbidocs/coedit/dist/commands.js +173 -11
  84. package/node_modules/@arbidocs/coedit/dist/commands.js.map +1 -1
  85. package/node_modules/@arbidocs/coedit/dist/server.cjs +58 -2
  86. package/node_modules/@arbidocs/coedit/dist/server.cjs.map +1 -1
  87. package/node_modules/@arbidocs/coedit/dist/server.d.cts +29 -1
  88. package/node_modules/@arbidocs/coedit/dist/server.d.ts +29 -1
  89. package/node_modules/@arbidocs/coedit/dist/server.js +58 -3
  90. package/node_modules/@arbidocs/coedit/dist/server.js.map +1 -1
  91. package/node_modules/@arbidocs/coedit/package.json +1 -1
  92. package/package.json +4 -4
  93. package/dist/chunk-2NIL2ASF.cjs.map +0 -1
  94. package/dist/chunk-GKDWQLVU.js.map +0 -1
@@ -1,10 +1,13 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var chunkGICUGQNN_cjs = require('../chunk-GICUGQNN.cjs');
4
5
  var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
6
+ require('../chunk-ULWRNGGE.cjs');
5
7
  var chunkMWDW5UBW_cjs = require('../chunk-MWDW5UBW.cjs');
6
8
  require('../chunk-PPCATBOY.cjs');
7
9
  require('../chunk-MHVNT4J3.cjs');
10
+ var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
8
11
  require('../chunk-DES3K4SD.cjs');
9
12
  var react = require('react');
10
13
  var ui = require('@arbidocs/react/ui');
@@ -681,9 +684,11 @@ function LeaveButton({
681
684
  onLeave,
682
685
  compact = false,
683
686
  label = "Leave",
684
- title = "Leave call"
687
+ title = "Leave call",
688
+ options
685
689
  }) {
686
- return /* @__PURE__ */ jsxRuntime.jsxs(
690
+ const menu = !!options?.length;
691
+ const button = /* @__PURE__ */ jsxRuntime.jsxs(
687
692
  ui.Button,
688
693
  {
689
694
  type: "button",
@@ -692,7 +697,7 @@ function LeaveButton({
692
697
  className: ui.cn("shrink-0", !compact && "px-4"),
693
698
  "aria-label": title,
694
699
  title,
695
- onClick: onLeave,
700
+ onClick: menu ? void 0 : onLeave,
696
701
  "data-testid": "call-leave",
697
702
  children: [
698
703
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { className: "size-4", "aria-hidden": true }),
@@ -700,13 +705,34 @@ function LeaveButton({
700
705
  ]
701
706
  }
702
707
  );
708
+ if (!menu) return button;
709
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: button }),
711
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", className: "w-56", children: [
712
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onLeave, "data-testid": "call-leave-only", children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { "aria-hidden": true }),
714
+ label
715
+ ] }),
716
+ options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
717
+ ui.DropdownMenuItem,
718
+ {
719
+ onSelect: o.onSelect,
720
+ className: "text-red-text focus:text-red-text",
721
+ "data-testid": o.testId,
722
+ children: o.label
723
+ },
724
+ o.key
725
+ ))
726
+ ] })
727
+ ] });
703
728
  }
729
+ var isSection = (g) => !Array.isArray(g);
704
730
  function MoreMenu({
705
731
  details,
706
732
  groups,
707
733
  label = "More options"
708
734
  }) {
709
- const shown = groups.filter((g) => g.length > 0);
735
+ const shown = groups.filter((g) => isSection(g) || g.length > 0);
710
736
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
711
737
  /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CallControlButton, { label, tooltip: false, "data-testid": "call-more", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { "aria-hidden": true }) }) }),
712
738
  /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { side: "top", align: "end", className: "w-72", "data-testid": "call-more-menu", children: [
@@ -716,7 +742,7 @@ function MoreMenu({
716
742
  ] }),
717
743
  shown.map((group, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", children: [
718
744
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
719
- group.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
745
+ isSection(group) ? group.content : group.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
720
746
  ui.DropdownMenuItem,
721
747
  {
722
748
  onSelect: item.onSelect,
@@ -730,7 +756,7 @@ function MoreMenu({
730
756
  },
731
757
  item.key
732
758
  ))
733
- ] }, group[0].key))
759
+ ] }, isSection(group) ? group.key : group[0].key))
734
760
  ] })
735
761
  ] });
736
762
  }
@@ -908,40 +934,69 @@ function CallSidePanel({
908
934
  onClose,
909
935
  closeLabel,
910
936
  closeTestId,
937
+ tabs,
938
+ activeTab,
939
+ onTabChange,
911
940
  children,
912
941
  className,
913
942
  ...rest
914
943
  }) {
915
- return /* @__PURE__ */ jsxRuntime.jsxs(
944
+ const tabbed = !!tabs?.length;
945
+ const current = activeTab ?? tabs?.[0]?.id;
946
+ const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border pl-3 pr-1.5", children: [
947
+ tabbed ? /* @__PURE__ */ jsxRuntime.jsx(ui.TabsList, { className: "h-8 min-w-0 flex-1 justify-start overflow-x-auto bg-transparent p-0", children: tabs.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
948
+ ui.TabsTrigger,
949
+ {
950
+ value: t.id,
951
+ className: "h-8 gap-1.5 px-2.5 data-[state=active]:bg-muted data-[state=active]:text-primary data-[state=active]:shadow-none",
952
+ "data-testid": t.testId,
953
+ children: [
954
+ t.label,
955
+ t.count !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs tabular-nums text-muted-foreground", children: t.count })
956
+ ]
957
+ },
958
+ t.id
959
+ )) }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-base font-semibold text-primary", children: [
960
+ icon,
961
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title })
962
+ ] }),
963
+ actions,
964
+ /* @__PURE__ */ jsxRuntime.jsx(
965
+ ui.Button,
966
+ {
967
+ type: "button",
968
+ variant: "ghost",
969
+ size: "icon",
970
+ className: "size-8 text-muted-foreground hover:text-foreground",
971
+ "aria-label": closeLabel,
972
+ title: closeLabel,
973
+ onClick: onClose,
974
+ "data-testid": closeTestId,
975
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
976
+ }
977
+ )
978
+ ] });
979
+ return /* @__PURE__ */ jsxRuntime.jsx(
916
980
  "aside",
917
981
  {
918
982
  className: ui.cn("flex min-h-0 flex-col bg-background text-foreground", className),
919
983
  "aria-label": title,
920
984
  ...rest,
921
- children: [
922
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border pl-3 pr-1.5", children: [
923
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-base font-semibold text-primary", children: [
924
- icon,
925
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title })
926
- ] }),
927
- actions,
928
- /* @__PURE__ */ jsxRuntime.jsx(
929
- ui.Button,
930
- {
931
- type: "button",
932
- variant: "ghost",
933
- size: "icon",
934
- className: "size-8 text-muted-foreground hover:text-foreground",
935
- "aria-label": closeLabel,
936
- title: closeLabel,
937
- onClick: onClose,
938
- "data-testid": closeTestId,
939
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
940
- }
941
- )
942
- ] }),
985
+ children: tabbed ? /* @__PURE__ */ jsxRuntime.jsxs(
986
+ ui.Tabs,
987
+ {
988
+ value: current,
989
+ onValueChange: (id) => onTabChange?.(id),
990
+ className: "flex min-h-0 flex-1 flex-col",
991
+ children: [
992
+ header,
993
+ current && /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: current, className: "mt-0 flex min-h-0 flex-1 flex-col", children })
994
+ ]
995
+ }
996
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
997
+ header,
943
998
  children
944
- ]
999
+ ] })
945
1000
  }
946
1001
  );
947
1002
  }
@@ -974,6 +1029,31 @@ function VoiceMeter({
974
1029
  }
975
1030
  );
976
1031
  }
1032
+ function CallPersonLabel({
1033
+ name,
1034
+ entity,
1035
+ isLocal = false,
1036
+ youLabel = "(me)"
1037
+ }) {
1038
+ if (entity) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: entity });
1039
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1040
+ /* @__PURE__ */ jsxRuntime.jsx(
1041
+ "span",
1042
+ {
1043
+ className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary",
1044
+ "aria-hidden": true,
1045
+ children: chunkMWDW5UBW_cjs.initialsOf(name)
1046
+ }
1047
+ ),
1048
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate", children: [
1049
+ name,
1050
+ isLocal && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
1051
+ " ",
1052
+ youLabel
1053
+ ] })
1054
+ ] })
1055
+ ] });
1056
+ }
977
1057
  function PersonRow({
978
1058
  p,
979
1059
  canRemove,
@@ -1003,20 +1083,7 @@ function PersonRow({
1003
1083
  children: p.entity
1004
1084
  }
1005
1085
  )
1006
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1007
- /* @__PURE__ */ jsxRuntime.jsx(
1008
- "span",
1009
- {
1010
- className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary",
1011
- "aria-hidden": true,
1012
- children: chunkMWDW5UBW_cjs.initialsOf(p.name)
1013
- }
1014
- ),
1015
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate", children: [
1016
- p.name,
1017
- p.isLocal && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: " (me)" })
1018
- ] })
1019
- ] }),
1086
+ ) : /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: p.name, isLocal: p.isLocal }),
1020
1087
  p.speaking && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " \u2014 speaking" }),
1021
1088
  p.note && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: p.note })
1022
1089
  ] }),
@@ -1428,18 +1495,22 @@ function CallStateMessage({
1428
1495
  title,
1429
1496
  description,
1430
1497
  spinner = true,
1498
+ icon,
1431
1499
  action,
1500
+ children,
1432
1501
  testId
1433
1502
  }) {
1434
1503
  return /* @__PURE__ */ jsxRuntime.jsxs(
1435
1504
  "div",
1436
1505
  {
1437
1506
  className: "flex size-full flex-col items-center justify-center gap-3 p-6 text-center",
1507
+ role: "status",
1438
1508
  "data-testid": testId,
1439
1509
  children: [
1440
- spinner && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-6 animate-spin text-muted-foreground", "aria-hidden": true }),
1510
+ icon ?? (spinner && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-6 animate-spin text-muted-foreground", "aria-hidden": true })),
1441
1511
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold", children: title }),
1442
1512
  description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }),
1513
+ children,
1443
1514
  action
1444
1515
  ]
1445
1516
  }
@@ -1581,8 +1652,10 @@ function DeviceSelect({
1581
1652
  function PreJoin({
1582
1653
  title,
1583
1654
  heading = "Ready to join?",
1655
+ headingAs: Heading = "h2",
1584
1656
  children,
1585
1657
  joinLabel = "Join",
1658
+ cancelLabel = "Cancel",
1586
1659
  busy = false,
1587
1660
  error,
1588
1661
  onJoin,
@@ -1653,7 +1726,7 @@ function PreJoin({
1653
1726
  ] }),
1654
1727
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
1655
1728
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1656
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold", children: heading }),
1729
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "text-xl font-semibold", children: heading }),
1657
1730
  title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm text-muted-foreground", children: title })
1658
1731
  ] }),
1659
1732
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
@@ -1724,14 +1797,957 @@ function PreJoin({
1724
1797
  type: "button",
1725
1798
  variant: "outline",
1726
1799
  onClick: onCancel,
1800
+ disabled: busy,
1727
1801
  "data-testid": "call-prejoin-cancel",
1728
- children: "Cancel"
1802
+ children: cancelLabel
1729
1803
  }
1730
1804
  )
1731
1805
  ] })
1732
1806
  ] })
1733
1807
  ] }) });
1734
1808
  }
1809
+ function WebinarWaiting({
1810
+ variant,
1811
+ title,
1812
+ when,
1813
+ host,
1814
+ onLeave,
1815
+ leaveLabel = "Leave"
1816
+ }) {
1817
+ const waiting = variant === "waiting";
1818
+ return /* @__PURE__ */ jsxRuntime.jsx(
1819
+ CallStateMessage,
1820
+ {
1821
+ title: waiting ? "Starting soon" : "This webinar has ended",
1822
+ description: waiting ? "The host hasn't gone live yet. You'll join automatically when the webinar starts." : "Thanks for attending.",
1823
+ spinner: waiting,
1824
+ icon: waiting ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarCheck, { className: "size-6 text-muted-foreground", "aria-hidden": true }),
1825
+ testId: waiting ? "webinar-waiting" : "webinar-ended",
1826
+ action: onLeave && /* @__PURE__ */ jsxRuntime.jsx(
1827
+ ui.Button,
1828
+ {
1829
+ type: "button",
1830
+ variant: "outline",
1831
+ onClick: onLeave,
1832
+ "data-testid": "webinar-waiting-leave",
1833
+ children: leaveLabel
1834
+ }
1835
+ ),
1836
+ children: (title || when || host) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-w-sm flex-col items-center gap-1 text-sm", children: [
1837
+ title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", "data-testid": "webinar-waiting-title", children: title }),
1838
+ when && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", "data-testid": "webinar-waiting-when", children: when }),
1839
+ host && /* @__PURE__ */ jsxRuntime.jsxs(
1840
+ "p",
1841
+ {
1842
+ className: "flex flex-wrap items-center justify-center gap-1 text-muted-foreground",
1843
+ "data-testid": "webinar-waiting-host",
1844
+ children: [
1845
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Hosted by" }),
1846
+ host
1847
+ ]
1848
+ }
1849
+ )
1850
+ ] })
1851
+ }
1852
+ );
1853
+ }
1854
+ function usePending() {
1855
+ const [keys, setKeys] = react.useState(() => /* @__PURE__ */ new Set());
1856
+ const mounted = react.useRef(true);
1857
+ react.useEffect(() => {
1858
+ mounted.current = true;
1859
+ return () => {
1860
+ mounted.current = false;
1861
+ };
1862
+ }, []);
1863
+ const set = react.useCallback((key, on) => {
1864
+ if (!mounted.current) return;
1865
+ setKeys((prev) => {
1866
+ if (prev.has(key) === on) return prev;
1867
+ const next = new Set(prev);
1868
+ if (on) next.add(key);
1869
+ else next.delete(key);
1870
+ return next;
1871
+ });
1872
+ }, []);
1873
+ const run = react.useCallback(
1874
+ async (key, fn) => {
1875
+ let result;
1876
+ try {
1877
+ result = fn();
1878
+ } catch {
1879
+ return false;
1880
+ }
1881
+ if (!result || typeof result.then !== "function") return true;
1882
+ set(key, true);
1883
+ try {
1884
+ await result;
1885
+ return true;
1886
+ } catch {
1887
+ return false;
1888
+ } finally {
1889
+ set(key, false);
1890
+ }
1891
+ },
1892
+ [set]
1893
+ );
1894
+ const isPending = react.useCallback((key) => keys.has(key), [keys]);
1895
+ return { isPending, run };
1896
+ }
1897
+ function useNow(ms = 3e4, fixed) {
1898
+ const [now, setNow] = react.useState(() => /* @__PURE__ */ new Date());
1899
+ const ticking = !fixed;
1900
+ react.useEffect(() => {
1901
+ if (!ticking) return;
1902
+ const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), ms);
1903
+ return () => clearInterval(id);
1904
+ }, [ms, ticking]);
1905
+ return fixed ?? now;
1906
+ }
1907
+ function WebinarLiveChip({
1908
+ compact = false,
1909
+ className
1910
+ }) {
1911
+ return /* @__PURE__ */ jsxRuntime.jsx(
1912
+ CallStatusChip,
1913
+ {
1914
+ tone: "red",
1915
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-3.5 shrink-0", "aria-hidden": true }),
1916
+ label: "Live",
1917
+ compact,
1918
+ title: "Live: attendees see and hear the stage",
1919
+ role: "status",
1920
+ className,
1921
+ testId: "webinar-live-chip"
1922
+ }
1923
+ );
1924
+ }
1925
+ function WebinarLiveControl({
1926
+ live,
1927
+ onGoLive,
1928
+ onEnd,
1929
+ compact = false,
1930
+ className
1931
+ }) {
1932
+ const { isPending, run } = usePending();
1933
+ const [confirming, setConfirming] = react.useState(false);
1934
+ if (!live) {
1935
+ if (!onGoLive) return null;
1936
+ const busy = isPending("live");
1937
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1938
+ ui.Button,
1939
+ {
1940
+ type: "button",
1941
+ size: compact ? "icon" : "sm",
1942
+ className: ui.cn("h-8 shrink-0", !compact && "px-3", className),
1943
+ disabled: busy,
1944
+ "aria-label": "Go live",
1945
+ title: "Go live: let attendees see and hear the stage",
1946
+ onClick: () => void run("live", onGoLive),
1947
+ "data-testid": "webinar-go-live",
1948
+ children: [
1949
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-4", "aria-hidden": true }),
1950
+ !compact && "Go live"
1951
+ ]
1952
+ }
1953
+ );
1954
+ }
1955
+ if (!onEnd) return null;
1956
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1957
+ /* @__PURE__ */ jsxRuntime.jsxs(
1958
+ ui.Button,
1959
+ {
1960
+ type: "button",
1961
+ variant: "outline",
1962
+ size: compact ? "icon" : "default",
1963
+ className: ui.cn(
1964
+ "shrink-0 border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
1965
+ !compact && "px-4",
1966
+ className
1967
+ ),
1968
+ "aria-label": "End webinar",
1969
+ title: "End webinar for everyone",
1970
+ onClick: () => setConfirming(true),
1971
+ "data-testid": "webinar-end",
1972
+ children: [
1973
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquareX, { className: "size-4", "aria-hidden": true }),
1974
+ !compact && "End webinar"
1975
+ ]
1976
+ }
1977
+ ),
1978
+ /* @__PURE__ */ jsxRuntime.jsx(WebinarEndConfirm, { open: confirming, onOpenChange: setConfirming, onEnd })
1979
+ ] });
1980
+ }
1981
+ function WebinarEndConfirm({
1982
+ open,
1983
+ onOpenChange,
1984
+ onEnd
1985
+ }) {
1986
+ const { isPending, run } = usePending();
1987
+ const ending = isPending("end");
1988
+ return /* @__PURE__ */ jsxRuntime.jsx(
1989
+ chunkGICUGQNN_cjs.ConfirmDialog,
1990
+ {
1991
+ isOpen: open,
1992
+ onClose: () => onOpenChange(false),
1993
+ onConfirm: () => void run("end", onEnd).then((ok) => {
1994
+ if (ok) onOpenChange(false);
1995
+ }),
1996
+ title: "End the webinar?",
1997
+ description: "Everyone leaves, attendees and panelists alike. The stage closes and cannot be reopened in this session.",
1998
+ confirmText: "End webinar",
1999
+ isLoading: ending,
2000
+ testId: "webinar-end-confirm",
2001
+ testIds: { cancel: "webinar-end-cancel", confirm: "webinar-end-confirm-button" }
2002
+ }
2003
+ );
2004
+ }
2005
+ function BackstageBanner({
2006
+ onGoLive,
2007
+ className
2008
+ }) {
2009
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2010
+ "div",
2011
+ {
2012
+ className: ui.cn(
2013
+ "flex min-h-10 min-w-0 items-center gap-2 rounded-md border border-yellow-border bg-yellow-bg py-1 pl-3 pr-1 text-sm text-yellow-text",
2014
+ className
2015
+ ),
2016
+ role: "status",
2017
+ "data-testid": "webinar-backstage",
2018
+ children: [
2019
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "size-4 shrink-0", "aria-hidden": true }),
2020
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
2021
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Backstage" }),
2022
+ " \u2014 attendees can't see or hear you yet",
2023
+ !onGoLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-yellow-text/80", children: ". The host goes live when ready." })
2024
+ ] }),
2025
+ onGoLive && /* @__PURE__ */ jsxRuntime.jsx(WebinarLiveControl, { live: false, onGoLive })
2026
+ ]
2027
+ }
2028
+ );
2029
+ }
2030
+ function RaiseHandButton({
2031
+ raised,
2032
+ onToggle,
2033
+ pending = false,
2034
+ shortcut = "H",
2035
+ className
2036
+ }) {
2037
+ const { isPending, run } = usePending();
2038
+ const busy = pending || isPending("hand");
2039
+ return /* @__PURE__ */ jsxRuntime.jsx(
2040
+ CallControlButton,
2041
+ {
2042
+ label: raised ? "Lower hand" : "Raise hand",
2043
+ shortcut,
2044
+ tone: raised ? "active" : "neutral",
2045
+ "aria-pressed": raised,
2046
+ disabled: busy,
2047
+ "aria-busy": busy || void 0,
2048
+ onClick: () => void run("hand", () => onToggle(!raised)),
2049
+ className,
2050
+ "data-testid": "webinar-raise-hand",
2051
+ "data-raised": raised,
2052
+ "data-call-shortcut": shortcut.toLowerCase(),
2053
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { "aria-hidden": true })
2054
+ }
2055
+ );
2056
+ }
2057
+ var ROLE_NOTE = {
2058
+ host: "Host",
2059
+ cohost: "Co-host",
2060
+ panelist: "Panelist",
2061
+ attendee: null
2062
+ };
2063
+ function SectionTitle({ children }) {
2064
+ return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "flex items-center gap-1.5 px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children });
2065
+ }
2066
+ function Row({ testId, children }) {
2067
+ return /* @__PURE__ */ jsxRuntime.jsx(
2068
+ "li",
2069
+ {
2070
+ className: "flex min-h-11 items-center gap-3 rounded-md px-2 py-1 hover:bg-muted",
2071
+ "data-testid": testId,
2072
+ children
2073
+ }
2074
+ );
2075
+ }
2076
+ function WebinarAudiencePanel({
2077
+ hands,
2078
+ attendees,
2079
+ onPromote,
2080
+ onDemote,
2081
+ searchThreshold = 8,
2082
+ now: fixedNow,
2083
+ className
2084
+ }) {
2085
+ const now = useNow(3e4, fixedNow);
2086
+ const { isPending, run } = usePending();
2087
+ const [query, setQuery] = react.useState("");
2088
+ const queue = react.useMemo(
2089
+ () => [...hands].sort((a, b) => Date.parse(a.raisedAt) - Date.parse(b.raisedAt)),
2090
+ [hands]
2091
+ );
2092
+ const searchable = attendees.length > searchThreshold;
2093
+ const q = searchable ? query.trim().toLowerCase() : "";
2094
+ const shown = q ? attendees.filter((a) => a.name.toLowerCase().includes(q)) : attendees;
2095
+ const action = (id, name, promote, where) => {
2096
+ const key = `${promote ? "promote" : "demote"}:${id}`;
2097
+ const busy = isPending(key);
2098
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2099
+ ui.Button,
2100
+ {
2101
+ type: "button",
2102
+ variant: "outline",
2103
+ size: "sm",
2104
+ className: "h-8 shrink-0",
2105
+ disabled: busy,
2106
+ "aria-label": promote ? `Promote ${name} to the stage` : `Move ${name} to the audience`,
2107
+ onClick: () => void run(key, () => promote ? onPromote(id) : onDemote(id)),
2108
+ "data-testid": `webinar-${where === "hand" ? "hand-" : ""}${promote ? "promote" : "demote"}-${id}`,
2109
+ children: [
2110
+ busy && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
2111
+ promote ? "Promote" : "Move to audience"
2112
+ ]
2113
+ }
2114
+ );
2115
+ };
2116
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2117
+ "div",
2118
+ {
2119
+ className: ui.cn("min-h-0 flex-1 overflow-y-auto px-2 pb-2", className),
2120
+ "data-testid": "webinar-audience",
2121
+ children: [
2122
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Raised hands", children: [
2123
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
2124
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { className: "size-3.5", "aria-hidden": true }),
2125
+ "Raised hands (",
2126
+ queue.length,
2127
+ ")"
2128
+ ] }),
2129
+ queue.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 py-2 text-sm text-muted-foreground", "data-testid": "webinar-hands-empty", children: "No hands raised." }) : /* @__PURE__ */ jsxRuntime.jsx("ol", { children: queue.map((h) => /* @__PURE__ */ jsxRuntime.jsxs(Row, { testId: `webinar-hand-${h.id}`, children: [
2130
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
2131
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex min-w-0 items-center gap-1.5 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: h.name, entity: h.entity }) }),
2132
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
2133
+ "Raised ",
2134
+ chunkKDG6FER6_cjs.fromNow(h.raisedAt, now)
2135
+ ] })
2136
+ ] }),
2137
+ action(h.id, h.name, true, "hand")
2138
+ ] }, h.id)) })
2139
+ ] }),
2140
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Attendees", children: [
2141
+ /* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
2142
+ "Attendees (",
2143
+ attendees.length,
2144
+ ")"
2145
+ ] }),
2146
+ searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative px-2 pb-1", children: [
2147
+ /* @__PURE__ */ jsxRuntime.jsx(
2148
+ lucideReact.Search,
2149
+ {
2150
+ className: "pointer-events-none absolute left-4.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground",
2151
+ "aria-hidden": true
2152
+ }
2153
+ ),
2154
+ /* @__PURE__ */ jsxRuntime.jsx(
2155
+ ui.Input,
2156
+ {
2157
+ type: "search",
2158
+ value: query,
2159
+ onChange: (e) => setQuery(e.target.value),
2160
+ placeholder: "Find someone",
2161
+ "aria-label": "Find an attendee",
2162
+ className: "h-8 pl-8 text-sm",
2163
+ "data-testid": "webinar-attendee-search"
2164
+ }
2165
+ )
2166
+ ] }),
2167
+ shown.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2168
+ "p",
2169
+ {
2170
+ className: "px-2 py-2 text-sm text-muted-foreground",
2171
+ "data-testid": "webinar-attendees-empty",
2172
+ children: q ? `No one matches \u201C${query.trim()}\u201D.` : "No attendees yet."
2173
+ }
2174
+ ) : /* @__PURE__ */ jsxRuntime.jsx("ul", { children: shown.map((a) => {
2175
+ const note = ROLE_NOTE[a.role];
2176
+ return /* @__PURE__ */ jsxRuntime.jsxs(Row, { testId: `webinar-attendee-${a.id}`, children: [
2177
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-sm", children: [
2178
+ /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: a.name, entity: a.entity }),
2179
+ (note || a.onStage) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: [note, a.onStage ? "On stage" : null].filter(Boolean).join(" \xB7 ") })
2180
+ ] }),
2181
+ a.handRaised && /* @__PURE__ */ jsxRuntime.jsx(
2182
+ lucideReact.Hand,
2183
+ {
2184
+ className: "size-4 shrink-0 text-primary",
2185
+ "aria-label": "Hand raised",
2186
+ "data-testid": `webinar-attendee-hand-${a.id}`
2187
+ }
2188
+ ),
2189
+ a.onStage ? a.role !== "host" && action(a.id, a.name, false, "list") : !a.handRaised && action(a.id, a.name, true, "list")
2190
+ ] }, a.id);
2191
+ }) })
2192
+ ] })
2193
+ ]
2194
+ }
2195
+ );
2196
+ }
2197
+ var DEFAULT_MAX = 500;
2198
+ function sortQuestions(questions, filter) {
2199
+ const match = (s) => filter === "open" ? s === "open" || s === "answering" : s === filter;
2200
+ return questions.filter((q) => match(q.status)).sort(
2201
+ (a, b) => Number(b.status === "answering") - Number(a.status === "answering") || b.voteCount - a.voteCount || Date.parse(a.createdAt) - Date.parse(b.createdAt)
2202
+ );
2203
+ }
2204
+ function PanelComposer({
2205
+ placeholder,
2206
+ ariaLabel,
2207
+ sendLabel,
2208
+ maxLength,
2209
+ busy,
2210
+ onSend,
2211
+ onCancel,
2212
+ autoFocus,
2213
+ testId
2214
+ }) {
2215
+ const [text, setText] = react.useState("");
2216
+ const body = text.trim();
2217
+ const canSend = !!body && body.length <= maxLength && !busy;
2218
+ const send = () => {
2219
+ if (!canSend) return;
2220
+ void onSend(body).then((ok) => {
2221
+ if (ok) setText("");
2222
+ });
2223
+ };
2224
+ const onKeyDown = (e) => {
2225
+ if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
2226
+ e.preventDefault();
2227
+ send();
2228
+ } else if (e.key === "Escape" && onCancel) {
2229
+ e.preventDefault();
2230
+ onCancel();
2231
+ }
2232
+ };
2233
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": testId, children: [
2234
+ /* @__PURE__ */ jsxRuntime.jsx(
2235
+ ui.Textarea,
2236
+ {
2237
+ value: text,
2238
+ onChange: (e) => setText(e.target.value),
2239
+ onKeyDown,
2240
+ placeholder,
2241
+ "aria-label": ariaLabel,
2242
+ maxLength,
2243
+ rows: 2,
2244
+ disabled: busy,
2245
+ autoFocus,
2246
+ className: "min-h-[60px] resize-none",
2247
+ "data-testid": `${testId}-input`
2248
+ }
2249
+ ),
2250
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2251
+ /* @__PURE__ */ jsxRuntime.jsxs(
2252
+ "span",
2253
+ {
2254
+ className: ui.cn(
2255
+ "flex-1 text-xs tabular-nums text-muted-foreground",
2256
+ text.length >= maxLength && "text-red-text"
2257
+ ),
2258
+ "aria-live": "polite",
2259
+ "data-testid": `${testId}-count`,
2260
+ children: [
2261
+ text.length,
2262
+ "/",
2263
+ maxLength
2264
+ ]
2265
+ }
2266
+ ),
2267
+ onCancel && /* @__PURE__ */ jsxRuntime.jsx(
2268
+ ui.Button,
2269
+ {
2270
+ type: "button",
2271
+ variant: "ghost",
2272
+ size: "sm",
2273
+ className: "h-8",
2274
+ onClick: onCancel,
2275
+ disabled: busy,
2276
+ "data-testid": `${testId}-cancel`,
2277
+ children: "Cancel"
2278
+ }
2279
+ ),
2280
+ /* @__PURE__ */ jsxRuntime.jsxs(
2281
+ ui.Button,
2282
+ {
2283
+ type: "button",
2284
+ size: "sm",
2285
+ className: "h-8",
2286
+ onClick: send,
2287
+ disabled: !canSend,
2288
+ "data-testid": `${testId}-send`,
2289
+ children: [
2290
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "size-4", "aria-hidden": true }),
2291
+ sendLabel
2292
+ ]
2293
+ }
2294
+ )
2295
+ ] })
2296
+ ] });
2297
+ }
2298
+ function QuestionItem({
2299
+ q,
2300
+ team,
2301
+ now,
2302
+ maxLength,
2303
+ pending,
2304
+ run,
2305
+ onVote,
2306
+ onStatusChange,
2307
+ onAnswer,
2308
+ onDelete
2309
+ }) {
2310
+ const [answering, setAnswering] = react.useState(false);
2311
+ const voteKey = `vote:${q.id}`;
2312
+ const statusKey = `status:${q.id}`;
2313
+ const answerKey = `answer:${q.id}`;
2314
+ const busy = pending(statusKey) || pending(answerKey) || pending(`delete:${q.id}`);
2315
+ const setStatus = (status) => () => onStatusChange ? onStatusChange(q, status) : void 0;
2316
+ const can = team && !!onStatusChange;
2317
+ const primary = !can ? null : q.status === "open" ? { key: "live", label: "Answer live", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, {}), run: setStatus("answering") } : q.status === "answering" ? {
2318
+ key: "answered",
2319
+ label: "Mark answered",
2320
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, {}),
2321
+ run: setStatus("answered")
2322
+ } : { key: "reopen", label: "Reopen", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, {}), run: setStatus("open") };
2323
+ const more = [
2324
+ ...can && q.status === "open" ? [
2325
+ {
2326
+ key: "answered",
2327
+ label: "Mark answered",
2328
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, {}),
2329
+ run: setStatus("answered")
2330
+ }
2331
+ ] : [],
2332
+ ...can && q.status === "answering" ? [{ key: "reopen", label: "Reopen", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, {}), run: setStatus("open") }] : [],
2333
+ ...can && q.status !== "dismissed" ? [{ key: "dismiss", label: "Dismiss", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, {}), run: setStatus("dismissed") }] : [],
2334
+ ...q.mine && q.status === "open" && onDelete ? [
2335
+ {
2336
+ key: "delete",
2337
+ label: "Delete question",
2338
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, {}),
2339
+ run: () => onDelete(q),
2340
+ destructive: true
2341
+ }
2342
+ ] : []
2343
+ ];
2344
+ const canAnswerInText = team && !!onAnswer && !q.answer && q.status !== "dismissed";
2345
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2346
+ "li",
2347
+ {
2348
+ className: "flex gap-2 rounded-md border border-border p-2",
2349
+ "data-testid": `webinar-question-${q.id}`,
2350
+ "data-status": q.status,
2351
+ children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsxs(
2353
+ ui.Button,
2354
+ {
2355
+ type: "button",
2356
+ variant: "ghost",
2357
+ className: ui.cn(
2358
+ "h-auto w-10 shrink-0 flex-col gap-0 self-start px-0 py-1 text-xs tabular-nums",
2359
+ q.voted ? "bg-primary/10 text-primary hover:bg-primary/15" : "text-muted-foreground"
2360
+ ),
2361
+ "aria-pressed": q.voted,
2362
+ "aria-label": q.mine ? `${q.voteCount} upvotes (your question)` : q.voted ? `Remove upvote (${q.voteCount})` : `Upvote (${q.voteCount})`,
2363
+ title: q.mine ? "You can't upvote your own question" : void 0,
2364
+ disabled: q.mine || pending(voteKey),
2365
+ onClick: () => void run(voteKey, () => onVote(q, !q.voted)),
2366
+ "data-testid": `webinar-question-vote-${q.id}`,
2367
+ children: [
2368
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4", "aria-hidden": true }),
2369
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": `webinar-question-votes-${q.id}`, children: q.voteCount })
2370
+ ]
2371
+ }
2372
+ ),
2373
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
2374
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [
2375
+ /* @__PURE__ */ jsxRuntime.jsx(
2376
+ "span",
2377
+ {
2378
+ className: "flex min-w-0 items-center gap-1.5 text-sm text-foreground",
2379
+ "data-testid": `webinar-question-asker-${q.id}`,
2380
+ children: q.askerName === null && !q.asker ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Attendee" }) : /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: q.askerName ?? "", entity: q.asker, isLocal: q.mine })
2381
+ }
2382
+ ),
2383
+ /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: q.createdAt, children: chunkKDG6FER6_cjs.fromNow(q.createdAt, now) }),
2384
+ q.status === "answering" && /* @__PURE__ */ jsxRuntime.jsx(
2385
+ CallStatusChip,
2386
+ {
2387
+ tone: "red",
2388
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-3.5 shrink-0", "aria-hidden": true }),
2389
+ label: "Answering live",
2390
+ testId: `webinar-question-live-${q.id}`
2391
+ }
2392
+ ),
2393
+ q.status === "answered" && /* @__PURE__ */ jsxRuntime.jsx(
2394
+ CallStatusChip,
2395
+ {
2396
+ tone: "green",
2397
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "size-3.5 shrink-0", "aria-hidden": true }),
2398
+ label: "Answered",
2399
+ testId: `webinar-question-answered-${q.id}`
2400
+ }
2401
+ ),
2402
+ q.status === "dismissed" && /* @__PURE__ */ jsxRuntime.jsx(CallStatusChip, { tone: "neutral", label: "Dismissed" })
2403
+ ] }),
2404
+ /* @__PURE__ */ jsxRuntime.jsx(
2405
+ "p",
2406
+ {
2407
+ className: "whitespace-pre-wrap break-words text-sm",
2408
+ "data-testid": `webinar-question-body-${q.id}`,
2409
+ children: q.body
2410
+ }
2411
+ ),
2412
+ q.answer && /* @__PURE__ */ jsxRuntime.jsxs(
2413
+ "div",
2414
+ {
2415
+ className: "flex flex-col gap-1 rounded-md bg-muted px-2.5 py-2 text-sm",
2416
+ "data-testid": `webinar-question-answer-${q.id}`,
2417
+ children: [
2418
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
2419
+ "Answer",
2420
+ q.answeredBy
2421
+ ] }),
2422
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap break-words", children: q.answer })
2423
+ ]
2424
+ }
2425
+ ),
2426
+ answering && onAnswer && /* @__PURE__ */ jsxRuntime.jsx(
2427
+ PanelComposer,
2428
+ {
2429
+ placeholder: "Write an answer",
2430
+ ariaLabel: "Answer in text",
2431
+ sendLabel: "Send answer",
2432
+ maxLength,
2433
+ busy: pending(answerKey),
2434
+ autoFocus: true,
2435
+ onSend: (text) => run(answerKey, () => onAnswer(q, text)).then((ok) => {
2436
+ if (ok) setAnswering(false);
2437
+ return ok;
2438
+ }),
2439
+ onCancel: () => setAnswering(false),
2440
+ testId: `webinar-answer-${q.id}`
2441
+ }
2442
+ ),
2443
+ (primary || canAnswerInText || more.length > 0) && !answering && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
2444
+ primary && /* @__PURE__ */ jsxRuntime.jsxs(
2445
+ ui.Button,
2446
+ {
2447
+ type: "button",
2448
+ variant: "outline",
2449
+ size: "sm",
2450
+ className: "h-7 gap-1.5 px-2 text-xs [&_svg]:size-3.5",
2451
+ disabled: busy,
2452
+ onClick: () => void run(statusKey, primary.run),
2453
+ "data-testid": `webinar-question-${primary.key}-${q.id}`,
2454
+ children: [
2455
+ pending(statusKey) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin", "aria-hidden": true }) : primary.icon,
2456
+ primary.label
2457
+ ]
2458
+ }
2459
+ ),
2460
+ canAnswerInText && /* @__PURE__ */ jsxRuntime.jsxs(
2461
+ ui.Button,
2462
+ {
2463
+ type: "button",
2464
+ variant: "ghost",
2465
+ size: "sm",
2466
+ className: "h-7 gap-1.5 px-2 text-xs [&_svg]:size-3.5",
2467
+ disabled: busy,
2468
+ onClick: () => setAnswering(true),
2469
+ "data-testid": `webinar-question-answer-text-${q.id}`,
2470
+ children: [
2471
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareText, { "aria-hidden": true }),
2472
+ "Answer in text"
2473
+ ]
2474
+ }
2475
+ ),
2476
+ more.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
2477
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2478
+ ui.Button,
2479
+ {
2480
+ type: "button",
2481
+ variant: "ghost",
2482
+ size: "icon",
2483
+ className: "ml-auto size-7 text-muted-foreground hover:text-foreground",
2484
+ "aria-label": "More question actions",
2485
+ disabled: busy,
2486
+ "data-testid": `webinar-question-menu-${q.id}`,
2487
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
2488
+ }
2489
+ ) }),
2490
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "end", className: "w-48", children: more.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
2491
+ ui.DropdownMenuItem,
2492
+ {
2493
+ onSelect: () => void run(a.key === "delete" ? `delete:${q.id}` : statusKey, a.run),
2494
+ className: ui.cn(a.destructive && "text-destructive focus:text-destructive"),
2495
+ "data-testid": `webinar-question-${a.key}-${q.id}`,
2496
+ children: [
2497
+ a.icon,
2498
+ a.label
2499
+ ]
2500
+ },
2501
+ a.key
2502
+ )) })
2503
+ ] })
2504
+ ] })
2505
+ ] })
2506
+ ]
2507
+ }
2508
+ );
2509
+ }
2510
+ var EMPTY = {
2511
+ open: {
2512
+ team: "Questions from the audience appear here.",
2513
+ audience: "No questions yet. Ask the first one."
2514
+ },
2515
+ answered: { team: "No answered questions yet.", audience: "No answered questions yet." },
2516
+ dismissed: { team: "Nothing dismissed.", audience: "Nothing dismissed." }
2517
+ };
2518
+ function QAPanel({
2519
+ questions,
2520
+ team = false,
2521
+ maxLength = DEFAULT_MAX,
2522
+ canAsk = true,
2523
+ onAsk,
2524
+ onVote,
2525
+ onStatusChange,
2526
+ onAnswer,
2527
+ onDelete,
2528
+ defaultFilter = "open",
2529
+ now: fixedNow,
2530
+ className
2531
+ }) {
2532
+ const now = useNow(3e4, fixedNow);
2533
+ const { isPending, run } = usePending();
2534
+ const [filter, setFilter] = react.useState(
2535
+ defaultFilter === "dismissed" && !team ? "open" : defaultFilter
2536
+ );
2537
+ const filters = [
2538
+ { id: "open", label: "Open" },
2539
+ { id: "answered", label: "Answered" },
2540
+ ...team ? [{ id: "dismissed", label: "Dismissed" }] : []
2541
+ ];
2542
+ const lists = react.useMemo(
2543
+ () => ({
2544
+ open: sortQuestions(questions, "open"),
2545
+ answered: sortQuestions(questions, "answered"),
2546
+ // Dismissed questions are the team's business only.
2547
+ dismissed: team ? sortQuestions(questions, "dismissed") : []
2548
+ }),
2549
+ [questions, team]
2550
+ );
2551
+ const shown = lists[filter];
2552
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex min-h-0 flex-1 flex-col", className), "data-testid": "webinar-qa", children: [
2553
+ /* @__PURE__ */ jsxRuntime.jsxs(
2554
+ ui.Tabs,
2555
+ {
2556
+ value: filter,
2557
+ onValueChange: (v) => setFilter(v),
2558
+ className: "flex min-h-0 flex-1 flex-col",
2559
+ children: [
2560
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-3 pt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.TabsList, { className: "h-8 w-full", children: filters.map((f) => /* @__PURE__ */ jsxRuntime.jsxs(
2561
+ ui.TabsTrigger,
2562
+ {
2563
+ value: f.id,
2564
+ className: "h-6 flex-1 gap-1.5 px-2 text-xs",
2565
+ "data-testid": `webinar-qa-filter-${f.id}`,
2566
+ children: [
2567
+ f.label,
2568
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums text-muted-foreground", children: lists[f.id].length })
2569
+ ]
2570
+ },
2571
+ f.id
2572
+ )) }) }),
2573
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: filter, className: "mt-0 min-h-0 flex-1 overflow-y-auto p-3", children: shown.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2574
+ "p",
2575
+ {
2576
+ className: "py-6 text-center text-sm text-muted-foreground",
2577
+ "data-testid": "webinar-qa-empty",
2578
+ children: filter === "open" && questions.length > 0 ? "No open questions right now." : EMPTY[filter][team ? "team" : "audience"]
2579
+ }
2580
+ ) : /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex flex-col gap-2", children: shown.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
2581
+ QuestionItem,
2582
+ {
2583
+ q,
2584
+ team,
2585
+ now,
2586
+ maxLength,
2587
+ pending: isPending,
2588
+ run,
2589
+ onVote,
2590
+ onStatusChange,
2591
+ onAnswer,
2592
+ onDelete
2593
+ },
2594
+ q.id
2595
+ )) }) })
2596
+ ]
2597
+ }
2598
+ ),
2599
+ canAsk && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t border-border p-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2600
+ PanelComposer,
2601
+ {
2602
+ placeholder: "Ask a question",
2603
+ ariaLabel: "Ask a question",
2604
+ sendLabel: "Ask",
2605
+ maxLength,
2606
+ busy: isPending("ask"),
2607
+ onSend: (text) => run("ask", () => onAsk(text)),
2608
+ testId: "webinar-ask"
2609
+ }
2610
+ ) })
2611
+ ] });
2612
+ }
2613
+ var OPTIONS = [
2614
+ { value: "panelists", label: "Panelists only" },
2615
+ { value: "everyone", label: "Everyone" }
2616
+ ];
2617
+ function ChatPermissionSetting({
2618
+ value,
2619
+ onChange,
2620
+ pending = false
2621
+ }) {
2622
+ const [choosing, setChoosing] = react.useState(null);
2623
+ const busy = pending || choosing !== null;
2624
+ const select = (next) => {
2625
+ const v = next;
2626
+ if (v === value || busy) return;
2627
+ const result = onChange(v);
2628
+ if (result && typeof result.then === "function") {
2629
+ setChoosing(v);
2630
+ void result.then(
2631
+ () => setChoosing(null),
2632
+ () => setChoosing(null)
2633
+ );
2634
+ }
2635
+ };
2636
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Who can chat", "data-testid": "webinar-chat-permission", children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuLabel, { className: "flex items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
2638
+ "Who can chat",
2639
+ busy && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin", "aria-label": "Saving" })
2640
+ ] }),
2641
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuRadioGroup, { value: choosing ?? value, onValueChange: select, children: OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
2642
+ ui.DropdownMenuRadioItem,
2643
+ {
2644
+ value: o.value,
2645
+ disabled: busy,
2646
+ "data-testid": `webinar-chat-${o.value}`,
2647
+ children: o.label
2648
+ },
2649
+ o.value
2650
+ )) })
2651
+ ] });
2652
+ }
2653
+ function chatPermissionSection(props) {
2654
+ return { key: "webinar-chat", content: /* @__PURE__ */ jsxRuntime.jsx(ChatPermissionSetting, { ...props }) };
2655
+ }
2656
+ function OnStageCheck({
2657
+ open,
2658
+ onJoinStage,
2659
+ onStayInAudience,
2660
+ busy = false,
2661
+ error,
2662
+ mirror = true,
2663
+ describeError = describeMediaError
2664
+ }) {
2665
+ const { isPending, run } = usePending();
2666
+ const working = busy || isPending("join") || isPending("stay");
2667
+ const stay = () => {
2668
+ if (!working) void run("stay", onStayInAudience);
2669
+ };
2670
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open, onOpenChange: (next) => !next && stay(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.DialogContent, { presentation: "sheet", className: "max-w-3xl", "data-testid": "webinar-on-stage", children: /* @__PURE__ */ jsxRuntime.jsx(
2671
+ PreJoin,
2672
+ {
2673
+ heading: "You're on stage",
2674
+ headingAs: ui.DialogTitle,
2675
+ joinLabel: "Join stage",
2676
+ cancelLabel: "Stay in audience",
2677
+ busy: working,
2678
+ error,
2679
+ mirror,
2680
+ describeError,
2681
+ onJoin: (choices) => void run("join", () => onJoinStage(choices)),
2682
+ onCancel: stay,
2683
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: "A host invited you to speak. Check your microphone and camera: once you join, everyone sees and hears you." })
2684
+ }
2685
+ ) }) });
2686
+ }
2687
+ function WebinarViewer({
2688
+ header,
2689
+ stage,
2690
+ stageRef,
2691
+ stageOverlay,
2692
+ captions,
2693
+ side,
2694
+ sideToggle,
2695
+ hand,
2696
+ onLeave,
2697
+ left,
2698
+ controls,
2699
+ shortcuts = true,
2700
+ className
2701
+ }) {
2702
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2703
+ "div",
2704
+ {
2705
+ className: ui.cn(
2706
+ "@container flex size-full min-h-0 flex-col bg-background text-foreground",
2707
+ className
2708
+ ),
2709
+ "data-testid": "webinar-viewer",
2710
+ children: [
2711
+ header,
2712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex min-h-0 flex-1", children: [
2713
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col gap-2 px-3 pb-3 pt-1", children: [
2714
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: stageRef, className: "relative min-h-0 flex-1", "data-testid": "call-stage", children: [
2715
+ stage,
2716
+ stageOverlay
2717
+ ] }),
2718
+ captions
2719
+ ] }),
2720
+ side && /* @__PURE__ */ jsxRuntime.jsx(
2721
+ "div",
2722
+ {
2723
+ className: "absolute inset-0 z-20 flex min-h-0 flex-col border-t border-border motion-safe:animate-in motion-safe:fade-in-0 @3xl:static @3xl:z-auto @3xl:w-80 @3xl:shrink-0 @3xl:border-l @3xl:border-t-0",
2724
+ "data-testid": "webinar-viewer-side",
2725
+ children: side
2726
+ }
2727
+ )
2728
+ ] }),
2729
+ /* @__PURE__ */ jsxRuntime.jsx(CallControlBar, { shortcuts, left, right: /* @__PURE__ */ jsxRuntime.jsx(LeaveButton, { onLeave }), children: /* @__PURE__ */ jsxRuntime.jsxs(ControlGroup, { children: [
2730
+ /* @__PURE__ */ jsxRuntime.jsx(RaiseHandButton, { ...hand }),
2731
+ sideToggle && /* @__PURE__ */ jsxRuntime.jsxs(
2732
+ CallControlButton,
2733
+ {
2734
+ label: sideToggle.open ? `Close ${sideToggle.label}` : sideToggle.label,
2735
+ tone: sideToggle.open ? "active" : "neutral",
2736
+ "aria-pressed": sideToggle.open,
2737
+ onClick: sideToggle.onToggle,
2738
+ "data-testid": "webinar-side-toggle",
2739
+ children: [
2740
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleQuestion, { "aria-hidden": true }),
2741
+ !!sideToggle.count && /* @__PURE__ */ jsxRuntime.jsx(ControlBadge, { count: sideToggle.count, tone: "quiet" })
2742
+ ]
2743
+ }
2744
+ ),
2745
+ controls
2746
+ ] }) })
2747
+ ]
2748
+ }
2749
+ );
2750
+ }
1735
2751
 
1736
2752
  Object.defineProperty(exports, "CAPTION_LINES", {
1737
2753
  enumerable: true,
@@ -1813,6 +2829,7 @@ Object.defineProperty(exports, "stageContentHeight", {
1813
2829
  enumerable: true,
1814
2830
  get: function () { return chunkMWDW5UBW_cjs.stageContentHeight; }
1815
2831
  });
2832
+ exports.BackstageBanner = BackstageBanner;
1816
2833
  exports.CallControlBar = CallControlBar;
1817
2834
  exports.CallControlButton = CallControlButton;
1818
2835
  exports.CallFocus = CallFocus;
@@ -1820,12 +2837,14 @@ exports.CallGrid = CallGrid;
1820
2837
  exports.CallHeader = CallHeader;
1821
2838
  exports.CallNotice = CallNotice;
1822
2839
  exports.CallParticipants = CallParticipants;
2840
+ exports.CallPersonLabel = CallPersonLabel;
1823
2841
  exports.CallSidePanel = CallSidePanel;
1824
2842
  exports.CallStageFrame = CallStageFrame;
1825
2843
  exports.CallStateMessage = CallStateMessage;
1826
2844
  exports.CallStatusChip = CallStatusChip;
1827
2845
  exports.CallTile = CallTile;
1828
2846
  exports.CaptionsStrip = CaptionsStrip;
2847
+ exports.ChatPermissionSetting = ChatPermissionSetting;
1829
2848
  exports.ConnectionOverlay = ConnectionOverlay;
1830
2849
  exports.ControlBadge = ControlBadge;
1831
2850
  exports.ControlDivider = ControlDivider;
@@ -1839,13 +2858,25 @@ exports.LobbyRequests = LobbyRequests;
1839
2858
  exports.MediaControl = MediaControl;
1840
2859
  exports.MinimisedCall = MinimisedCall;
1841
2860
  exports.MoreMenu = MoreMenu;
2861
+ exports.OnStageCheck = OnStageCheck;
2862
+ exports.PanelComposer = PanelComposer;
1842
2863
  exports.PreJoin = PreJoin;
2864
+ exports.QAPanel = QAPanel;
2865
+ exports.RaiseHandButton = RaiseHandButton;
1843
2866
  exports.RecordControl = RecordControl;
1844
2867
  exports.RecordingStatusChip = RecordingStatusChip;
1845
2868
  exports.SpeakingNow = SpeakingNow;
1846
2869
  exports.TranscriptionStatusChip = TranscriptionStatusChip;
1847
2870
  exports.VoiceMeter = VoiceMeter;
2871
+ exports.WebinarAudiencePanel = WebinarAudiencePanel;
2872
+ exports.WebinarEndConfirm = WebinarEndConfirm;
2873
+ exports.WebinarLiveChip = WebinarLiveChip;
2874
+ exports.WebinarLiveControl = WebinarLiveControl;
2875
+ exports.WebinarViewer = WebinarViewer;
2876
+ exports.WebinarWaiting = WebinarWaiting;
2877
+ exports.chatPermissionSection = chatPermissionSection;
1848
2878
  exports.describeMediaError = describeMediaError;
2879
+ exports.sortQuestions = sortQuestions;
1849
2880
  exports.useBriefNotice = useBriefNotice;
1850
2881
  exports.useElementSize = useElementSize;
1851
2882
  exports.useShortcutKeys = useShortcutKeys;