@signalwire/web-components 4.0.0-beta.1 → 4.0.0-beta.11

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 (79) hide show
  1. package/README.md +9 -10
  2. package/dist/components/audio-level.d.ts +114 -0
  3. package/dist/components/audio-level.d.ts.map +1 -0
  4. package/dist/components/audio-level.js +203 -0
  5. package/dist/components/audio-level.js.map +1 -0
  6. package/dist/components/call-controls.d.ts +183 -0
  7. package/dist/components/call-controls.d.ts.map +1 -0
  8. package/dist/components/call-controls.js +606 -0
  9. package/dist/components/call-controls.js.map +1 -0
  10. package/dist/components/call-media.d.ts +118 -0
  11. package/dist/components/call-media.d.ts.map +1 -0
  12. package/dist/components/call-media.js +219 -0
  13. package/dist/components/call-media.js.map +1 -0
  14. package/dist/components/call-status.d.ts +83 -0
  15. package/dist/components/call-status.d.ts.map +1 -0
  16. package/dist/components/call-status.js +255 -0
  17. package/dist/components/call-status.js.map +1 -0
  18. package/dist/components/click-to-call.d.ts +151 -0
  19. package/dist/components/click-to-call.d.ts.map +1 -0
  20. package/dist/components/click-to-call.js +428 -0
  21. package/dist/components/click-to-call.js.map +1 -0
  22. package/dist/components/device-selector.d.ts +238 -0
  23. package/dist/components/device-selector.d.ts.map +1 -0
  24. package/dist/components/device-selector.js +685 -0
  25. package/dist/components/device-selector.js.map +1 -0
  26. package/dist/components/dialpad.d.ts +74 -0
  27. package/dist/components/dialpad.d.ts.map +1 -0
  28. package/dist/components/dialpad.js +372 -0
  29. package/dist/components/dialpad.js.map +1 -0
  30. package/dist/components/directory.d.ts +125 -0
  31. package/dist/components/directory.d.ts.map +1 -0
  32. package/dist/components/directory.js +503 -0
  33. package/dist/components/directory.js.map +1 -0
  34. package/dist/components/example-button.d.ts +21 -0
  35. package/dist/components/example-button.d.ts.map +1 -0
  36. package/dist/components/example-button.js +74 -0
  37. package/dist/components/example-button.js.map +1 -0
  38. package/dist/components/participant-controls.d.ts +123 -0
  39. package/dist/components/participant-controls.d.ts.map +1 -0
  40. package/dist/components/participant-controls.js +468 -0
  41. package/dist/components/participant-controls.js.map +1 -0
  42. package/dist/components/participants.d.ts +120 -0
  43. package/dist/components/participants.d.ts.map +1 -0
  44. package/dist/components/participants.js +394 -0
  45. package/dist/components/participants.js.map +1 -0
  46. package/dist/components/self-media.d.ts +78 -0
  47. package/dist/components/self-media.d.ts.map +1 -0
  48. package/dist/components/self-media.js +129 -0
  49. package/dist/components/self-media.js.map +1 -0
  50. package/dist/constants.d.ts +10 -0
  51. package/dist/constants.d.ts.map +1 -0
  52. package/dist/constants.js +5 -0
  53. package/dist/constants.js.map +1 -0
  54. package/dist/context/call-context.d.ts +13 -0
  55. package/dist/context/call-context.d.ts.map +1 -0
  56. package/dist/context/call-context.js +6 -0
  57. package/dist/context/call-context.js.map +1 -0
  58. package/dist/context/index.d.ts +2 -0
  59. package/dist/context/index.d.ts.map +1 -0
  60. package/dist/index.d.ts +29 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +35 -5644
  63. package/dist/index.js.map +1 -1
  64. package/dist/react.d.ts +122 -0
  65. package/dist/types/index.d.ts +20 -0
  66. package/dist/types/index.d.ts.map +1 -0
  67. package/dist/types/index.js +12 -0
  68. package/dist/types/index.js.map +1 -0
  69. package/dist/utils/debounce.d.ts +10 -0
  70. package/dist/utils/debounce.d.ts.map +1 -0
  71. package/dist/utils/debounce.js +13 -0
  72. package/dist/utils/debounce.js.map +1 -0
  73. package/dist/utils/index.d.ts +3 -0
  74. package/dist/utils/index.d.ts.map +1 -0
  75. package/dist/utils/video.d.ts +34 -0
  76. package/dist/utils/video.d.ts.map +1 -0
  77. package/dist/utils/video.js +26 -0
  78. package/dist/utils/video.js.map +1 -0
  79. package/package.json +70 -3
@@ -0,0 +1,428 @@
1
+ import { LitElement as h, html as o, css as p } from "lit";
2
+ import { property as c, state as n, customElement as v } from "lit/decorators.js";
3
+ import { switchMap as w } from "rxjs";
4
+ var f = Object.defineProperty, g = Object.getOwnPropertyDescriptor, a = (t, e, r, l) => {
5
+ for (var i = l > 1 ? void 0 : l ? g(e, r) : e, u = t.length - 1, d; u >= 0; u--)
6
+ (d = t[u]) && (i = (l ? d(e, r, i) : d(i)) || i);
7
+ return l && i && f(e, r, i), i;
8
+ };
9
+ let s = class extends h {
10
+ constructor() {
11
+ super(...arguments), this.client = null, this.destination = "", this.label = "Call", this.audioOnly = !0, this.status = "idle", this.call = null, this.audioMuted = !1, this.selfParticipant = null, this.callDuration = 0, this.errorMessage = "", this.subscriptions = [], this.durationInterval = null, this.callStartTime = null;
12
+ }
13
+ disconnectedCallback() {
14
+ super.disconnectedCallback(), this.cleanup();
15
+ }
16
+ async initiateCall() {
17
+ if (!this.client || !this.destination) {
18
+ this.errorMessage = "No client or destination configured", this.status = "error";
19
+ return;
20
+ }
21
+ try {
22
+ this.status = "connecting", this.errorMessage = "", this.dispatchEvent(
23
+ new CustomEvent("sw-dial", {
24
+ detail: { destination: this.destination },
25
+ bubbles: !0,
26
+ composed: !0
27
+ })
28
+ );
29
+ const t = await this.client.dial(this.destination, {
30
+ audio: !0,
31
+ video: !this.audioOnly
32
+ });
33
+ this.call = t, this.subscribeToCall(t);
34
+ } catch (t) {
35
+ this.status = "error", this.errorMessage = t instanceof Error ? t.message : "Failed to connect", console.error("Click-to-call error:", t);
36
+ }
37
+ }
38
+ subscribeToCall(t) {
39
+ if (t.status$) {
40
+ const e = t.status$.subscribe((r) => {
41
+ r === "active" || r === "connected" ? (this.status = "connected", this.startDurationTimer()) : r === "disconnecting" ? this.status = "disconnecting" : (r === "disconnected" || r === "destroyed" || r === "failed") && this.handleCallEnded();
42
+ });
43
+ this.subscriptions.push(e);
44
+ }
45
+ if (t.self$) {
46
+ const e = t.self$.pipe(
47
+ w((r) => (this.selfParticipant = r, r.audioMuted$))
48
+ ).subscribe((r) => {
49
+ r !== void 0 && (this.audioMuted = r);
50
+ });
51
+ this.subscriptions.push(e);
52
+ }
53
+ }
54
+ startDurationTimer() {
55
+ this.callStartTime = Date.now(), this.callDuration = 0, this.durationInterval = window.setInterval(() => {
56
+ this.callStartTime && (this.callDuration = Math.floor((Date.now() - this.callStartTime) / 1e3));
57
+ }, 1e3);
58
+ }
59
+ stopDurationTimer() {
60
+ this.durationInterval && (clearInterval(this.durationInterval), this.durationInterval = null), this.callStartTime = null;
61
+ }
62
+ formatDuration(t) {
63
+ const e = Math.floor(t / 60), r = t % 60;
64
+ return `${e}:${r.toString().padStart(2, "0")}`;
65
+ }
66
+ handleCallEnded() {
67
+ this.cleanup(), this.status = "idle", this.call = null, this.selfParticipant = null, this.audioMuted = !1, this.callDuration = 0, this.dispatchEvent(
68
+ new CustomEvent("sw-hangup", {
69
+ bubbles: !0,
70
+ composed: !0
71
+ })
72
+ );
73
+ }
74
+ async toggleMute() {
75
+ if (this.selfParticipant)
76
+ try {
77
+ this.audioMuted ? await this.selfParticipant.unmute() : await this.selfParticipant.mute(), this.dispatchEvent(
78
+ new CustomEvent("sw-mute-toggle", {
79
+ detail: { muted: !this.audioMuted },
80
+ bubbles: !0,
81
+ composed: !0
82
+ })
83
+ );
84
+ } catch (t) {
85
+ console.error("Failed to toggle mute:", t);
86
+ }
87
+ }
88
+ async hangup() {
89
+ if (this.call)
90
+ try {
91
+ this.status = "disconnecting", await this.call.hangup();
92
+ } catch (t) {
93
+ console.error("Failed to hangup:", t), this.handleCallEnded();
94
+ }
95
+ }
96
+ cleanup() {
97
+ this.subscriptions.forEach((t) => t.unsubscribe()), this.subscriptions = [], this.stopDurationTimer();
98
+ }
99
+ renderIdleState() {
100
+ return o`
101
+ <button
102
+ class="call-button"
103
+ part="button"
104
+ @click=${this.initiateCall}
105
+ ?disabled=${!this.client || !this.destination}
106
+ aria-label="${this.label}"
107
+ >
108
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
109
+ <path
110
+ d="M6.62 10.79c1.44 2.83 3.76 5.15 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"
111
+ />
112
+ </svg>
113
+ ${this.label}
114
+ </button>
115
+ `;
116
+ }
117
+ renderConnectingState() {
118
+ return o`
119
+ <div class="active-call" part="controls">
120
+ <div class="status-row">
121
+ <div class="status" part="status">
122
+ <span class="status-indicator connecting"></span>
123
+ Connecting...
124
+ </div>
125
+ </div>
126
+ </div>
127
+ `;
128
+ }
129
+ renderConnectedState() {
130
+ return o`
131
+ <div class="active-call" part="controls">
132
+ <div class="status-row">
133
+ <div class="status" part="status">
134
+ <span class="status-indicator"></span>
135
+ Connected
136
+ </div>
137
+ <span class="duration" part="duration">${this.formatDuration(this.callDuration)}</span>
138
+ </div>
139
+ <div class="controls-row">
140
+ <button
141
+ class="control-button ${this.audioMuted ? "active" : ""}"
142
+ @click=${this.toggleMute}
143
+ aria-label="${this.audioMuted ? "Unmute" : "Mute"}"
144
+ aria-pressed="${this.audioMuted}"
145
+ >
146
+ ${this.audioMuted ? o`<svg
147
+ xmlns="http://www.w3.org/2000/svg"
148
+ viewBox="0 0 24 24"
149
+ fill="currentColor"
150
+ >
151
+ <path
152
+ 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"
153
+ />
154
+ </svg>` : o`<svg
155
+ xmlns="http://www.w3.org/2000/svg"
156
+ viewBox="0 0 24 24"
157
+ fill="currentColor"
158
+ >
159
+ <path
160
+ d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"
161
+ />
162
+ </svg>`}
163
+ </button>
164
+ <button class="control-button hangup-button" @click=${this.hangup} aria-label="Hang up">
165
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
166
+ <path
167
+ 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"
168
+ />
169
+ </svg>
170
+ </button>
171
+ </div>
172
+ </div>
173
+ `;
174
+ }
175
+ renderErrorState() {
176
+ return o`
177
+ <div class="container" part="container">
178
+ ${this.renderIdleState()}
179
+ ${this.errorMessage ? o`<div class="error-message">${this.errorMessage}</div>` : null}
180
+ </div>
181
+ `;
182
+ }
183
+ render() {
184
+ return this.status === "error" ? this.renderErrorState() : this.status === "connecting" ? o` <div class="container" part="container">${this.renderConnectingState()}</div> ` : this.status === "connected" || this.status === "disconnecting" ? o` <div class="container" part="container">${this.renderConnectedState()}</div> ` : o` <div class="container" part="container">${this.renderIdleState()}</div> `;
185
+ }
186
+ };
187
+ s.styles = p`
188
+ :host {
189
+ /* CSS Custom Properties for theming */
190
+ --sw-color-primary: #044cf6;
191
+ --sw-color-primary-hover: #0339c4;
192
+ --sw-color-success: #10b981;
193
+ --sw-color-success-hover: #0ea472;
194
+ --sw-color-danger: #ef4444;
195
+ --sw-color-danger-hover: #dc2626;
196
+ --sw-color-warning: #f59e0b;
197
+ --sw-color-text: #1f2937;
198
+ --sw-color-text-muted: #6b7280;
199
+ --sw-color-text-inverse: #ffffff;
200
+ --sw-color-background: #ffffff;
201
+ --sw-color-background-hover: #f3f4f6;
202
+ --sw-color-border: #e5e7eb;
203
+ --sw-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
204
+ --sw-font-size-sm: 12px;
205
+ --sw-font-size-base: 14px;
206
+ --sw-font-size-lg: 16px;
207
+ --sw-space-1: 4px;
208
+ --sw-space-2: 8px;
209
+ --sw-space-3: 12px;
210
+ --sw-space-4: 16px;
211
+ --sw-border-radius: 8px;
212
+ --sw-border-radius-full: 9999px;
213
+
214
+ display: inline-block;
215
+ font-family: var(--sw-font-family);
216
+ }
217
+
218
+ /* Dark mode support */
219
+ :host([data-theme='dark']) {
220
+ --sw-color-text: #f9fafb;
221
+ --sw-color-text-muted: #9ca3af;
222
+ --sw-color-background: #1f2937;
223
+ --sw-color-background-hover: #374151;
224
+ --sw-color-border: #374151;
225
+ }
226
+
227
+ @media (prefers-color-scheme: dark) {
228
+ :host(:not([data-theme='light'])) {
229
+ --sw-color-text: #f9fafb;
230
+ --sw-color-text-muted: #9ca3af;
231
+ --sw-color-background: #1f2937;
232
+ --sw-color-background-hover: #374151;
233
+ --sw-color-border: #374151;
234
+ }
235
+ }
236
+
237
+ .container {
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: var(--sw-space-2);
241
+ }
242
+
243
+ /* Idle state - call button */
244
+ .call-button {
245
+ display: inline-flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ gap: var(--sw-space-2);
249
+ padding: var(--sw-space-3) var(--sw-space-4);
250
+ min-width: 120px;
251
+ min-height: 44px;
252
+ background: var(--sw-color-success);
253
+ color: var(--sw-color-text-inverse);
254
+ border: none;
255
+ border-radius: var(--sw-border-radius);
256
+ font-family: var(--sw-font-family);
257
+ font-size: var(--sw-font-size-lg);
258
+ font-weight: 600;
259
+ cursor: pointer;
260
+ transition:
261
+ background-color 0.15s ease,
262
+ transform 0.1s ease;
263
+ }
264
+
265
+ .call-button:hover {
266
+ background: var(--sw-color-success-hover);
267
+ }
268
+
269
+ .call-button:active {
270
+ transform: scale(0.98);
271
+ }
272
+
273
+ .call-button:disabled {
274
+ opacity: 0.5;
275
+ cursor: not-allowed;
276
+ }
277
+
278
+ .call-button svg {
279
+ width: 20px;
280
+ height: 20px;
281
+ }
282
+
283
+ /* Connected state - expanded controls */
284
+ .active-call {
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: var(--sw-space-3);
288
+ padding: var(--sw-space-4);
289
+ background: var(--sw-color-background);
290
+ border: 1px solid var(--sw-color-border);
291
+ border-radius: var(--sw-border-radius);
292
+ min-width: 200px;
293
+ }
294
+
295
+ .status-row {
296
+ display: flex;
297
+ align-items: center;
298
+ justify-content: space-between;
299
+ gap: var(--sw-space-3);
300
+ }
301
+
302
+ .status {
303
+ display: flex;
304
+ align-items: center;
305
+ gap: var(--sw-space-2);
306
+ font-size: var(--sw-font-size-base);
307
+ color: var(--sw-color-text);
308
+ }
309
+
310
+ .status-indicator {
311
+ width: 8px;
312
+ height: 8px;
313
+ border-radius: 50%;
314
+ background: var(--sw-color-success);
315
+ }
316
+
317
+ .status-indicator.connecting {
318
+ background: var(--sw-color-warning);
319
+ animation: pulse 1.5s ease-in-out infinite;
320
+ }
321
+
322
+ .status-indicator.error {
323
+ background: var(--sw-color-danger);
324
+ }
325
+
326
+ @keyframes pulse {
327
+ 0%,
328
+ 100% {
329
+ opacity: 1;
330
+ }
331
+ 50% {
332
+ opacity: 0.5;
333
+ }
334
+ }
335
+
336
+ .duration {
337
+ font-variant-numeric: tabular-nums;
338
+ color: var(--sw-color-text-muted);
339
+ font-size: var(--sw-font-size-sm);
340
+ }
341
+
342
+ .controls-row {
343
+ display: flex;
344
+ align-items: center;
345
+ justify-content: center;
346
+ gap: var(--sw-space-2);
347
+ }
348
+
349
+ .control-button {
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: center;
353
+ width: 44px;
354
+ height: 44px;
355
+ background: var(--sw-color-background-hover);
356
+ border: 1px solid var(--sw-color-border);
357
+ border-radius: var(--sw-border-radius-full);
358
+ cursor: pointer;
359
+ color: var(--sw-color-text);
360
+ transition: background-color 0.15s ease;
361
+ }
362
+
363
+ .control-button:hover {
364
+ background: var(--sw-color-border);
365
+ }
366
+
367
+ .control-button.active {
368
+ background: var(--sw-color-danger);
369
+ border-color: var(--sw-color-danger);
370
+ color: var(--sw-color-text-inverse);
371
+ }
372
+
373
+ .control-button svg {
374
+ width: 20px;
375
+ height: 20px;
376
+ }
377
+
378
+ .hangup-button {
379
+ background: var(--sw-color-danger);
380
+ border-color: var(--sw-color-danger);
381
+ color: var(--sw-color-text-inverse);
382
+ }
383
+
384
+ .hangup-button:hover {
385
+ background: var(--sw-color-danger-hover);
386
+ }
387
+
388
+ /* Error state */
389
+ .error-message {
390
+ color: var(--sw-color-danger);
391
+ font-size: var(--sw-font-size-sm);
392
+ text-align: center;
393
+ }
394
+ `;
395
+ a([
396
+ c({ attribute: !1 })
397
+ ], s.prototype, "client", 2);
398
+ a([
399
+ c({ type: String })
400
+ ], s.prototype, "destination", 2);
401
+ a([
402
+ c({ type: String })
403
+ ], s.prototype, "label", 2);
404
+ a([
405
+ c({ type: Boolean, attribute: "audio-only" })
406
+ ], s.prototype, "audioOnly", 2);
407
+ a([
408
+ n()
409
+ ], s.prototype, "status", 2);
410
+ a([
411
+ n()
412
+ ], s.prototype, "call", 2);
413
+ a([
414
+ n()
415
+ ], s.prototype, "audioMuted", 2);
416
+ a([
417
+ n()
418
+ ], s.prototype, "callDuration", 2);
419
+ a([
420
+ n()
421
+ ], s.prototype, "errorMessage", 2);
422
+ s = a([
423
+ v("sw-click-to-call")
424
+ ], s);
425
+ export {
426
+ s as ClickToCallComponent
427
+ };
428
+ //# sourceMappingURL=click-to-call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click-to-call.js","sources":["../../src/components/click-to-call.ts"],"sourcesContent":["/**\n * Click to Call Component\n *\n * A single button widget to initiate calls to a preconfigured destination.\n * Shows minimal UI with call status, duration, and basic controls.\n *\n * @example\n * ```html\n * <sw-click-to-call\n * destination=\"sip:support@example.com\"\n * .client=${signalWire}\n * label=\"Call Support\"\n * ></sw-click-to-call>\n * ```\n *\n * @fires sw-dial - Fired when a call is initiated. Detail: `{ destination: string }`\n * @fires sw-hangup - Fired when the hangup button is clicked.\n * @fires sw-mute-toggle - Fired when the mute button is toggled. Detail: `{ muted: boolean }`\n *\n * @cssprop [--sw-color-primary=#044cf6] - Primary brand color\n * @cssprop [--sw-color-primary-hover=#0339c4] - Primary color on hover\n * @cssprop [--sw-color-success=#10b981] - Success/positive color\n * @cssprop [--sw-color-success-hover=#0ea472] - Success color on hover\n * @cssprop [--sw-color-danger=#ef4444] - Danger/destructive color\n * @cssprop [--sw-color-danger-hover=#dc2626] - Danger color on hover\n * @cssprop [--sw-color-warning=#f59e0b] - Warning color\n * @cssprop [--sw-color-text=#1f2937] - Primary text color\n * @cssprop [--sw-color-text-muted=#6b7280] - Secondary/muted text color\n * @cssprop [--sw-color-text-inverse=#ffffff] - Inverse text color for buttons\n * @cssprop [--sw-color-background=#ffffff] - Component background color\n * @cssprop [--sw-color-background-hover=#f3f4f6] - Background color on hover\n * @cssprop [--sw-color-border=#e5e7eb] - Border color\n * @cssprop [--sw-font-family=-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif] - Font family\n * @cssprop [--sw-font-size-sm=12px] - Small font size\n * @cssprop [--sw-font-size-base=14px] - Base font size\n * @cssprop [--sw-font-size-lg=16px] - Large font size\n * @cssprop [--sw-space-1=4px] - Smallest spacing unit\n * @cssprop [--sw-space-2=8px] - Small spacing unit\n * @cssprop [--sw-space-3=12px] - Medium spacing unit\n * @cssprop [--sw-space-4=16px] - Large spacing unit\n * @cssprop [--sw-border-radius=8px] - Border radius for containers\n * @cssprop [--sw-border-radius-full=9999px] - Fully rounded border radius for circular buttons\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { Subscription, switchMap } from 'rxjs';\nimport type { Observable } from 'rxjs';\n\n/**\n * Call status type\n */\nexport type ClickToCallStatus = 'idle' | 'connecting' | 'connected' | 'disconnecting' | 'error';\n\n/**\n * Self participant interface for click-to-call component\n */\nexport interface ClickToCallSelf {\n audioMuted$: Observable<boolean | undefined>;\n mute(): Promise<void>;\n unmute(): Promise<void>;\n}\n\n/**\n * Call interface for click-to-call component\n */\nexport interface ClickToCallCall {\n status$: Observable<string>;\n hangup(): Promise<void>;\n self$?: Observable<ClickToCallSelf>;\n self?: ClickToCallSelf;\n}\n\n/**\n * Client interface for click-to-call component\n */\nexport interface ClickToCallClient {\n dial(\n destination: string,\n options?: { audio?: boolean; video?: boolean }\n ): Promise<ClickToCallCall>;\n}\n\n@customElement('sw-click-to-call')\nexport class ClickToCallComponent 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-success: #10b981;\n --sw-color-success-hover: #0ea472;\n --sw-color-danger: #ef4444;\n --sw-color-danger-hover: #dc2626;\n --sw-color-warning: #f59e0b;\n --sw-color-text: #1f2937;\n --sw-color-text-muted: #6b7280;\n --sw-color-text-inverse: #ffffff;\n --sw-color-background: #ffffff;\n --sw-color-background-hover: #f3f4f6;\n --sw-color-border: #e5e7eb;\n --sw-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n --sw-font-size-sm: 12px;\n --sw-font-size-base: 14px;\n --sw-font-size-lg: 16px;\n --sw-space-1: 4px;\n --sw-space-2: 8px;\n --sw-space-3: 12px;\n --sw-space-4: 16px;\n --sw-border-radius: 8px;\n --sw-border-radius-full: 9999px;\n\n display: inline-block;\n font-family: var(--sw-font-family);\n }\n\n /* Dark mode support */\n :host([data-theme='dark']) {\n --sw-color-text: #f9fafb;\n --sw-color-text-muted: #9ca3af;\n --sw-color-background: #1f2937;\n --sw-color-background-hover: #374151;\n --sw-color-border: #374151;\n }\n\n @media (prefers-color-scheme: dark) {\n :host(:not([data-theme='light'])) {\n --sw-color-text: #f9fafb;\n --sw-color-text-muted: #9ca3af;\n --sw-color-background: #1f2937;\n --sw-color-background-hover: #374151;\n --sw-color-border: #374151;\n }\n }\n\n .container {\n display: flex;\n flex-direction: column;\n gap: var(--sw-space-2);\n }\n\n /* Idle state - call button */\n .call-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--sw-space-2);\n padding: var(--sw-space-3) var(--sw-space-4);\n min-width: 120px;\n min-height: 44px;\n background: var(--sw-color-success);\n color: var(--sw-color-text-inverse);\n border: none;\n border-radius: var(--sw-border-radius);\n font-family: var(--sw-font-family);\n font-size: var(--sw-font-size-lg);\n font-weight: 600;\n cursor: pointer;\n transition:\n background-color 0.15s ease,\n transform 0.1s ease;\n }\n\n .call-button:hover {\n background: var(--sw-color-success-hover);\n }\n\n .call-button:active {\n transform: scale(0.98);\n }\n\n .call-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .call-button svg {\n width: 20px;\n height: 20px;\n }\n\n /* Connected state - expanded controls */\n .active-call {\n display: flex;\n flex-direction: column;\n gap: var(--sw-space-3);\n padding: var(--sw-space-4);\n background: var(--sw-color-background);\n border: 1px solid var(--sw-color-border);\n border-radius: var(--sw-border-radius);\n min-width: 200px;\n }\n\n .status-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--sw-space-3);\n }\n\n .status {\n display: flex;\n align-items: center;\n gap: var(--sw-space-2);\n font-size: var(--sw-font-size-base);\n color: var(--sw-color-text);\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--sw-color-success);\n }\n\n .status-indicator.connecting {\n background: var(--sw-color-warning);\n animation: pulse 1.5s ease-in-out infinite;\n }\n\n .status-indicator.error {\n background: var(--sw-color-danger);\n }\n\n @keyframes pulse {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n }\n\n .duration {\n font-variant-numeric: tabular-nums;\n color: var(--sw-color-text-muted);\n font-size: var(--sw-font-size-sm);\n }\n\n .controls-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--sw-space-2);\n }\n\n .control-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n background: var(--sw-color-background-hover);\n border: 1px solid var(--sw-color-border);\n border-radius: var(--sw-border-radius-full);\n cursor: pointer;\n color: var(--sw-color-text);\n transition: background-color 0.15s ease;\n }\n\n .control-button:hover {\n background: var(--sw-color-border);\n }\n\n .control-button.active {\n background: var(--sw-color-danger);\n border-color: var(--sw-color-danger);\n color: var(--sw-color-text-inverse);\n }\n\n .control-button svg {\n width: 20px;\n height: 20px;\n }\n\n .hangup-button {\n background: var(--sw-color-danger);\n border-color: var(--sw-color-danger);\n color: var(--sw-color-text-inverse);\n }\n\n .hangup-button:hover {\n background: var(--sw-color-danger-hover);\n }\n\n /* Error state */\n .error-message {\n color: var(--sw-color-danger);\n font-size: var(--sw-font-size-sm);\n text-align: center;\n }\n `;\n\n /**\n * Client for initiating calls (SignalWire)\n */\n @property({ attribute: false })\n client: ClickToCallClient | null = null;\n\n /**\n * Destination address to call\n */\n @property({ type: String })\n destination: string = '';\n\n /**\n * Button label when idle\n */\n @property({ type: String })\n label: string = 'Call';\n\n /**\n * Audio-only mode (no video)\n */\n @property({ type: Boolean, attribute: 'audio-only' })\n audioOnly: boolean = true;\n\n /**\n * Current call status\n */\n @state()\n private status: ClickToCallStatus = 'idle';\n\n /**\n * Current call object\n */\n @state()\n private call: ClickToCallCall | null = null;\n\n /**\n * Is audio muted\n */\n @state()\n private audioMuted: boolean = false;\n\n /**\n * Self participant reference for mute/unmute operations\n */\n private selfParticipant: ClickToCallSelf | null = null;\n\n /**\n * Call duration in seconds\n */\n @state()\n private callDuration: number = 0;\n\n /**\n * Error message\n */\n @state()\n private errorMessage: string = '';\n\n /**\n * RxJS subscriptions for cleanup\n */\n private subscriptions: Subscription[] = [];\n\n /**\n * Duration timer interval\n */\n private durationInterval: number | null = null;\n\n /**\n * Call start time\n */\n private callStartTime: number | null = null;\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.cleanup();\n }\n\n private async initiateCall() {\n if (!this.client || !this.destination) {\n this.errorMessage = 'No client or destination configured';\n this.status = 'error';\n return;\n }\n\n try {\n this.status = 'connecting';\n this.errorMessage = '';\n\n // Dispatch dial event\n this.dispatchEvent(\n new CustomEvent('sw-dial', {\n detail: { destination: this.destination },\n bubbles: true,\n composed: true\n })\n );\n\n const call = await this.client.dial(this.destination, {\n audio: true,\n video: !this.audioOnly\n });\n\n this.call = call;\n this.subscribeToCall(call);\n } catch (error) {\n this.status = 'error';\n this.errorMessage = error instanceof Error ? error.message : 'Failed to connect';\n console.error('Click-to-call error:', error);\n }\n }\n\n private subscribeToCall(call: ClickToCallCall) {\n // Subscribe to status\n if (call.status$) {\n const statusSub = call.status$.subscribe((status) => {\n if (status === 'active' || status === 'connected') {\n this.status = 'connected';\n this.startDurationTimer();\n } else if (status === 'disconnecting') {\n this.status = 'disconnecting';\n } else if (status === 'disconnected' || status === 'destroyed' || status === 'failed') {\n this.handleCallEnded();\n }\n });\n this.subscriptions.push(statusSub);\n }\n\n // Subscribe to self$ observable to get audioMuted$ updates when self becomes available\n if (call.self$) {\n const selfSub = call.self$\n .pipe(\n switchMap((self) => {\n this.selfParticipant = self;\n return self.audioMuted$;\n })\n )\n .subscribe((muted) => {\n if (muted !== undefined) this.audioMuted = muted;\n });\n this.subscriptions.push(selfSub);\n }\n }\n\n private startDurationTimer() {\n this.callStartTime = Date.now();\n this.callDuration = 0;\n\n this.durationInterval = window.setInterval(() => {\n if (this.callStartTime) {\n this.callDuration = Math.floor((Date.now() - this.callStartTime) / 1000);\n }\n }, 1000);\n }\n\n private stopDurationTimer() {\n if (this.durationInterval) {\n clearInterval(this.durationInterval);\n this.durationInterval = null;\n }\n this.callStartTime = null;\n }\n\n private formatDuration(seconds: number): string {\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n }\n\n private handleCallEnded() {\n this.cleanup();\n this.status = 'idle';\n this.call = null;\n this.selfParticipant = null;\n this.audioMuted = false;\n this.callDuration = 0;\n\n this.dispatchEvent(\n new CustomEvent('sw-hangup', {\n bubbles: true,\n composed: true\n })\n );\n }\n\n private async toggleMute() {\n if (!this.selfParticipant) return;\n\n try {\n if (this.audioMuted) {\n await this.selfParticipant.unmute();\n } else {\n await this.selfParticipant.mute();\n }\n\n this.dispatchEvent(\n new CustomEvent('sw-mute-toggle', {\n detail: { muted: !this.audioMuted },\n bubbles: true,\n composed: true\n })\n );\n } catch (error) {\n console.error('Failed to toggle mute:', error);\n }\n }\n\n private async hangup() {\n if (!this.call) return;\n\n try {\n this.status = 'disconnecting';\n await this.call.hangup();\n } catch (error) {\n console.error('Failed to hangup:', error);\n this.handleCallEnded();\n }\n }\n\n private cleanup() {\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.subscriptions = [];\n this.stopDurationTimer();\n }\n\n private renderIdleState() {\n return html`\n <button\n class=\"call-button\"\n part=\"button\"\n @click=${this.initiateCall}\n ?disabled=${!this.client || !this.destination}\n aria-label=\"${this.label}\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path\n d=\"M6.62 10.79c1.44 2.83 3.76 5.15 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z\"\n />\n </svg>\n ${this.label}\n </button>\n `;\n }\n\n private renderConnectingState() {\n return html`\n <div class=\"active-call\" part=\"controls\">\n <div class=\"status-row\">\n <div class=\"status\" part=\"status\">\n <span class=\"status-indicator connecting\"></span>\n Connecting...\n </div>\n </div>\n </div>\n `;\n }\n\n private renderConnectedState() {\n return html`\n <div class=\"active-call\" part=\"controls\">\n <div class=\"status-row\">\n <div class=\"status\" part=\"status\">\n <span class=\"status-indicator\"></span>\n Connected\n </div>\n <span class=\"duration\" part=\"duration\">${this.formatDuration(this.callDuration)}</span>\n </div>\n <div class=\"controls-row\">\n <button\n class=\"control-button ${this.audioMuted ? 'active' : ''}\"\n @click=${this.toggleMute}\n aria-label=\"${this.audioMuted ? 'Unmute' : 'Mute'}\"\n aria-pressed=\"${this.audioMuted}\"\n >\n ${this.audioMuted\n ? html`<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\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\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path\n d=\"M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z\"\n />\n </svg>`}\n </button>\n <button class=\"control-button hangup-button\" @click=${this.hangup} aria-label=\"Hang up\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" 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 </button>\n </div>\n </div>\n `;\n }\n\n private renderErrorState() {\n return html`\n <div class=\"container\" part=\"container\">\n ${this.renderIdleState()}\n ${this.errorMessage ? html`<div class=\"error-message\">${this.errorMessage}</div>` : null}\n </div>\n `;\n }\n\n render() {\n if (this.status === 'error') {\n return this.renderErrorState();\n }\n\n if (this.status === 'connecting') {\n return html` <div class=\"container\" part=\"container\">${this.renderConnectingState()}</div> `;\n }\n\n if (this.status === 'connected' || this.status === 'disconnecting') {\n return html` <div class=\"container\" part=\"container\">${this.renderConnectedState()}</div> `;\n }\n\n return html` <div class=\"container\" part=\"container\">${this.renderIdleState()}</div> `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-click-to-call': ClickToCallComponent;\n }\n}\n"],"names":["ClickToCallComponent","LitElement","call","error","statusSub","status","selfSub","switchMap","self","muted","seconds","mins","secs","sub","html","css","__decorateClass","property","state","customElement"],"mappings":"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"}