@signalwire/web-components 4.0.0-beta.2 → 4.0.0-beta.4
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.
- package/README.md +3 -1
- package/dist/components/audio-level.d.ts +106 -0
- package/dist/components/audio-level.d.ts.map +1 -0
- package/dist/components/audio-level.js +203 -0
- package/dist/components/audio-level.js.map +1 -0
- package/dist/components/call-controls.d.ts +163 -0
- package/dist/components/call-controls.d.ts.map +1 -0
- package/dist/components/call-controls.js +606 -0
- package/dist/components/call-controls.js.map +1 -0
- package/dist/components/call-media.d.ts +114 -0
- package/dist/components/call-media.d.ts.map +1 -0
- package/dist/components/call-media.js +215 -0
- package/dist/components/call-media.js.map +1 -0
- package/dist/components/call-status.d.ts +71 -0
- package/dist/components/call-status.d.ts.map +1 -0
- package/dist/components/call-status.js +251 -0
- package/dist/components/call-status.js.map +1 -0
- package/dist/components/click-to-call.d.ts +123 -0
- package/dist/components/click-to-call.d.ts.map +1 -0
- package/dist/components/click-to-call.js +428 -0
- package/dist/components/click-to-call.js.map +1 -0
- package/dist/components/device-selector.d.ts +250 -0
- package/dist/components/device-selector.d.ts.map +1 -0
- package/dist/components/device-selector.js +685 -0
- package/dist/components/device-selector.js.map +1 -0
- package/dist/components/dialpad.d.ts +60 -0
- package/dist/components/dialpad.d.ts.map +1 -0
- package/dist/components/dialpad.js +372 -0
- package/dist/components/dialpad.js.map +1 -0
- package/dist/components/directory.d.ts +103 -0
- package/dist/components/directory.d.ts.map +1 -0
- package/dist/components/directory.js +503 -0
- package/dist/components/directory.js.map +1 -0
- package/dist/components/example-button.d.ts +20 -0
- package/dist/components/example-button.d.ts.map +1 -0
- package/dist/components/example-button.js +74 -0
- package/dist/components/example-button.js.map +1 -0
- package/dist/components/participant-controls.d.ts +94 -0
- package/dist/components/participant-controls.d.ts.map +1 -0
- package/dist/components/participant-controls.js +468 -0
- package/dist/components/participant-controls.js.map +1 -0
- package/dist/components/participants.d.ts +116 -0
- package/dist/components/participants.d.ts.map +1 -0
- package/dist/components/participants.js +394 -0
- package/dist/components/participants.js.map +1 -0
- package/dist/components/self-media.d.ts +78 -0
- package/dist/components/self-media.d.ts.map +1 -0
- package/dist/components/self-media.js +128 -0
- package/dist/components/self-media.js.map +1 -0
- package/dist/context/call-context.d.ts +13 -0
- package/dist/context/call-context.d.ts.map +1 -0
- package/dist/context/call-context.js +6 -0
- package/dist/context/call-context.js.map +1 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -5645
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +101 -0
- package/dist/types/index.d.ts +67 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/debounce.d.ts +10 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/debounce.js +13 -0
- package/dist/utils/debounce.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/video.d.ts +34 -0
- package/dist/utils/video.d.ts.map +1 -0
- package/dist/utils/video.js +26 -0
- package/dist/utils/video.js.map +1 -0
- package/package.json +70 -3
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import { LitElement as b, html as n, nothing as v, css as f } from "lit";
|
|
2
|
+
import { property as h, state as u, customElement as w } from "lit/decorators.js";
|
|
3
|
+
import { consume as m } from "@lit/context";
|
|
4
|
+
import { of as g } from "rxjs";
|
|
5
|
+
import { filter as x, switchMap as d } from "rxjs/operators";
|
|
6
|
+
import { callContext as S } from "../context/call-context.js";
|
|
7
|
+
var y = Object.defineProperty, C = Object.getOwnPropertyDescriptor, c = (t, e, s, r) => {
|
|
8
|
+
for (var i = r > 1 ? void 0 : r ? C(e, s) : e, o = t.length - 1, l; o >= 0; o--)
|
|
9
|
+
(l = t[o]) && (i = (r ? l(e, s, i) : l(i)) || i);
|
|
10
|
+
return r && i && y(e, s, i), i;
|
|
11
|
+
};
|
|
12
|
+
let a = class extends b {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments), this.orientation = "horizontal", this.showTooltips = !0, this._audioMuted = !1, this._videoMuted = !1, this._screenShareStatus = "inactive", this._capabilities = [], this._overflowOpen = !1, this.subscriptions = [];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the effective call (property or context)
|
|
18
|
+
*/
|
|
19
|
+
get effectiveCall() {
|
|
20
|
+
return this.call || this._contextCall;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Lifecycle: Component connected to DOM
|
|
24
|
+
*/
|
|
25
|
+
connectedCallback() {
|
|
26
|
+
super.connectedCallback(), this.setupSubscriptions();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Lifecycle: React to property changes
|
|
30
|
+
*/
|
|
31
|
+
updated(t) {
|
|
32
|
+
super.updated(t), (t.has("call") || t.has("_contextCall")) && (this.cleanupSubscriptions(), this.setupSubscriptions());
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Lifecycle: Component disconnected from DOM
|
|
36
|
+
*/
|
|
37
|
+
disconnectedCallback() {
|
|
38
|
+
super.disconnectedCallback(), this.cleanupSubscriptions();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to call observables
|
|
42
|
+
*/
|
|
43
|
+
setupSubscriptions() {
|
|
44
|
+
const t = this.effectiveCall;
|
|
45
|
+
if (t) {
|
|
46
|
+
if (t.self$) {
|
|
47
|
+
const e = t.self$.pipe(
|
|
48
|
+
x((o) => o !== null)
|
|
49
|
+
), s = e.pipe(
|
|
50
|
+
d((o) => (this.selfParticipant = o, o.audioMuted$))
|
|
51
|
+
).subscribe((o) => {
|
|
52
|
+
this._audioMuted = o;
|
|
53
|
+
});
|
|
54
|
+
this.subscriptions.push(s);
|
|
55
|
+
const r = e.pipe(d((o) => o.videoMuted$)).subscribe((o) => {
|
|
56
|
+
this._videoMuted = o;
|
|
57
|
+
});
|
|
58
|
+
this.subscriptions.push(r);
|
|
59
|
+
const i = e.pipe(d((o) => o.screenShareStatus$ ?? g("inactive"))).subscribe((o) => {
|
|
60
|
+
this._screenShareStatus = o;
|
|
61
|
+
});
|
|
62
|
+
this.subscriptions.push(i);
|
|
63
|
+
} else t.self && (this.selfParticipant = t.self, t.self.audioMuted$ && this.subscriptions.push(
|
|
64
|
+
t.self.audioMuted$.subscribe((e) => {
|
|
65
|
+
this._audioMuted = e;
|
|
66
|
+
})
|
|
67
|
+
), t.self.videoMuted$ && this.subscriptions.push(
|
|
68
|
+
t.self.videoMuted$.subscribe((e) => {
|
|
69
|
+
this._videoMuted = e;
|
|
70
|
+
})
|
|
71
|
+
), t.self.screenShareStatus$ && this.subscriptions.push(
|
|
72
|
+
t.self.screenShareStatus$.subscribe((e) => {
|
|
73
|
+
this._screenShareStatus = e;
|
|
74
|
+
})
|
|
75
|
+
));
|
|
76
|
+
t.capabilities$ && this.subscriptions.push(
|
|
77
|
+
t.capabilities$.subscribe((e) => {
|
|
78
|
+
this._capabilities = e;
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Cleanup all subscriptions
|
|
85
|
+
*/
|
|
86
|
+
cleanupSubscriptions() {
|
|
87
|
+
this.subscriptions.forEach((t) => t.unsubscribe()), this.subscriptions = [], this.selfParticipant = void 0;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if capability is available
|
|
91
|
+
*/
|
|
92
|
+
hasCapability(t) {
|
|
93
|
+
return !this._capabilities || this._capabilities.length === 0 ? !0 : this._capabilities.includes(t);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Handle mute audio toggle
|
|
97
|
+
*/
|
|
98
|
+
async handleMuteAudio() {
|
|
99
|
+
var s;
|
|
100
|
+
const t = this.selfParticipant ?? ((s = this.effectiveCall) == null ? void 0 : s.self);
|
|
101
|
+
if (!t) return;
|
|
102
|
+
const e = !this._audioMuted;
|
|
103
|
+
try {
|
|
104
|
+
this._audioMuted ? await t.unmute() : await t.mute(), this.dispatchEvent(
|
|
105
|
+
new CustomEvent("sw-mute-audio", {
|
|
106
|
+
detail: { muted: e },
|
|
107
|
+
bubbles: !0,
|
|
108
|
+
composed: !0
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
} catch (r) {
|
|
112
|
+
console.error("Failed to toggle audio mute:", r);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Handle mute video toggle
|
|
117
|
+
*/
|
|
118
|
+
async handleMuteVideo() {
|
|
119
|
+
var s;
|
|
120
|
+
const t = this.selfParticipant ?? ((s = this.effectiveCall) == null ? void 0 : s.self);
|
|
121
|
+
if (!t) return;
|
|
122
|
+
const e = !this._videoMuted;
|
|
123
|
+
try {
|
|
124
|
+
this._videoMuted ? await t.unmuteVideo() : await t.muteVideo(), this.dispatchEvent(
|
|
125
|
+
new CustomEvent("sw-mute-video", {
|
|
126
|
+
detail: { muted: e },
|
|
127
|
+
bubbles: !0,
|
|
128
|
+
composed: !0
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
} catch (r) {
|
|
132
|
+
console.error("Failed to toggle video mute:", r);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Handle screen share toggle
|
|
137
|
+
*/
|
|
138
|
+
async handleScreenShare() {
|
|
139
|
+
var s, r, i;
|
|
140
|
+
const t = this.selfParticipant ?? ((s = this.effectiveCall) == null ? void 0 : s.self);
|
|
141
|
+
if (!t) return;
|
|
142
|
+
const e = this._screenShareStatus !== "active";
|
|
143
|
+
try {
|
|
144
|
+
this._screenShareStatus === "active" ? await ((r = t.stopScreenShare) == null ? void 0 : r.call(t)) : await ((i = t.startScreenShare) == null ? void 0 : i.call(t)), this.dispatchEvent(
|
|
145
|
+
new CustomEvent("sw-screen-share", {
|
|
146
|
+
detail: { active: e },
|
|
147
|
+
bubbles: !0,
|
|
148
|
+
composed: !0
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
} catch (o) {
|
|
152
|
+
console.error("Failed to toggle screen share:", o);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Handle hangup
|
|
157
|
+
*/
|
|
158
|
+
async handleHangup() {
|
|
159
|
+
const t = this.effectiveCall;
|
|
160
|
+
if (t)
|
|
161
|
+
try {
|
|
162
|
+
await t.hangup(), this.dispatchEvent(
|
|
163
|
+
new CustomEvent("sw-hangup", {
|
|
164
|
+
bubbles: !0,
|
|
165
|
+
composed: !0
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error("Failed to hangup:", e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Toggle overflow menu
|
|
174
|
+
*/
|
|
175
|
+
toggleOverflow() {
|
|
176
|
+
this._overflowOpen = !this._overflowOpen;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get tooltip text for button
|
|
180
|
+
*/
|
|
181
|
+
getTooltipText(t) {
|
|
182
|
+
switch (t) {
|
|
183
|
+
case "mute-audio":
|
|
184
|
+
return this._audioMuted ? "Unmute Audio" : "Mute Audio";
|
|
185
|
+
case "mute-video":
|
|
186
|
+
return this._videoMuted ? "Turn On Camera" : "Turn Off Camera";
|
|
187
|
+
case "screen-share":
|
|
188
|
+
return this._screenShareStatus === "active" ? "Stop Sharing" : "Share Screen";
|
|
189
|
+
case "hangup":
|
|
190
|
+
return "End Call";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Render button icon
|
|
195
|
+
*/
|
|
196
|
+
renderIcon(t) {
|
|
197
|
+
switch (t) {
|
|
198
|
+
case "mute-audio":
|
|
199
|
+
return this._audioMuted ? n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
200
|
+
<path
|
|
201
|
+
d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"
|
|
202
|
+
/>
|
|
203
|
+
</svg>` : n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
204
|
+
<path
|
|
205
|
+
d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.91-3c-.49 0-.9.36-.98.85C16.52 14.2 14.47 16 12 16s-4.52-1.8-4.93-4.15c-.08-.49-.49-.85-.98-.85-.61 0-1.09.54-1 1.14.49 3 2.89 5.35 5.91 5.78V20c0 .55.45 1 1 1s1-.45 1-1v-2.08c3.02-.43 5.42-2.78 5.91-5.78.1-.6-.39-1.14-1-1.14z"
|
|
206
|
+
/>
|
|
207
|
+
</svg>`;
|
|
208
|
+
case "mute-video":
|
|
209
|
+
return this._videoMuted ? n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
210
|
+
<path
|
|
211
|
+
d="M21 6.5l-4 4V7c0-.55-.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.21 0 .39-.08.54-.18L19.73 21 21 19.73 3.27 2z"
|
|
212
|
+
/>
|
|
213
|
+
</svg>` : n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
214
|
+
<path
|
|
215
|
+
d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"
|
|
216
|
+
/>
|
|
217
|
+
</svg>`;
|
|
218
|
+
case "screen-share":
|
|
219
|
+
return this._screenShareStatus === "active" ? n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
220
|
+
<path
|
|
221
|
+
d="M21.22 18.02l2 2H24v-2h-2.78zm.77-2l.01-10c0-1.11-.9-2-2-2H7.22l5.23 5.23c.18-.04.36-.07.55-.1V7.02l4 3.73-1.58 1.47 5.54 5.54c.61-.33 1.03-.99 1.03-1.74zM2.39 1.73L1.11 3l1.54 1.54c-.4.36-.65.89-.65 1.48v10c0 1.1.89 2 2 2H0v2h18.13l2.71 2.71 1.27-1.27L2.39 1.73zM7 15.02c.31-1.48.92-2.95 2.07-4.06l1.59 1.59c-1.54.38-2.7 1.18-3.66 2.47z"
|
|
222
|
+
/>
|
|
223
|
+
</svg>` : n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
224
|
+
<path
|
|
225
|
+
d="M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6zm9 9v-4h3l-4-4-4 4h3v4h2z"
|
|
226
|
+
/>
|
|
227
|
+
</svg>`;
|
|
228
|
+
case "hangup":
|
|
229
|
+
return n`<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
230
|
+
<path
|
|
231
|
+
d="M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08c-.18-.17-.29-.42-.29-.7 0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z"
|
|
232
|
+
/>
|
|
233
|
+
</svg>`;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Render a control button
|
|
238
|
+
*/
|
|
239
|
+
renderButton(t, e) {
|
|
240
|
+
const { onClick: s, active: r = !1, disabled: i = !1, className: o = "" } = e, l = this.getTooltipText(t);
|
|
241
|
+
return n`
|
|
242
|
+
<button
|
|
243
|
+
class="control-button ${t} ${r ? "active" : ""} ${o}"
|
|
244
|
+
part="button ${r ? "button-active" : ""} ${i ? "button-disabled" : ""}"
|
|
245
|
+
aria-label="${l}"
|
|
246
|
+
aria-pressed="${t !== "hangup" ? r : v}"
|
|
247
|
+
?disabled=${i}
|
|
248
|
+
@click=${s}
|
|
249
|
+
>
|
|
250
|
+
${this.renderIcon(t)}
|
|
251
|
+
${this.showTooltips ? n` <span class="tooltip" part="tooltip">${l}</span> ` : v}
|
|
252
|
+
</button>
|
|
253
|
+
`;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Render the component
|
|
257
|
+
*/
|
|
258
|
+
render() {
|
|
259
|
+
var l, p;
|
|
260
|
+
const t = this.effectiveCall, e = !!(this.selfParticipant ?? (t == null ? void 0 : t.self)), s = this.hasCapability("self"), r = s || this.hasCapability("selfMuteAudio") || this.hasCapability("muteAudio"), i = s || this.hasCapability("vmuted") || this.hasCapability("selfMuteVideo") || this.hasCapability("muteVideo"), o = (this.hasCapability("screenshare") || this.hasCapability("screenShare")) && !!(((l = this.selfParticipant) == null ? void 0 : l.startScreenShare) ?? ((p = t == null ? void 0 : t.self) == null ? void 0 : p.startScreenShare));
|
|
261
|
+
return n`
|
|
262
|
+
<div
|
|
263
|
+
class="container ${this.orientation === "vertical" ? "vertical" : ""}"
|
|
264
|
+
part="container"
|
|
265
|
+
role="toolbar"
|
|
266
|
+
aria-label="Call controls"
|
|
267
|
+
>
|
|
268
|
+
${this.renderButton("mute-audio", {
|
|
269
|
+
onClick: () => this.handleMuteAudio(),
|
|
270
|
+
active: this._audioMuted,
|
|
271
|
+
disabled: !e || !r
|
|
272
|
+
})}
|
|
273
|
+
${this.renderButton("mute-video", {
|
|
274
|
+
onClick: () => this.handleMuteVideo(),
|
|
275
|
+
active: this._videoMuted,
|
|
276
|
+
disabled: !e || !i
|
|
277
|
+
})}
|
|
278
|
+
${this.renderButton("screen-share", {
|
|
279
|
+
onClick: () => this.handleScreenShare(),
|
|
280
|
+
active: this._screenShareStatus === "active",
|
|
281
|
+
disabled: !e || !o
|
|
282
|
+
})}
|
|
283
|
+
${this.renderButton("hangup", {
|
|
284
|
+
onClick: () => this.handleHangup(),
|
|
285
|
+
disabled: !t || !1,
|
|
286
|
+
className: "hangup"
|
|
287
|
+
})}
|
|
288
|
+
|
|
289
|
+
<!-- Overflow menu for responsive collapse -->
|
|
290
|
+
<div class="overflow-menu ${this._overflowOpen ? "open" : ""}">
|
|
291
|
+
<button
|
|
292
|
+
class="control-button overflow-button"
|
|
293
|
+
aria-label="More options"
|
|
294
|
+
aria-expanded="${this._overflowOpen}"
|
|
295
|
+
@click=${this.toggleOverflow}
|
|
296
|
+
>
|
|
297
|
+
<svg class="button-icon" viewBox="0 0 24 24" fill="currentColor">
|
|
298
|
+
<path
|
|
299
|
+
d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
|
300
|
+
/>
|
|
301
|
+
</svg>
|
|
302
|
+
</button>
|
|
303
|
+
<div class="overflow-content">
|
|
304
|
+
${this.renderButton("mute-audio", {
|
|
305
|
+
onClick: () => this.handleMuteAudio(),
|
|
306
|
+
active: this._audioMuted,
|
|
307
|
+
disabled: !e || !r
|
|
308
|
+
})}
|
|
309
|
+
${this.renderButton("mute-video", {
|
|
310
|
+
onClick: () => this.handleMuteVideo(),
|
|
311
|
+
active: this._videoMuted,
|
|
312
|
+
disabled: !e || !i
|
|
313
|
+
})}
|
|
314
|
+
${this.renderButton("screen-share", {
|
|
315
|
+
onClick: () => this.handleScreenShare(),
|
|
316
|
+
active: this._screenShareStatus === "active",
|
|
317
|
+
disabled: !e || !o
|
|
318
|
+
})}
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
`;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
a.styles = f`
|
|
326
|
+
:host {
|
|
327
|
+
/* CSS Custom Properties for theming */
|
|
328
|
+
--sw-color-primary: #044cf6;
|
|
329
|
+
--sw-color-primary-hover: #0339c4;
|
|
330
|
+
--sw-color-danger: #ef4444;
|
|
331
|
+
--sw-color-danger-hover: #dc2626;
|
|
332
|
+
--sw-color-background: #1a1a1a;
|
|
333
|
+
--sw-color-surface: #2a2a2a;
|
|
334
|
+
--sw-color-surface-hover: #3a3a3a;
|
|
335
|
+
--sw-color-text: #ffffff;
|
|
336
|
+
--sw-color-text-muted: #a0a0a0;
|
|
337
|
+
--sw-color-border: #404040;
|
|
338
|
+
--sw-color-active: #ef4444;
|
|
339
|
+
--sw-border-radius: 8px;
|
|
340
|
+
--sw-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
341
|
+
--sw-space-1: 4px;
|
|
342
|
+
--sw-space-2: 8px;
|
|
343
|
+
--sw-space-3: 12px;
|
|
344
|
+
--sw-space-4: 16px;
|
|
345
|
+
--sw-space-6: 24px;
|
|
346
|
+
|
|
347
|
+
display: block;
|
|
348
|
+
font-family: var(--sw-font-family);
|
|
349
|
+
color: var(--sw-color-text);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.container {
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
justify-content: center;
|
|
356
|
+
gap: var(--sw-space-3);
|
|
357
|
+
padding: var(--sw-space-3);
|
|
358
|
+
background: var(--sw-color-background);
|
|
359
|
+
border-radius: var(--sw-border-radius);
|
|
360
|
+
flex-wrap: wrap;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.container.vertical {
|
|
364
|
+
flex-direction: column;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.control-button {
|
|
368
|
+
position: relative;
|
|
369
|
+
display: flex;
|
|
370
|
+
align-items: center;
|
|
371
|
+
justify-content: center;
|
|
372
|
+
width: 48px;
|
|
373
|
+
height: 48px;
|
|
374
|
+
min-width: 44px;
|
|
375
|
+
min-height: 44px;
|
|
376
|
+
padding: 0;
|
|
377
|
+
background: var(--sw-color-surface);
|
|
378
|
+
border: 1px solid var(--sw-color-border);
|
|
379
|
+
border-radius: 50%;
|
|
380
|
+
color: var(--sw-color-text);
|
|
381
|
+
cursor: pointer;
|
|
382
|
+
transition:
|
|
383
|
+
background-color 0.2s ease,
|
|
384
|
+
border-color 0.2s ease,
|
|
385
|
+
transform 0.1s ease;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.control-button:hover:not(:disabled) {
|
|
389
|
+
background: var(--sw-color-surface-hover);
|
|
390
|
+
border-color: var(--sw-color-text-muted);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.control-button:focus {
|
|
394
|
+
outline: none;
|
|
395
|
+
box-shadow:
|
|
396
|
+
0 0 0 2px var(--sw-color-background),
|
|
397
|
+
0 0 0 4px var(--sw-color-primary);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.control-button:focus-visible {
|
|
401
|
+
outline: 2px solid var(--sw-color-primary);
|
|
402
|
+
outline-offset: 2px;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.control-button:active:not(:disabled) {
|
|
406
|
+
transform: scale(0.95);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.control-button:disabled {
|
|
410
|
+
opacity: 0.4;
|
|
411
|
+
cursor: not-allowed;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.control-button.active {
|
|
415
|
+
background: var(--sw-color-active);
|
|
416
|
+
border-color: var(--sw-color-active);
|
|
417
|
+
color: white;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.control-button.active:hover:not(:disabled) {
|
|
421
|
+
background: var(--sw-color-danger-hover);
|
|
422
|
+
border-color: var(--sw-color-danger-hover);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.control-button.hangup {
|
|
426
|
+
background: var(--sw-color-danger);
|
|
427
|
+
border-color: var(--sw-color-danger);
|
|
428
|
+
color: white;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.control-button.hangup:hover:not(:disabled) {
|
|
432
|
+
background: var(--sw-color-danger-hover);
|
|
433
|
+
border-color: var(--sw-color-danger-hover);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.control-button.screen-share.active {
|
|
437
|
+
background: var(--sw-color-primary);
|
|
438
|
+
border-color: var(--sw-color-primary);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.control-button.screen-share.active:hover:not(:disabled) {
|
|
442
|
+
background: var(--sw-color-primary-hover);
|
|
443
|
+
border-color: var(--sw-color-primary-hover);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.button-icon {
|
|
447
|
+
width: 24px;
|
|
448
|
+
height: 24px;
|
|
449
|
+
flex-shrink: 0;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.tooltip {
|
|
453
|
+
position: absolute;
|
|
454
|
+
bottom: calc(100% + 8px);
|
|
455
|
+
left: 50%;
|
|
456
|
+
transform: translateX(-50%);
|
|
457
|
+
padding: var(--sw-space-1) var(--sw-space-2);
|
|
458
|
+
background: var(--sw-color-surface);
|
|
459
|
+
border: 1px solid var(--sw-color-border);
|
|
460
|
+
border-radius: 4px;
|
|
461
|
+
font-size: 12px;
|
|
462
|
+
white-space: nowrap;
|
|
463
|
+
opacity: 0;
|
|
464
|
+
visibility: hidden;
|
|
465
|
+
transition:
|
|
466
|
+
opacity 0.2s ease,
|
|
467
|
+
visibility 0.2s ease;
|
|
468
|
+
pointer-events: none;
|
|
469
|
+
z-index: 10;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.tooltip::after {
|
|
473
|
+
content: '';
|
|
474
|
+
position: absolute;
|
|
475
|
+
top: 100%;
|
|
476
|
+
left: 50%;
|
|
477
|
+
transform: translateX(-50%);
|
|
478
|
+
border: 6px solid transparent;
|
|
479
|
+
border-top-color: var(--sw-color-border);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.control-button:hover .tooltip,
|
|
483
|
+
.control-button:focus .tooltip {
|
|
484
|
+
opacity: 1;
|
|
485
|
+
visibility: visible;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* Vertical orientation tooltip positioning */
|
|
489
|
+
.container.vertical .tooltip {
|
|
490
|
+
bottom: auto;
|
|
491
|
+
left: calc(100% + 8px);
|
|
492
|
+
top: 50%;
|
|
493
|
+
transform: translateY(-50%);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.container.vertical .tooltip::after {
|
|
497
|
+
top: 50%;
|
|
498
|
+
left: auto;
|
|
499
|
+
right: 100%;
|
|
500
|
+
transform: translateY(-50%);
|
|
501
|
+
border: 6px solid transparent;
|
|
502
|
+
border-right-color: var(--sw-color-border);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* Overflow menu for responsive collapse */
|
|
506
|
+
.overflow-menu {
|
|
507
|
+
position: relative;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.overflow-button {
|
|
511
|
+
display: none;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.overflow-content {
|
|
515
|
+
display: none;
|
|
516
|
+
position: absolute;
|
|
517
|
+
bottom: calc(100% + 8px);
|
|
518
|
+
right: 0;
|
|
519
|
+
background: var(--sw-color-background);
|
|
520
|
+
border: 1px solid var(--sw-color-border);
|
|
521
|
+
border-radius: var(--sw-border-radius);
|
|
522
|
+
padding: var(--sw-space-2);
|
|
523
|
+
gap: var(--sw-space-2);
|
|
524
|
+
flex-direction: column;
|
|
525
|
+
z-index: 20;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.overflow-menu.open .overflow-content {
|
|
529
|
+
display: flex;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/* Responsive collapse at small widths */
|
|
533
|
+
@media (max-width: 320px) {
|
|
534
|
+
.container:not(.vertical) > .control-button:not(.hangup):not(.overflow-button) {
|
|
535
|
+
display: none;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.container:not(.vertical) .overflow-button {
|
|
539
|
+
display: flex;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* Ensure overflow content buttons remain visible when menu is open */
|
|
543
|
+
.container:not(.vertical) .overflow-content .control-button {
|
|
544
|
+
display: flex;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* Dark mode adjustments */
|
|
549
|
+
@media (prefers-color-scheme: light) {
|
|
550
|
+
:host {
|
|
551
|
+
--sw-color-background: #ffffff;
|
|
552
|
+
--sw-color-surface: #f5f5f5;
|
|
553
|
+
--sw-color-surface-hover: #e5e5e5;
|
|
554
|
+
--sw-color-text: #1a1a1a;
|
|
555
|
+
--sw-color-text-muted: #666666;
|
|
556
|
+
--sw-color-border: #d4d4d4;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
:host([data-theme='light']) {
|
|
561
|
+
--sw-color-background: #ffffff;
|
|
562
|
+
--sw-color-surface: #f5f5f5;
|
|
563
|
+
--sw-color-surface-hover: #e5e5e5;
|
|
564
|
+
--sw-color-text: #1a1a1a;
|
|
565
|
+
--sw-color-text-muted: #666666;
|
|
566
|
+
--sw-color-border: #d4d4d4;
|
|
567
|
+
}
|
|
568
|
+
`;
|
|
569
|
+
c([
|
|
570
|
+
h({ type: Object })
|
|
571
|
+
], a.prototype, "call", 2);
|
|
572
|
+
c([
|
|
573
|
+
m({ context: S, subscribe: !0 }),
|
|
574
|
+
u()
|
|
575
|
+
], a.prototype, "_contextCall", 2);
|
|
576
|
+
c([
|
|
577
|
+
h({ type: String })
|
|
578
|
+
], a.prototype, "orientation", 2);
|
|
579
|
+
c([
|
|
580
|
+
h({ type: Boolean, attribute: "show-tooltips" })
|
|
581
|
+
], a.prototype, "showTooltips", 2);
|
|
582
|
+
c([
|
|
583
|
+
u()
|
|
584
|
+
], a.prototype, "_audioMuted", 2);
|
|
585
|
+
c([
|
|
586
|
+
u()
|
|
587
|
+
], a.prototype, "_videoMuted", 2);
|
|
588
|
+
c([
|
|
589
|
+
u()
|
|
590
|
+
], a.prototype, "_screenShareStatus", 2);
|
|
591
|
+
c([
|
|
592
|
+
u()
|
|
593
|
+
], a.prototype, "_capabilities", 2);
|
|
594
|
+
c([
|
|
595
|
+
u()
|
|
596
|
+
], a.prototype, "_overflowOpen", 2);
|
|
597
|
+
c([
|
|
598
|
+
u()
|
|
599
|
+
], a.prototype, "selfParticipant", 2);
|
|
600
|
+
a = c([
|
|
601
|
+
w("sw-call-controls")
|
|
602
|
+
], a);
|
|
603
|
+
export {
|
|
604
|
+
a as CallControls
|
|
605
|
+
};
|
|
606
|
+
//# sourceMappingURL=call-controls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-controls.js","sources":["../../src/components/call-controls.ts"],"sourcesContent":["/**\n * Call Controls Component\n *\n * Responsive button bar for call actions. Displays mute audio, mute video,\n * screen share, and hangup buttons with states reflecting current call state.\n *\n * @example\n * ```html\n * <sw-call-controls .call=${call}></sw-call-controls>\n * ```\n */\n\nimport { LitElement, html, css, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\nimport { Subscription, of } from 'rxjs';\nimport { switchMap, filter } from 'rxjs/operators';\nimport type { Observable } from 'rxjs';\nimport { callContext } from '../context/index.js';\n\n/**\n * Screen share status type\n */\nexport type ScreenShareStatus = 'inactive' | 'pending' | 'active';\n\n/**\n * SelfParticipant interface for call controls\n */\nexport interface SelfParticipant {\n id: string;\n audioMuted$: Observable<boolean>;\n videoMuted$: Observable<boolean>;\n screenShareStatus$?: Observable<string>;\n mute: () => Promise<void>;\n unmute: () => Promise<void>;\n muteVideo: () => Promise<void>;\n unmuteVideo: () => Promise<void>;\n startScreenShare?: () => Promise<void>;\n stopScreenShare?: () => Promise<void>;\n}\n\n/**\n * Call interface for call controls\n */\nexport interface CallControlsCall {\n self?: SelfParticipant | null;\n self$?: Observable<SelfParticipant | null>;\n capabilities$?: Observable<string[]>;\n hangup: () => Promise<void>;\n}\n\n/**\n * Button type for controls\n */\ntype ControlButtonType = 'mute-audio' | 'mute-video' | 'screen-share' | 'hangup';\n\n@customElement('sw-call-controls')\nexport class CallControls extends LitElement {\n static styles = css`\n :host {\n /* CSS Custom Properties for theming */\n --sw-color-primary: #044cf6;\n --sw-color-primary-hover: #0339c4;\n --sw-color-danger: #ef4444;\n --sw-color-danger-hover: #dc2626;\n --sw-color-background: #1a1a1a;\n --sw-color-surface: #2a2a2a;\n --sw-color-surface-hover: #3a3a3a;\n --sw-color-text: #ffffff;\n --sw-color-text-muted: #a0a0a0;\n --sw-color-border: #404040;\n --sw-color-active: #ef4444;\n --sw-border-radius: 8px;\n --sw-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n --sw-space-1: 4px;\n --sw-space-2: 8px;\n --sw-space-3: 12px;\n --sw-space-4: 16px;\n --sw-space-6: 24px;\n\n display: block;\n font-family: var(--sw-font-family);\n color: var(--sw-color-text);\n }\n\n .container {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--sw-space-3);\n padding: var(--sw-space-3);\n background: var(--sw-color-background);\n border-radius: var(--sw-border-radius);\n flex-wrap: wrap;\n }\n\n .container.vertical {\n flex-direction: column;\n }\n\n .control-button {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n min-width: 44px;\n min-height: 44px;\n padding: 0;\n background: var(--sw-color-surface);\n border: 1px solid var(--sw-color-border);\n border-radius: 50%;\n color: var(--sw-color-text);\n cursor: pointer;\n transition:\n background-color 0.2s ease,\n border-color 0.2s ease,\n transform 0.1s ease;\n }\n\n .control-button:hover:not(:disabled) {\n background: var(--sw-color-surface-hover);\n border-color: var(--sw-color-text-muted);\n }\n\n .control-button:focus {\n outline: none;\n box-shadow:\n 0 0 0 2px var(--sw-color-background),\n 0 0 0 4px var(--sw-color-primary);\n }\n\n .control-button:focus-visible {\n outline: 2px solid var(--sw-color-primary);\n outline-offset: 2px;\n }\n\n .control-button:active:not(:disabled) {\n transform: scale(0.95);\n }\n\n .control-button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .control-button.active {\n background: var(--sw-color-active);\n border-color: var(--sw-color-active);\n color: white;\n }\n\n .control-button.active:hover:not(:disabled) {\n background: var(--sw-color-danger-hover);\n border-color: var(--sw-color-danger-hover);\n }\n\n .control-button.hangup {\n background: var(--sw-color-danger);\n border-color: var(--sw-color-danger);\n color: white;\n }\n\n .control-button.hangup:hover:not(:disabled) {\n background: var(--sw-color-danger-hover);\n border-color: var(--sw-color-danger-hover);\n }\n\n .control-button.screen-share.active {\n background: var(--sw-color-primary);\n border-color: var(--sw-color-primary);\n }\n\n .control-button.screen-share.active:hover:not(:disabled) {\n background: var(--sw-color-primary-hover);\n border-color: var(--sw-color-primary-hover);\n }\n\n .button-icon {\n width: 24px;\n height: 24px;\n flex-shrink: 0;\n }\n\n .tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n padding: var(--sw-space-1) var(--sw-space-2);\n background: var(--sw-color-surface);\n border: 1px solid var(--sw-color-border);\n border-radius: 4px;\n font-size: 12px;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition:\n opacity 0.2s ease,\n visibility 0.2s ease;\n pointer-events: none;\n z-index: 10;\n }\n\n .tooltip::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-top-color: var(--sw-color-border);\n }\n\n .control-button:hover .tooltip,\n .control-button:focus .tooltip {\n opacity: 1;\n visibility: visible;\n }\n\n /* Vertical orientation tooltip positioning */\n .container.vertical .tooltip {\n bottom: auto;\n left: calc(100% + 8px);\n top: 50%;\n transform: translateY(-50%);\n }\n\n .container.vertical .tooltip::after {\n top: 50%;\n left: auto;\n right: 100%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-right-color: var(--sw-color-border);\n }\n\n /* Overflow menu for responsive collapse */\n .overflow-menu {\n position: relative;\n }\n\n .overflow-button {\n display: none;\n }\n\n .overflow-content {\n display: none;\n position: absolute;\n bottom: calc(100% + 8px);\n right: 0;\n background: var(--sw-color-background);\n border: 1px solid var(--sw-color-border);\n border-radius: var(--sw-border-radius);\n padding: var(--sw-space-2);\n gap: var(--sw-space-2);\n flex-direction: column;\n z-index: 20;\n }\n\n .overflow-menu.open .overflow-content {\n display: flex;\n }\n\n /* Responsive collapse at small widths */\n @media (max-width: 320px) {\n .container:not(.vertical) > .control-button:not(.hangup):not(.overflow-button) {\n display: none;\n }\n\n .container:not(.vertical) .overflow-button {\n display: flex;\n }\n\n /* Ensure overflow content buttons remain visible when menu is open */\n .container:not(.vertical) .overflow-content .control-button {\n display: flex;\n }\n }\n\n /* Dark mode adjustments */\n @media (prefers-color-scheme: light) {\n :host {\n --sw-color-background: #ffffff;\n --sw-color-surface: #f5f5f5;\n --sw-color-surface-hover: #e5e5e5;\n --sw-color-text: #1a1a1a;\n --sw-color-text-muted: #666666;\n --sw-color-border: #d4d4d4;\n }\n }\n\n :host([data-theme='light']) {\n --sw-color-background: #ffffff;\n --sw-color-surface: #f5f5f5;\n --sw-color-surface-hover: #e5e5e5;\n --sw-color-text: #1a1a1a;\n --sw-color-text-muted: #666666;\n --sw-color-border: #d4d4d4;\n }\n `;\n\n /**\n * The call object - can be provided via property or context\n */\n @property({ type: Object }) call?: CallControlsCall;\n\n /**\n * Consume call from context if not provided as property\n */\n @consume({ context: callContext, subscribe: true })\n @state()\n private _contextCall?: CallControlsCall;\n\n /**\n * Orientation: horizontal (default) or vertical\n */\n @property({ type: String }) orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /**\n * Show tooltips on hover\n */\n @property({ type: Boolean, attribute: 'show-tooltips' }) showTooltips = true;\n\n /**\n * Current audio muted state\n */\n @state() private _audioMuted = false;\n\n /**\n * Current video muted state\n */\n @state() private _videoMuted = false;\n\n /**\n * Current screen share status\n */\n @state() private _screenShareStatus: ScreenShareStatus = 'inactive';\n\n /**\n * Available capabilities\n */\n @state() private _capabilities: string[] = [];\n\n /**\n * Is overflow menu open\n */\n @state() private _overflowOpen = false;\n\n /**\n * RxJS subscriptions for cleanup\n */\n private subscriptions: Subscription[] = [];\n\n /**\n * Cached self participant reference for button handlers.\n * Marked as @state() to trigger re-render when self becomes available,\n * enabling the control buttons.\n */\n @state() private selfParticipant?: SelfParticipant;\n\n /**\n * Get the effective call (property or context)\n */\n private get effectiveCall(): CallControlsCall | undefined {\n return this.call || this._contextCall;\n }\n\n /**\n * Lifecycle: Component connected to DOM\n */\n connectedCallback() {\n super.connectedCallback();\n this.setupSubscriptions();\n }\n\n /**\n * Lifecycle: React to property changes\n */\n protected updated(changedProperties: Map<string, unknown>): void {\n super.updated(changedProperties);\n if (changedProperties.has('call') || changedProperties.has('_contextCall')) {\n this.cleanupSubscriptions();\n this.setupSubscriptions();\n }\n }\n\n /**\n * Lifecycle: Component disconnected from DOM\n */\n disconnectedCallback() {\n super.disconnectedCallback();\n this.cleanupSubscriptions();\n }\n\n /**\n * Subscribe to call observables\n */\n private setupSubscriptions(): void {\n const call = this.effectiveCall;\n if (!call) return;\n\n // Use self$ observable if available (recommended for real calls)\n if (call.self$) {\n // Subscribe to self$ and switch to audioMuted$ when self becomes available\n const nonNullSelf$ = call.self$.pipe(\n filter((self): self is SelfParticipant => self !== null)\n );\n\n const audioSub = nonNullSelf$\n .pipe(\n switchMap((self) => {\n this.selfParticipant = self;\n return self.audioMuted$;\n })\n )\n .subscribe((muted) => {\n this._audioMuted = muted;\n });\n this.subscriptions.push(audioSub);\n\n // Subscribe to videoMuted$\n const videoSub = nonNullSelf$.pipe(switchMap((self) => self.videoMuted$)).subscribe((muted) => {\n this._videoMuted = muted;\n });\n this.subscriptions.push(videoSub);\n\n // Subscribe to screenShareStatus$\n const screenShareSub = nonNullSelf$\n .pipe(switchMap((self) => self.screenShareStatus$ ?? of('inactive' as ScreenShareStatus)))\n .subscribe((status) => {\n this._screenShareStatus = status as ScreenShareStatus;\n });\n this.subscriptions.push(screenShareSub);\n } else if (call.self) {\n // Fallback for synchronous self (tests, mocks)\n this.selfParticipant = call.self;\n\n if (call.self.audioMuted$) {\n this.subscriptions.push(\n call.self.audioMuted$.subscribe((muted) => {\n this._audioMuted = muted;\n })\n );\n }\n if (call.self.videoMuted$) {\n this.subscriptions.push(\n call.self.videoMuted$.subscribe((muted) => {\n this._videoMuted = muted;\n })\n );\n }\n if (call.self.screenShareStatus$) {\n this.subscriptions.push(\n call.self.screenShareStatus$.subscribe((status) => {\n this._screenShareStatus = status as ScreenShareStatus;\n })\n );\n }\n }\n\n // Subscribe to capabilities\n if (call.capabilities$) {\n this.subscriptions.push(\n call.capabilities$.subscribe((caps) => {\n this._capabilities = caps;\n })\n );\n }\n }\n\n /**\n * Cleanup all subscriptions\n */\n private cleanupSubscriptions(): void {\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.subscriptions = [];\n this.selfParticipant = undefined;\n }\n\n /**\n * Check if capability is available\n */\n private hasCapability(capability: string): boolean {\n // If no capabilities defined, assume all available\n if (!this._capabilities || this._capabilities.length === 0) {\n return true;\n }\n return this._capabilities.includes(capability);\n }\n\n /**\n * Handle mute audio toggle\n */\n private async handleMuteAudio(): Promise<void> {\n const self = this.selfParticipant ?? this.effectiveCall?.self;\n if (!self) return;\n\n // Capture the intended new state before calling the SDK\n const willBeMuted = !this._audioMuted;\n\n try {\n if (this._audioMuted) {\n await self.unmute();\n } else {\n await self.mute();\n }\n\n this.dispatchEvent(\n new CustomEvent('sw-mute-audio', {\n detail: { muted: willBeMuted },\n bubbles: true,\n composed: true\n })\n );\n } catch (error) {\n console.error('Failed to toggle audio mute:', error);\n }\n }\n\n /**\n * Handle mute video toggle\n */\n private async handleMuteVideo(): Promise<void> {\n const self = this.selfParticipant ?? this.effectiveCall?.self;\n if (!self) return;\n\n // Capture the intended new state before calling the SDK\n const willBeMuted = !this._videoMuted;\n\n try {\n if (this._videoMuted) {\n await self.unmuteVideo();\n } else {\n await self.muteVideo();\n }\n\n this.dispatchEvent(\n new CustomEvent('sw-mute-video', {\n detail: { muted: willBeMuted },\n bubbles: true,\n composed: true\n })\n );\n } catch (error) {\n console.error('Failed to toggle video mute:', error);\n }\n }\n\n /**\n * Handle screen share toggle\n */\n private async handleScreenShare(): Promise<void> {\n const self = this.selfParticipant ?? this.effectiveCall?.self;\n if (!self) return;\n\n // Capture the intended new state before calling the SDK\n const willBeActive = this._screenShareStatus !== 'active';\n\n try {\n if (this._screenShareStatus === 'active') {\n await self.stopScreenShare?.();\n } else {\n await self.startScreenShare?.();\n }\n\n this.dispatchEvent(\n new CustomEvent('sw-screen-share', {\n detail: { active: willBeActive },\n bubbles: true,\n composed: true\n })\n );\n } catch (error) {\n console.error('Failed to toggle screen share:', error);\n }\n }\n\n /**\n * Handle hangup\n */\n private async handleHangup(): Promise<void> {\n const call = this.effectiveCall;\n if (!call) return;\n\n try {\n await call.hangup();\n\n this.dispatchEvent(\n new CustomEvent('sw-hangup', {\n bubbles: true,\n composed: true\n })\n );\n } catch (error) {\n console.error('Failed to hangup:', error);\n }\n }\n\n /**\n * Toggle overflow menu\n */\n private toggleOverflow(): void {\n this._overflowOpen = !this._overflowOpen;\n }\n\n /**\n * Get tooltip text for button\n */\n private getTooltipText(type: ControlButtonType): string {\n switch (type) {\n case 'mute-audio':\n return this._audioMuted ? 'Unmute Audio' : 'Mute Audio';\n case 'mute-video':\n return this._videoMuted ? 'Turn On Camera' : 'Turn Off Camera';\n case 'screen-share':\n return this._screenShareStatus === 'active' ? 'Stop Sharing' : 'Share Screen';\n case 'hangup':\n return 'End Call';\n }\n }\n\n /**\n * Render button icon\n */\n private renderIcon(type: ControlButtonType) {\n switch (type) {\n case 'mute-audio':\n return this._audioMuted\n ? html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\"\n />\n </svg>`\n : html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.91-3c-.49 0-.9.36-.98.85C16.52 14.2 14.47 16 12 16s-4.52-1.8-4.93-4.15c-.08-.49-.49-.85-.98-.85-.61 0-1.09.54-1 1.14.49 3 2.89 5.35 5.91 5.78V20c0 .55.45 1 1 1s1-.45 1-1v-2.08c3.02-.43 5.42-2.78 5.91-5.78.1-.6-.39-1.14-1-1.14z\"\n />\n </svg>`;\n\n case 'mute-video':\n return this._videoMuted\n ? html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M21 6.5l-4 4V7c0-.55-.45-1-1-1H9.82L21 17.18V6.5zM3.27 2L2 3.27 4.73 6H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.21 0 .39-.08.54-.18L19.73 21 21 19.73 3.27 2z\"\n />\n </svg>`\n : html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z\"\n />\n </svg>`;\n\n case 'screen-share':\n return this._screenShareStatus === 'active'\n ? html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M21.22 18.02l2 2H24v-2h-2.78zm.77-2l.01-10c0-1.11-.9-2-2-2H7.22l5.23 5.23c.18-.04.36-.07.55-.1V7.02l4 3.73-1.58 1.47 5.54 5.54c.61-.33 1.03-.99 1.03-1.74zM2.39 1.73L1.11 3l1.54 1.54c-.4.36-.65.89-.65 1.48v10c0 1.1.89 2 2 2H0v2h18.13l2.71 2.71 1.27-1.27L2.39 1.73zM7 15.02c.31-1.48.92-2.95 2.07-4.06l1.59 1.59c-1.54.38-2.7 1.18-3.66 2.47z\"\n />\n </svg>`\n : html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6zm9 9v-4h3l-4-4-4 4h3v4h2z\"\n />\n </svg>`;\n\n case 'hangup':\n return html`<svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08c-.18-.17-.29-.42-.29-.7 0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z\"\n />\n </svg>`;\n }\n }\n\n /**\n * Render a control button\n */\n private renderButton(\n type: ControlButtonType,\n options: {\n onClick: () => void;\n active?: boolean;\n disabled?: boolean;\n className?: string;\n }\n ) {\n const { onClick, active = false, disabled = false, className = '' } = options;\n const tooltipText = this.getTooltipText(type);\n\n return html`\n <button\n class=\"control-button ${type} ${active ? 'active' : ''} ${className}\"\n part=\"button ${active ? 'button-active' : ''} ${disabled ? 'button-disabled' : ''}\"\n aria-label=\"${tooltipText}\"\n aria-pressed=\"${type !== 'hangup' ? active : nothing}\"\n ?disabled=${disabled}\n @click=${onClick}\n >\n ${this.renderIcon(type)}\n ${this.showTooltips\n ? html` <span class=\"tooltip\" part=\"tooltip\">${tooltipText}</span> `\n : nothing}\n </button>\n `;\n }\n\n /**\n * Render the component\n */\n render() {\n const call = this.effectiveCall;\n const hasSelf = Boolean(this.selfParticipant ?? call?.self);\n\n // Check capabilities - server sends: self, member, vmuted, layout, digit, screenshare, device, lock, end\n // Having 'self' capability implies self-controls are available (mute audio/video)\n const hasSelfCapability = this.hasCapability('self');\n const canMuteAudio =\n hasSelfCapability || this.hasCapability('selfMuteAudio') || this.hasCapability('muteAudio');\n const canMuteVideo =\n hasSelfCapability ||\n this.hasCapability('vmuted') ||\n this.hasCapability('selfMuteVideo') ||\n this.hasCapability('muteVideo');\n const canScreenShare =\n (this.hasCapability('screenshare') || this.hasCapability('screenShare')) &&\n Boolean(this.selfParticipant?.startScreenShare ?? call?.self?.startScreenShare);\n const canHangup = true; // Always allow hangup\n\n return html`\n <div\n class=\"container ${this.orientation === 'vertical' ? 'vertical' : ''}\"\n part=\"container\"\n role=\"toolbar\"\n aria-label=\"Call controls\"\n >\n ${this.renderButton('mute-audio', {\n onClick: () => this.handleMuteAudio(),\n active: this._audioMuted,\n disabled: !hasSelf || !canMuteAudio\n })}\n ${this.renderButton('mute-video', {\n onClick: () => this.handleMuteVideo(),\n active: this._videoMuted,\n disabled: !hasSelf || !canMuteVideo\n })}\n ${this.renderButton('screen-share', {\n onClick: () => this.handleScreenShare(),\n active: this._screenShareStatus === 'active',\n disabled: !hasSelf || !canScreenShare\n })}\n ${this.renderButton('hangup', {\n onClick: () => this.handleHangup(),\n disabled: !call || !canHangup,\n className: 'hangup'\n })}\n\n <!-- Overflow menu for responsive collapse -->\n <div class=\"overflow-menu ${this._overflowOpen ? 'open' : ''}\">\n <button\n class=\"control-button overflow-button\"\n aria-label=\"More options\"\n aria-expanded=\"${this._overflowOpen}\"\n @click=${this.toggleOverflow}\n >\n <svg class=\"button-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"\n />\n </svg>\n </button>\n <div class=\"overflow-content\">\n ${this.renderButton('mute-audio', {\n onClick: () => this.handleMuteAudio(),\n active: this._audioMuted,\n disabled: !hasSelf || !canMuteAudio\n })}\n ${this.renderButton('mute-video', {\n onClick: () => this.handleMuteVideo(),\n active: this._videoMuted,\n disabled: !hasSelf || !canMuteVideo\n })}\n ${this.renderButton('screen-share', {\n onClick: () => this.handleScreenShare(),\n active: this._screenShareStatus === 'active',\n disabled: !hasSelf || !canScreenShare\n })}\n </div>\n </div>\n </div>\n `;\n }\n}\n\n/**\n * Declare global type for TypeScript\n */\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-call-controls': CallControls;\n }\n}\n"],"names":["CallControls","LitElement","changedProperties","call","nonNullSelf$","filter","self","audioSub","switchMap","muted","videoSub","screenShareSub","of","status","caps","sub","capability","_a","willBeMuted","error","willBeActive","_b","_c","type","html","options","onClick","active","disabled","className","tooltipText","nothing","hasSelf","hasSelfCapability","canMuteAudio","canMuteVideo","canScreenShare","css","__decorateClass","property","consume","callContext","state","customElement"],"mappings":"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"}
|