@arbidocs/blocks 0.4.129 → 0.4.131

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 (121) hide show
  1. package/dist/agents/index.cjs +303 -303
  2. package/dist/agents/index.js +11 -11
  3. package/dist/calendar/CalendarPrint.d.ts +25 -0
  4. package/dist/calendar/booking-slots.d.ts +21 -0
  5. package/dist/calendar/index.cjs +381 -97
  6. package/dist/calendar/index.cjs.map +1 -1
  7. package/dist/calendar/index.d.ts +4 -0
  8. package/dist/calendar/index.js +277 -3
  9. package/dist/calendar/index.js.map +1 -1
  10. package/dist/calendar/print-layout.d.ts +16 -0
  11. package/dist/calendar/printCalendar.d.ts +6 -0
  12. package/dist/calls/composite-canvas.d.ts +52 -0
  13. package/dist/calls/index.cjs +374 -1
  14. package/dist/calls/index.cjs.map +1 -1
  15. package/dist/calls/index.d.ts +3 -0
  16. package/dist/calls/index.js +359 -4
  17. package/dist/calls/index.js.map +1 -1
  18. package/dist/calls/ringtone.d.ts +16 -0
  19. package/dist/calls/voice-levels.d.ts +32 -0
  20. package/dist/chat/ThreadVisualizer.d.ts +28 -0
  21. package/dist/chat/index.cjs +151 -135
  22. package/dist/chat/index.d.ts +2 -0
  23. package/dist/chat/index.js +4 -4
  24. package/dist/chat/thread-diagram.d.ts +26 -0
  25. package/dist/{chunk-H2KQ6OSU.js → chunk-26E6PHD2.js} +231 -6
  26. package/dist/chunk-26E6PHD2.js.map +1 -0
  27. package/dist/{chunk-2PNNCEPH.js → chunk-54ANPPMV.js} +4 -4
  28. package/dist/{chunk-2PNNCEPH.js.map → chunk-54ANPPMV.js.map} +1 -1
  29. package/dist/{chunk-IBZJYCYM.js → chunk-66TA5IBN.js} +17 -25
  30. package/dist/chunk-66TA5IBN.js.map +1 -0
  31. package/dist/{chunk-OYMWV45N.js → chunk-7D4W3SAH.js} +51 -4
  32. package/dist/chunk-7D4W3SAH.js.map +1 -0
  33. package/dist/{chunk-2DFDFOM7.js → chunk-7HAM7Y5U.js} +3 -3
  34. package/dist/{chunk-2DFDFOM7.js.map → chunk-7HAM7Y5U.js.map} +1 -1
  35. package/dist/{chunk-7423V6RM.cjs → chunk-7KH4M3KY.cjs} +8 -8
  36. package/dist/{chunk-7423V6RM.cjs.map → chunk-7KH4M3KY.cjs.map} +1 -1
  37. package/dist/{chunk-TGWTLNXW.cjs → chunk-BIXHB4LV.cjs} +3 -2
  38. package/dist/{chunk-TGWTLNXW.cjs.map → chunk-BIXHB4LV.cjs.map} +1 -1
  39. package/dist/{chunk-DZYAAL4H.cjs → chunk-BZF55UCE.cjs} +234 -5
  40. package/dist/chunk-BZF55UCE.cjs.map +1 -0
  41. package/dist/{chunk-3BJLNKOB.cjs → chunk-CDZVC32G.cjs} +5 -5
  42. package/dist/{chunk-3BJLNKOB.cjs.map → chunk-CDZVC32G.cjs.map} +1 -1
  43. package/dist/{chunk-PUCY3UXN.js → chunk-CXLVI3SB.js} +3 -3
  44. package/dist/{chunk-PUCY3UXN.js.map → chunk-CXLVI3SB.js.map} +1 -1
  45. package/dist/{chunk-KYDRUFWT.cjs → chunk-D4YR56FV.cjs} +5 -5
  46. package/dist/{chunk-KYDRUFWT.cjs.map → chunk-D4YR56FV.cjs.map} +1 -1
  47. package/dist/{chunk-6BTCDKCK.js → chunk-DI35D756.js} +4 -4
  48. package/dist/{chunk-6BTCDKCK.js.map → chunk-DI35D756.js.map} +1 -1
  49. package/dist/{chunk-TGJNPKST.js → chunk-GTCC2VAR.js} +3 -3
  50. package/dist/{chunk-TGJNPKST.js.map → chunk-GTCC2VAR.js.map} +1 -1
  51. package/dist/{chunk-6AALMYPS.cjs → chunk-HM23LXUP.cjs} +3 -3
  52. package/dist/{chunk-6AALMYPS.cjs.map → chunk-HM23LXUP.cjs.map} +1 -1
  53. package/dist/{chunk-HSFLEVZY.js → chunk-KLOSOT26.js} +10 -10
  54. package/dist/{chunk-HSFLEVZY.js.map → chunk-KLOSOT26.js.map} +1 -1
  55. package/dist/{chunk-SARREDFP.cjs → chunk-LC2KJSUS.cjs} +46 -46
  56. package/dist/{chunk-SARREDFP.cjs.map → chunk-LC2KJSUS.cjs.map} +1 -1
  57. package/dist/{chunk-MUMH3Z6K.cjs → chunk-LRD7BHAT.cjs} +50 -3
  58. package/dist/chunk-LRD7BHAT.cjs.map +1 -0
  59. package/dist/{chunk-CJBN5HIS.js → chunk-P5HOXWYL.js} +3 -3
  60. package/dist/{chunk-CJBN5HIS.js.map → chunk-P5HOXWYL.js.map} +1 -1
  61. package/dist/{chunk-5Y7JRY7Y.js → chunk-P5ST47VY.js} +3 -3
  62. package/dist/{chunk-5Y7JRY7Y.js.map → chunk-P5ST47VY.js.map} +1 -1
  63. package/dist/{chunk-A7NCSZAP.cjs → chunk-QZTNTP75.cjs} +17 -25
  64. package/dist/chunk-QZTNTP75.cjs.map +1 -0
  65. package/dist/{chunk-ENDP7JER.js → chunk-VW2C2AZL.js} +3 -3
  66. package/dist/{chunk-ENDP7JER.js.map → chunk-VW2C2AZL.js.map} +1 -1
  67. package/dist/{chunk-JLTXVW25.cjs → chunk-W27VK32R.cjs} +78 -78
  68. package/dist/{chunk-JLTXVW25.cjs.map → chunk-W27VK32R.cjs.map} +1 -1
  69. package/dist/{chunk-PJJY6CYL.cjs → chunk-WV4IDVDQ.cjs} +11 -11
  70. package/dist/{chunk-PJJY6CYL.cjs.map → chunk-WV4IDVDQ.cjs.map} +1 -1
  71. package/dist/{chunk-NYHGG2IA.cjs → chunk-ZV3BKLFY.cjs} +3 -3
  72. package/dist/{chunk-NYHGG2IA.cjs.map → chunk-ZV3BKLFY.cjs.map} +1 -1
  73. package/dist/collaboration/index.cjs +9 -9
  74. package/dist/collaboration/index.js +1 -1
  75. package/dist/connect/docx.cjs +4 -4
  76. package/dist/connect/docx.js +3 -3
  77. package/dist/connect/index.cjs +183 -146
  78. package/dist/connect/index.cjs.map +1 -1
  79. package/dist/connect/index.d.ts +1 -1
  80. package/dist/connect/index.js +134 -98
  81. package/dist/connect/index.js.map +1 -1
  82. package/dist/connection/ConnectedSettings.d.ts +42 -7
  83. package/dist/document-tools/index.cjs +1 -1
  84. package/dist/document-tools/index.js +1 -1
  85. package/dist/facts/fact-citations.d.ts +56 -0
  86. package/dist/facts/fact-table-column-resize.d.ts +18 -0
  87. package/dist/facts/index.cjs +194 -8
  88. package/dist/facts/index.cjs.map +1 -1
  89. package/dist/facts/index.d.ts +2 -0
  90. package/dist/facts/index.js +180 -5
  91. package/dist/facts/index.js.map +1 -1
  92. package/dist/files/index.cjs +1 -1
  93. package/dist/files/index.js +1 -1
  94. package/dist/home/index.cjs +17 -17
  95. package/dist/home/index.js +3 -3
  96. package/dist/index.cjs +517 -501
  97. package/dist/index.js +18 -18
  98. package/dist/settings/MoreInfo.d.ts +25 -0
  99. package/dist/settings/PlanCard.d.ts +1 -1
  100. package/dist/settings/index.cjs +79 -225
  101. package/dist/settings/index.cjs.map +1 -1
  102. package/dist/settings/index.d.ts +1 -1
  103. package/dist/settings/index.js +70 -215
  104. package/dist/settings/index.js.map +1 -1
  105. package/dist/shell/index.cjs +1 -1
  106. package/dist/shell/index.js +1 -1
  107. package/dist/site/index.cjs +5 -5
  108. package/dist/site/index.js +1 -1
  109. package/dist/studio/index.cjs +8 -8
  110. package/dist/studio/index.js +6 -6
  111. package/dist/workflow-canvas/index.cjs +64 -64
  112. package/dist/workflow-canvas/index.js +12 -12
  113. package/node_modules/@arbidocs/coedit/package.json +1 -1
  114. package/package.json +9 -4
  115. package/dist/chunk-A7NCSZAP.cjs.map +0 -1
  116. package/dist/chunk-DZYAAL4H.cjs.map +0 -1
  117. package/dist/chunk-H2KQ6OSU.js.map +0 -1
  118. package/dist/chunk-IBZJYCYM.js.map +0 -1
  119. package/dist/chunk-MUMH3Z6K.cjs.map +0 -1
  120. package/dist/chunk-OYMWV45N.js.map +0 -1
  121. package/dist/settings/FirmPool.d.ts +0 -82
@@ -0,0 +1,16 @@
1
+ /** Pure layout helpers for the calendar print view: ranges and zone-correct day bucketing. */
2
+ import type { components } from '@arbidocs/client';
3
+ export type CalendarEvent = components['schemas']['CalendarEvent'];
4
+ export type PrintView = 'agenda' | 'day' | 'week' | 'month';
5
+ /** The days [from, to) a view covers. */
6
+ export declare function printRange(view: PrintView, date: string, weekStart?: number, agendaDays?: number): {
7
+ from: string;
8
+ to: string;
9
+ };
10
+ export declare function eachDay(from: string, to: string): string[];
11
+ /** Zone days an event touches (all-day: its dates; timed: the zone dates of [start, end)). */
12
+ export declare function eventDays(e: CalendarEvent, zone: string): string[];
13
+ export declare function timeLabel(e: CalendarEvent, day: string, zone: string): string;
14
+ /** Events per zone day within [from, to), all-day first then by start. */
15
+ export declare function eventsByDay(events: CalendarEvent[], zone: string, from: string, to: string): Map<string, CalendarEvent[]>;
16
+ export declare function heading(view: PrintView, date: string, from: string, to: string): string;
@@ -0,0 +1,6 @@
1
+ import { type CalendarPrintProps } from './CalendarPrint';
2
+ /**
3
+ * Open the browser print dialog showing only the calendar print view. With `props`, the view is rendered
4
+ * into a temporary body-level host; without, the first mounted `<CalendarPrint>` is copied there.
5
+ */
6
+ export declare function printCalendar(props?: CalendarPrintProps): void;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The host's composite recording (ARBI `docs/meeting-chats-plan.md` §6, "Audio + video"): a canvas
3
+ * that mirrors the host's call stage — the same tiles in the same places (grid, or the screen share
4
+ * large with the others in a strip), since it is drawn from the stage's own rendered <video>
5
+ * elements — plus the mixed audio the host hears (WebAudio: every remote audio track and the host's
6
+ * microphone). The stream is recorded by the chunked recorder in the host's browser.
7
+ */
8
+ /** Frame rate and size of the composite recording canvas. */
9
+ export declare const COMPOSITE_FPS = 15;
10
+ export declare const COMPOSITE_MAX_WIDTH = 1280;
11
+ export declare const COMPOSITE_MAX_HEIGHT = 720;
12
+ /** Fit a `w × h` stage into the canvas, centred, aspect kept. */
13
+ export declare function fitStage(stage: {
14
+ width: number;
15
+ height: number;
16
+ }, canvas: {
17
+ width: number;
18
+ height: number;
19
+ }): {
20
+ scale: number;
21
+ dx: number;
22
+ dy: number;
23
+ };
24
+ /** Draw `src` (w × h) into a box, `contain` (letterboxed) or `cover` (cropped). */
25
+ export declare function fitMedia(src: {
26
+ width: number;
27
+ height: number;
28
+ }, box: {
29
+ x: number;
30
+ y: number;
31
+ width: number;
32
+ height: number;
33
+ }, mode: 'contain' | 'cover'): {
34
+ sx: number;
35
+ sy: number;
36
+ sw: number;
37
+ sh: number;
38
+ dx: number;
39
+ dy: number;
40
+ dw: number;
41
+ dh: number;
42
+ };
43
+ /** One frame of the stage. */
44
+ export declare function drawStageFrame(ctx: CanvasRenderingContext2D, stage: HTMLElement, width: number, height: number): void;
45
+ export interface CompositeCapture {
46
+ stream: MediaStream;
47
+ /** Keep the mixed audio in step with the room's audio tracks. */
48
+ setAudioTracks(tracks: MediaStreamTrack[]): void;
49
+ dispose(): void;
50
+ }
51
+ /** Start drawing the stage into a ≤720p canvas and mixing the given audio. */
52
+ export declare function startCompositeCapture(stage: HTMLElement): CompositeCapture;
@@ -2,8 +2,8 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkZAVEMQ37_cjs = require('../chunk-ZAVEMQ37.cjs');
5
- require('../chunk-ULWRNGGE.cjs');
6
5
  var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
6
+ require('../chunk-ULWRNGGE.cjs');
7
7
  var chunkMWDW5UBW_cjs = require('../chunk-MWDW5UBW.cjs');
8
8
  require('../chunk-PPCATBOY.cjs');
9
9
  require('../chunk-MHVNT4J3.cjs');
@@ -2748,6 +2748,361 @@ function WebinarViewer({
2748
2748
  }
2749
2749
  );
2750
2750
  }
2751
+ var LEVEL_TICK_MS = 60;
2752
+ var SPEAKING_RELEASE_MS = 350;
2753
+ var EMPTY2 = { levels: {}, speaking: [], spotlight: null };
2754
+ var snapshot = EMPTY2;
2755
+ var listeners = /* @__PURE__ */ new Set();
2756
+ function publish(next) {
2757
+ snapshot = next;
2758
+ listeners.forEach((fn) => fn());
2759
+ }
2760
+ function subscribe(fn) {
2761
+ listeners.add(fn);
2762
+ return () => listeners.delete(fn);
2763
+ }
2764
+ var get = () => snapshot;
2765
+ function useVoiceLevel(identity) {
2766
+ return react.useSyncExternalStore(
2767
+ subscribe,
2768
+ () => identity ? get().levels[identity] ?? 0 : 0,
2769
+ () => 0
2770
+ );
2771
+ }
2772
+ function useVoiceLevels() {
2773
+ return react.useSyncExternalStore(
2774
+ subscribe,
2775
+ () => get().levels,
2776
+ () => EMPTY2.levels
2777
+ );
2778
+ }
2779
+ function useIsSpeaking(identity) {
2780
+ return react.useSyncExternalStore(
2781
+ subscribe,
2782
+ () => identity ? get().speaking.includes(identity) : false,
2783
+ () => false
2784
+ );
2785
+ }
2786
+ function useSpeakingIds() {
2787
+ const key = react.useSyncExternalStore(
2788
+ subscribe,
2789
+ () => get().speaking.join("\n"),
2790
+ () => ""
2791
+ );
2792
+ return key ? key.split("\n") : [];
2793
+ }
2794
+ function useSpotlightId() {
2795
+ return react.useSyncExternalStore(
2796
+ subscribe,
2797
+ () => get().spotlight,
2798
+ () => null
2799
+ );
2800
+ }
2801
+ function startVoiceLevels(sources) {
2802
+ let ctx = null;
2803
+ try {
2804
+ ctx = typeof AudioContext !== "undefined" ? new AudioContext() : null;
2805
+ } catch {
2806
+ ctx = null;
2807
+ }
2808
+ const meters = /* @__PURE__ */ new Map();
2809
+ const smoothed = /* @__PURE__ */ new Map();
2810
+ const loudAt = /* @__PURE__ */ new Map();
2811
+ let spot = chunkMWDW5UBW_cjs.INITIAL_SPOTLIGHT;
2812
+ const meterFor = (s) => {
2813
+ if (!ctx || !s.track || s.track.readyState === "ended") return null;
2814
+ const have = meters.get(s.identity);
2815
+ if (have && have.track === s.track) return have;
2816
+ have?.source.disconnect();
2817
+ try {
2818
+ const source = ctx.createMediaStreamSource(new MediaStream([s.track]));
2819
+ const analyser = ctx.createAnalyser();
2820
+ analyser.fftSize = 512;
2821
+ source.connect(analyser);
2822
+ const m = { track: s.track, source, analyser, buf: new Float32Array(analyser.fftSize) };
2823
+ meters.set(s.identity, m);
2824
+ return m;
2825
+ } catch {
2826
+ return null;
2827
+ }
2828
+ };
2829
+ const tick = () => {
2830
+ if (ctx?.state === "suspended") void ctx.resume().catch(() => void 0);
2831
+ const now = Date.now();
2832
+ const list = sources();
2833
+ const seen = /* @__PURE__ */ new Set();
2834
+ const levels = {};
2835
+ for (const s of list) {
2836
+ seen.add(s.identity);
2837
+ let raw = 0;
2838
+ const m = s.muted ? null : meterFor(s);
2839
+ if (m) {
2840
+ m.analyser.getFloatTimeDomainData(m.buf);
2841
+ let sum = 0;
2842
+ for (let i = 0; i < m.buf.length; i++) sum += m.buf[i] * m.buf[i];
2843
+ raw = Math.min(1, Math.sqrt(sum / m.buf.length) * 5);
2844
+ }
2845
+ const prev2 = smoothed.get(s.identity) ?? 0;
2846
+ const level = raw >= prev2 ? raw : prev2 * 0.8 + raw * 0.2;
2847
+ smoothed.set(s.identity, level);
2848
+ if (level >= chunkMWDW5UBW_cjs.SPEAKING_LEVEL) loudAt.set(s.identity, now);
2849
+ levels[s.identity] = Math.round(level * 20) / 20;
2850
+ }
2851
+ for (const id2 of [...meters.keys()]) {
2852
+ if (!seen.has(id2)) {
2853
+ meters.get(id2)?.source.disconnect();
2854
+ meters.delete(id2);
2855
+ smoothed.delete(id2);
2856
+ loudAt.delete(id2);
2857
+ }
2858
+ }
2859
+ const speaking = list.map((s) => s.identity).filter((id2) => now - (loudAt.get(id2) ?? -Infinity) <= SPEAKING_RELEASE_MS).sort((a, b) => (smoothed.get(b) ?? 0) - (smoothed.get(a) ?? 0));
2860
+ spot = chunkMWDW5UBW_cjs.nextSpotlight(spot, Object.fromEntries(smoothed), now, {
2861
+ exclude: list.filter((s) => s.local).map((s) => s.identity)
2862
+ });
2863
+ if (spot.id && !seen.has(spot.id)) spot = chunkMWDW5UBW_cjs.INITIAL_SPOTLIGHT;
2864
+ const prev = snapshot;
2865
+ const same = prev.spotlight === spot.id && prev.speaking.join("\n") === speaking.join("\n") && Object.keys(levels).length === Object.keys(prev.levels).length && Object.entries(levels).every(([k, v]) => prev.levels[k] === v);
2866
+ if (!same) publish({ levels, speaking, spotlight: spot.id });
2867
+ };
2868
+ const id = setInterval(tick, LEVEL_TICK_MS);
2869
+ return () => {
2870
+ clearInterval(id);
2871
+ for (const m of meters.values()) m.source.disconnect();
2872
+ meters.clear();
2873
+ void ctx?.close().catch(() => void 0);
2874
+ publish(EMPTY2);
2875
+ };
2876
+ }
2877
+ var RINGTONE_MUTED_KEY = "arbi-call-ringtone-muted";
2878
+ var RING_ON_S = 1.2;
2879
+ var RING_PERIOD_S = 4;
2880
+ var GAIN = 0.08;
2881
+ function audioContextCtor() {
2882
+ if (typeof window === "undefined") return null;
2883
+ return window.AudioContext ?? window.webkitAudioContext ?? null;
2884
+ }
2885
+ function startRingtone() {
2886
+ const Ctor = audioContextCtor();
2887
+ if (!Ctor) return () => {
2888
+ };
2889
+ let ctx;
2890
+ try {
2891
+ ctx = new Ctor();
2892
+ } catch {
2893
+ return () => {
2894
+ };
2895
+ }
2896
+ const out = ctx.createGain();
2897
+ out.gain.value = 0;
2898
+ out.connect(ctx.destination);
2899
+ const oscillators = [440, 480].map((frequency) => {
2900
+ const osc = ctx.createOscillator();
2901
+ osc.type = "sine";
2902
+ osc.frequency.value = frequency;
2903
+ osc.connect(out);
2904
+ osc.start();
2905
+ return osc;
2906
+ });
2907
+ let nextRingAt = ctx.currentTime + 0.05;
2908
+ const schedule = () => {
2909
+ while (nextRingAt < ctx.currentTime + RING_PERIOD_S * 2) {
2910
+ out.gain.setValueAtTime(0, nextRingAt);
2911
+ out.gain.linearRampToValueAtTime(GAIN, nextRingAt + 0.03);
2912
+ out.gain.setValueAtTime(GAIN, nextRingAt + RING_ON_S - 0.03);
2913
+ out.gain.linearRampToValueAtTime(0, nextRingAt + RING_ON_S);
2914
+ nextRingAt += RING_PERIOD_S;
2915
+ }
2916
+ };
2917
+ schedule();
2918
+ const timer = setInterval(schedule, 1e3);
2919
+ void ctx.resume().catch(() => {
2920
+ });
2921
+ let stopped = false;
2922
+ return () => {
2923
+ if (stopped) return;
2924
+ stopped = true;
2925
+ clearInterval(timer);
2926
+ for (const osc of oscillators) {
2927
+ try {
2928
+ osc.stop();
2929
+ } catch {
2930
+ }
2931
+ }
2932
+ void ctx.close().catch(() => {
2933
+ });
2934
+ };
2935
+ }
2936
+ function readMuted() {
2937
+ try {
2938
+ return localStorage.getItem(RINGTONE_MUTED_KEY) === "1";
2939
+ } catch {
2940
+ return false;
2941
+ }
2942
+ }
2943
+ function useRingtoneMuted() {
2944
+ const [muted, setMutedState] = react.useState(readMuted);
2945
+ const setMuted = react.useCallback((next) => {
2946
+ setMutedState(next);
2947
+ try {
2948
+ if (next) localStorage.setItem(RINGTONE_MUTED_KEY, "1");
2949
+ else localStorage.removeItem(RINGTONE_MUTED_KEY);
2950
+ } catch {
2951
+ }
2952
+ }, []);
2953
+ return [muted, setMuted];
2954
+ }
2955
+ function useRingtone(ringing, muted) {
2956
+ react.useEffect(() => {
2957
+ if (!ringing || muted) return;
2958
+ return startRingtone();
2959
+ }, [ringing, muted]);
2960
+ }
2961
+
2962
+ // src/calls/composite-canvas.ts
2963
+ var COMPOSITE_FPS = 15;
2964
+ var COMPOSITE_MAX_WIDTH = 1280;
2965
+ var COMPOSITE_MAX_HEIGHT = 720;
2966
+ function fitStage(stage, canvas) {
2967
+ if (stage.width <= 0 || stage.height <= 0) return { scale: 0, dx: 0, dy: 0 };
2968
+ const scale = Math.min(canvas.width / stage.width, canvas.height / stage.height);
2969
+ return {
2970
+ scale,
2971
+ dx: (canvas.width - stage.width * scale) / 2,
2972
+ dy: (canvas.height - stage.height * scale) / 2
2973
+ };
2974
+ }
2975
+ function fitMedia(src, box, mode) {
2976
+ const srcRatio = src.width / src.height;
2977
+ const boxRatio = box.width / box.height;
2978
+ if (mode === "contain") {
2979
+ const dw = srcRatio > boxRatio ? box.width : box.height * srcRatio;
2980
+ const dh = srcRatio > boxRatio ? box.width / srcRatio : box.height;
2981
+ return {
2982
+ sx: 0,
2983
+ sy: 0,
2984
+ sw: src.width,
2985
+ sh: src.height,
2986
+ dx: box.x + (box.width - dw) / 2,
2987
+ dy: box.y + (box.height - dh) / 2,
2988
+ dw,
2989
+ dh
2990
+ };
2991
+ }
2992
+ const sw = srcRatio > boxRatio ? src.height * boxRatio : src.width;
2993
+ const sh = srcRatio > boxRatio ? src.height : src.width / boxRatio;
2994
+ return {
2995
+ sx: (src.width - sw) / 2,
2996
+ sy: (src.height - sh) / 2,
2997
+ sw,
2998
+ sh,
2999
+ dx: box.x,
3000
+ dy: box.y,
3001
+ dw: box.width,
3002
+ dh: box.height
3003
+ };
3004
+ }
3005
+ function drawStageFrame(ctx, stage, width, height) {
3006
+ ctx.fillStyle = "#111";
3007
+ ctx.fillRect(0, 0, width, height);
3008
+ const stageRect = stage.getBoundingClientRect();
3009
+ const { scale, dx, dy } = fitStage(stageRect, { width, height });
3010
+ if (!scale) {
3011
+ ctx.fillStyle = "#bbb";
3012
+ ctx.font = "24px sans-serif";
3013
+ ctx.textAlign = "center";
3014
+ ctx.fillText("Video paused", width / 2, height / 2);
3015
+ ctx.textAlign = "start";
3016
+ return;
3017
+ }
3018
+ const tiles = Array.from(stage.querySelectorAll(".lk-participant-tile"));
3019
+ for (const tile of tiles) {
3020
+ const r = tile.getBoundingClientRect();
3021
+ if (r.width <= 0 || r.height <= 0) continue;
3022
+ const box = {
3023
+ x: dx + (r.left - stageRect.left) * scale,
3024
+ y: dy + (r.top - stageRect.top) * scale,
3025
+ width: r.width * scale,
3026
+ height: r.height * scale
3027
+ };
3028
+ ctx.fillStyle = "#222";
3029
+ ctx.fillRect(box.x, box.y, box.width, box.height);
3030
+ const video = tile.querySelector("video");
3031
+ if (video && video.readyState >= 2 && video.videoWidth > 0 && video.videoHeight > 0) {
3032
+ const screen = tile.getAttribute("data-lk-source") === "screen_share";
3033
+ const f = fitMedia(
3034
+ { width: video.videoWidth, height: video.videoHeight },
3035
+ box,
3036
+ screen ? "contain" : "cover"
3037
+ );
3038
+ try {
3039
+ ctx.drawImage(video, f.sx, f.sy, f.sw, f.sh, f.dx, f.dy, f.dw, f.dh);
3040
+ } catch {
3041
+ }
3042
+ }
3043
+ if (tile.getAttribute("data-lk-speaking") === "true") {
3044
+ ctx.strokeStyle = "#4ade80";
3045
+ ctx.lineWidth = 3;
3046
+ ctx.strokeRect(box.x + 1.5, box.y + 1.5, box.width - 3, box.height - 3);
3047
+ }
3048
+ const name = tile.querySelector(".lk-participant-name")?.textContent?.trim();
3049
+ if (name) {
3050
+ ctx.font = `${Math.max(11, Math.round(14 * Math.min(1, scale * 1.2)))}px sans-serif`;
3051
+ const w = ctx.measureText(name).width;
3052
+ ctx.fillStyle = "rgba(0,0,0,0.6)";
3053
+ ctx.fillRect(box.x + 6, box.y + box.height - 26, w + 12, 20);
3054
+ ctx.fillStyle = "#fff";
3055
+ ctx.fillText(name, box.x + 12, box.y + box.height - 11);
3056
+ }
3057
+ }
3058
+ }
3059
+ function startCompositeCapture(stage) {
3060
+ const canvas = document.createElement("canvas");
3061
+ canvas.width = COMPOSITE_MAX_WIDTH;
3062
+ canvas.height = COMPOSITE_MAX_HEIGHT;
3063
+ const ctx = canvas.getContext("2d");
3064
+ if (!ctx) throw new Error("This browser cannot draw the recording");
3065
+ const draw = () => drawStageFrame(ctx, stage, canvas.width, canvas.height);
3066
+ draw();
3067
+ const timer = setInterval(draw, Math.round(1e3 / COMPOSITE_FPS));
3068
+ const video = canvas.captureStream(COMPOSITE_FPS);
3069
+ const audio = new AudioContext();
3070
+ const destination = audio.createMediaStreamDestination();
3071
+ const sources = /* @__PURE__ */ new Map();
3072
+ const stream = new MediaStream([
3073
+ ...video.getVideoTracks(),
3074
+ ...destination.stream.getAudioTracks()
3075
+ ]);
3076
+ return {
3077
+ stream,
3078
+ setAudioTracks(tracks) {
3079
+ const wanted = new Map(tracks.map((t) => [t.id, t]));
3080
+ for (const [id, node] of sources) {
3081
+ if (!wanted.has(id)) {
3082
+ node.disconnect();
3083
+ sources.delete(id);
3084
+ }
3085
+ }
3086
+ for (const [id, track] of wanted) {
3087
+ if (sources.has(id) || track.readyState === "ended") continue;
3088
+ try {
3089
+ const node = audio.createMediaStreamSource(new MediaStream([track]));
3090
+ node.connect(destination);
3091
+ sources.set(id, node);
3092
+ } catch {
3093
+ }
3094
+ }
3095
+ if (audio.state === "suspended") void audio.resume().catch(() => void 0);
3096
+ },
3097
+ dispose() {
3098
+ clearInterval(timer);
3099
+ for (const node of sources.values()) node.disconnect();
3100
+ sources.clear();
3101
+ video.getTracks().forEach((t) => t.stop());
3102
+ void audio.close().catch(() => void 0);
3103
+ }
3104
+ };
3105
+ }
2751
3106
 
2752
3107
  Object.defineProperty(exports, "CAPTION_LINES", {
2753
3108
  enumerable: true,
@@ -2830,6 +3185,9 @@ Object.defineProperty(exports, "stageContentHeight", {
2830
3185
  get: function () { return chunkMWDW5UBW_cjs.stageContentHeight; }
2831
3186
  });
2832
3187
  exports.BackstageBanner = BackstageBanner;
3188
+ exports.COMPOSITE_FPS = COMPOSITE_FPS;
3189
+ exports.COMPOSITE_MAX_HEIGHT = COMPOSITE_MAX_HEIGHT;
3190
+ exports.COMPOSITE_MAX_WIDTH = COMPOSITE_MAX_WIDTH;
2833
3191
  exports.CallControlBar = CallControlBar;
2834
3192
  exports.CallControlButton = CallControlButton;
2835
3193
  exports.CallFocus = CallFocus;
@@ -2853,6 +3211,7 @@ exports.DEFAULT_JOIN_CHOICES = DEFAULT_JOIN_CHOICES;
2853
3211
  exports.ElapsedTime = ElapsedTime;
2854
3212
  exports.EncryptionStatusChip = EncryptionStatusChip;
2855
3213
  exports.IncomingCallCard = IncomingCallCard;
3214
+ exports.LEVEL_TICK_MS = LEVEL_TICK_MS;
2856
3215
  exports.LeaveButton = LeaveButton;
2857
3216
  exports.LobbyRequests = LobbyRequests;
2858
3217
  exports.MediaControl = MediaControl;
@@ -2862,6 +3221,7 @@ exports.OnStageCheck = OnStageCheck;
2862
3221
  exports.PanelComposer = PanelComposer;
2863
3222
  exports.PreJoin = PreJoin;
2864
3223
  exports.QAPanel = QAPanel;
3224
+ exports.RINGTONE_MUTED_KEY = RINGTONE_MUTED_KEY;
2865
3225
  exports.RaiseHandButton = RaiseHandButton;
2866
3226
  exports.RecordControl = RecordControl;
2867
3227
  exports.RecordingStatusChip = RecordingStatusChip;
@@ -2876,9 +3236,22 @@ exports.WebinarViewer = WebinarViewer;
2876
3236
  exports.WebinarWaiting = WebinarWaiting;
2877
3237
  exports.chatPermissionSection = chatPermissionSection;
2878
3238
  exports.describeMediaError = describeMediaError;
3239
+ exports.drawStageFrame = drawStageFrame;
3240
+ exports.fitMedia = fitMedia;
3241
+ exports.fitStage = fitStage;
2879
3242
  exports.sortQuestions = sortQuestions;
3243
+ exports.startCompositeCapture = startCompositeCapture;
3244
+ exports.startRingtone = startRingtone;
3245
+ exports.startVoiceLevels = startVoiceLevels;
2880
3246
  exports.useBriefNotice = useBriefNotice;
2881
3247
  exports.useElementSize = useElementSize;
3248
+ exports.useIsSpeaking = useIsSpeaking;
3249
+ exports.useRingtone = useRingtone;
3250
+ exports.useRingtoneMuted = useRingtoneMuted;
2882
3251
  exports.useShortcutKeys = useShortcutKeys;
3252
+ exports.useSpeakingIds = useSpeakingIds;
3253
+ exports.useSpotlightId = useSpotlightId;
3254
+ exports.useVoiceLevel = useVoiceLevel;
3255
+ exports.useVoiceLevels = useVoiceLevels;
2883
3256
  //# sourceMappingURL=index.cjs.map
2884
3257
  //# sourceMappingURL=index.cjs.map