@signalwire/web-components 4.0.0-beta.12 → 4.0.0-beta.13
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/dist/components/UI/controls/sw-ui-dialpad.d.ts +1 -1
- package/dist/components/UI/controls/sw-ui-dialpad.d.ts.map +1 -1
- package/dist/components/UI/controls/sw-ui-dialpad.js +9 -8
- package/dist/components/UI/controls/sw-ui-dialpad.js.map +1 -1
- package/dist/components/UI/controls/sw-ui-dropup.d.ts +1 -1
- package/dist/components/UI/controls/sw-ui-dropup.d.ts.map +1 -1
- package/dist/components/UI/controls/sw-ui-dropup.js +9 -8
- package/dist/components/UI/controls/sw-ui-dropup.js.map +1 -1
- package/dist/components/UI/controls/sw-ui-split-button.d.ts +1 -1
- package/dist/components/UI/controls/sw-ui-split-button.d.ts.map +1 -1
- package/dist/components/UI/controls/sw-ui-split-button.js +13 -12
- package/dist/components/UI/controls/sw-ui-split-button.js.map +1 -1
- package/dist/components/UI/host-reset.d.ts +16 -0
- package/dist/components/UI/host-reset.d.ts.map +1 -0
- package/dist/components/UI/host-reset.js +20 -0
- package/dist/components/UI/host-reset.js.map +1 -0
- package/dist/components/UI/sw-ui-alert.d.ts +1 -1
- package/dist/components/UI/sw-ui-alert.d.ts.map +1 -1
- package/dist/components/UI/sw-ui-alert.js +14 -13
- package/dist/components/UI/sw-ui-alert.js.map +1 -1
- package/dist/components/UI/sw-ui-transcript-view.d.ts +1 -1
- package/dist/components/UI/sw-ui-transcript-view.d.ts.map +1 -1
- package/dist/components/UI/sw-ui-transcript-view.js +6 -5
- package/dist/components/UI/sw-ui-transcript-view.js.map +1 -1
- package/dist/components/sw-call-media.d.ts +0 -9
- package/dist/components/sw-call-media.d.ts.map +1 -1
- package/dist/components/sw-call-media.js +60 -102
- package/dist/components/sw-call-media.js.map +1 -1
- package/dist/components/sw-call-status.d.ts +1 -1
- package/dist/components/sw-call-status.d.ts.map +1 -1
- package/dist/components/sw-call-status.js +6 -5
- package/dist/components/sw-call-status.js.map +1 -1
- package/dist/components/sw-call-widget/sw-call-widget.d.ts +1 -1
- package/dist/components/sw-call-widget/sw-call-widget.d.ts.map +1 -1
- package/dist/components/sw-call-widget/sw-call-widget.js +15 -14
- package/dist/components/sw-call-widget/sw-call-widget.js.map +1 -1
- package/dist/components/sw-click-to-call.d.ts +1 -1
- package/dist/components/sw-click-to-call.d.ts.map +1 -1
- package/dist/components/sw-click-to-call.js +9 -8
- package/dist/components/sw-click-to-call.js.map +1 -1
- package/dist/components/sw-device-selector/sw-device-selector.d.ts +1 -1
- package/dist/components/sw-device-selector/sw-device-selector.d.ts.map +1 -1
- package/dist/components/sw-device-selector/sw-device-selector.js +5 -4
- package/dist/components/sw-device-selector/sw-device-selector.js.map +1 -1
- package/dist/components/sw-directory.d.ts +1 -1
- package/dist/components/sw-directory.d.ts.map +1 -1
- package/dist/components/sw-directory.js +6 -5
- package/dist/components/sw-directory.js.map +1 -1
- package/dist/components/sw-participant-controls.d.ts +1 -1
- package/dist/components/sw-participant-controls.d.ts.map +1 -1
- package/dist/components/sw-participant-controls.js +6 -5
- package/dist/components/sw-participant-controls.js.map +1 -1
- package/dist/components/sw-participants.d.ts +1 -1
- package/dist/components/sw-participants.d.ts.map +1 -1
- package/dist/components/sw-participants.js +20 -19
- package/dist/components/sw-participants.js.map +1 -1
- package/dist/embed/signalwire-web-components-embed.iife.js +195 -182
- package/dist/embed/signalwire-web-components-embed.iife.js.map +1 -1
- package/dist/embed/signalwire-web-components-embed.umd.cjs +195 -182
- package/dist/embed/signalwire-web-components-embed.umd.cjs.map +1 -1
- package/dist/index.js +46 -46
- package/dist/node_modules/dompurify/dist/purify.es.js +692 -423
- package/dist/node_modules/dompurify/dist/purify.es.js.map +1 -1
- package/dist/utils/video.js +6 -21
- package/dist/utils/video.js.map +1 -1
- package/package.json +5 -4
- package/dist/constants.js +0 -5
- package/dist/constants.js.map +0 -1
- package/dist/utils/debounce.js +0 -13
- package/dist/utils/debounce.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LitElement as C, nothing as c, html as _ } from "lit";
|
|
2
|
-
import { property as l, state as p, customElement as
|
|
3
|
-
import {
|
|
2
|
+
import { property as l, state as p, customElement as f } from "lit/decorators.js";
|
|
3
|
+
import { SignalWire as y, getLogger as w } from "@signalwire/js";
|
|
4
4
|
import { filter as g, first as m } from "rxjs/operators";
|
|
5
5
|
import { CallStateContextController as b } from "../../context/CallStateContextController.js";
|
|
6
6
|
import { IncomingCallController as v } from "../../context/call-state-context.js";
|
|
@@ -10,14 +10,15 @@ import { UserEventController as L } from "../../context/UserEventController.js";
|
|
|
10
10
|
import { showPrompt as h } from "../UI/sw-ui-alert.js";
|
|
11
11
|
import { ensureSignalWireTheme as I, ensureSignalWireFonts as D } from "../../utils/theme-loader.js";
|
|
12
12
|
import { withWidgetCapabilities as T, parseUserVariablesAttribute as F } from "../../utils/user-variables.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
import { hostReset as $ } from "../UI/host-reset.js";
|
|
14
|
+
import { buildCredentialProvider as A } from "./client-factory.js";
|
|
15
|
+
import { renderCallView as k, renderConnecting as W, widgetStyles as U } from "./sw-call-widget.templates.js";
|
|
16
|
+
var V = Object.defineProperty, B = Object.getOwnPropertyDescriptor, s = (t, e, n, r) => {
|
|
17
|
+
for (var o = r > 1 ? void 0 : r ? B(e, n) : e, a = t.length - 1, u; a >= 0; a--)
|
|
17
18
|
(u = t[a]) && (o = (r ? u(e, n, o) : u(o)) || o);
|
|
18
|
-
return r && o &&
|
|
19
|
+
return r && o && V(e, n, o), o;
|
|
19
20
|
};
|
|
20
|
-
const d =
|
|
21
|
+
const d = w();
|
|
21
22
|
let i = class extends C {
|
|
22
23
|
constructor() {
|
|
23
24
|
super(...arguments), this.token = "", this.host = "", this.destination = "", this.modal = !1, this.transcription = !1, this.allowIncomingCalls = !1, this.audioOnly = !1, this.userVariables = "", this.disableAutoTheme = !1, this.disableAutoFonts = !1, this._call = null, this._connecting = !1, this._hasLayoutLayers = !1, this._drawer = null, this._callState = new b(this), this._devices = new E(this), this._transcript = new S(this), this._userEventCtrl = new L(this), this._incomingCalls = new v(this), this._client = null, this._subs = [], this._pendingIncoming = !1, this._handleIncomingCall = async (t) => {
|
|
@@ -79,8 +80,8 @@ let i = class extends C {
|
|
|
79
80
|
_refreshClient() {
|
|
80
81
|
this._destroyClient();
|
|
81
82
|
try {
|
|
82
|
-
this._client = new
|
|
83
|
-
|
|
83
|
+
this._client = new y(
|
|
84
|
+
A(this.token, this.host)
|
|
84
85
|
), this._devices.connectDevices(this._client), this.allowIncomingCalls && this._connectIncomingCalls();
|
|
85
86
|
} catch (t) {
|
|
86
87
|
const e = t instanceof Error ? t.message : "Failed to initialise client";
|
|
@@ -178,7 +179,7 @@ let i = class extends C {
|
|
|
178
179
|
}
|
|
179
180
|
// ── Render ─────────────────────────────────────────────────────────
|
|
180
181
|
render() {
|
|
181
|
-
const t = !!(this._call || this._connecting), e = this._call ?
|
|
182
|
+
const t = !!(this._call || this._connecting), e = this._call ? k({
|
|
182
183
|
transcription: this.transcription,
|
|
183
184
|
hasLayoutLayers: this._hasLayoutLayers,
|
|
184
185
|
drawer: this._drawer,
|
|
@@ -187,7 +188,7 @@ let i = class extends C {
|
|
|
187
188
|
onFullscreenToggle: this._onFullscreenToggle,
|
|
188
189
|
onTranscriptToggle: this._onTranscriptToggle,
|
|
189
190
|
onDrawerClose: this._onDrawerClose
|
|
190
|
-
}) : this._connecting ?
|
|
191
|
+
}) : this._connecting ? W() : c;
|
|
191
192
|
return this.modal ? _`
|
|
192
193
|
<slot @slotchange=${this._onSlotChange}></slot>
|
|
193
194
|
<sw-ui-modal ?open=${t} @sw-modal-close=${this._onModalClose}>
|
|
@@ -198,7 +199,7 @@ let i = class extends C {
|
|
|
198
199
|
` : e !== c ? e : _`<slot @slotchange=${this._onSlotChange}></slot>`;
|
|
199
200
|
}
|
|
200
201
|
};
|
|
201
|
-
i.styles =
|
|
202
|
+
i.styles = [$, U];
|
|
202
203
|
s([
|
|
203
204
|
l({ type: String })
|
|
204
205
|
], i.prototype, "token", 2);
|
|
@@ -242,7 +243,7 @@ s([
|
|
|
242
243
|
p()
|
|
243
244
|
], i.prototype, "_drawer", 2);
|
|
244
245
|
i = s([
|
|
245
|
-
|
|
246
|
+
f("sw-call-widget")
|
|
246
247
|
], i);
|
|
247
248
|
export {
|
|
248
249
|
i as SwCallWidget
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-call-widget.js","sources":["../../../src/components/sw-call-widget/sw-call-widget.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { SignalWire, getLogger } from '@signalwire/js';\nimport type { Call } from '../../types/index.js';\nimport { Subscription } from 'rxjs';\nimport { first, filter } from 'rxjs/operators';\n\nimport { CallStateContextController } from '../../context/CallStateContextController.js';\nimport { IncomingCallController } from '../../context/call-state-context.js';\nimport type { IncomingCallInfo } from '../../context/call-state-context.js';\nimport { DevicesContextController } from '../../context/DevicesContextController.js';\nimport { TranscriptController } from '../../context/TranscriptController.js';\nimport { UserEventController } from '../../context/UserEventController.js';\n\nimport '../sw-call-media.js';\nimport '../sw-local-camera.js';\nimport '../sw-call-controls.js';\nimport '../UI/layout/sw-ui-call-layout.js';\nimport '../UI/layout/sw-ui-responsive-container.js';\nimport '../UI/layout/sw-ui-modal.js';\nimport '../UI/layout/sw-ui-background.js';\nimport '../UI/layout/sw-ui-content-drawer.js';\nimport '../UI/sw-ui-transcript-view.js';\nimport { showPrompt } from '../UI/sw-ui-alert.js';\nimport type { DisplayContentPayload } from '../UI/layout/sw-ui-content-drawer.js';\nimport { ensureSignalWireTheme, ensureSignalWireFonts } from '../../utils/theme-loader.js';\nimport {\n parseUserVariablesAttribute,\n withWidgetCapabilities,\n} from '../../utils/user-variables.js';\nimport { buildCredentialProvider } from './client-factory.js';\nimport {\n widgetStyles,\n renderCallView,\n renderConnecting,\n} from './sw-call-widget.templates.js';\n\nconst logger = getLogger();\n\n/**\n * All-in-one call widget. Handles client initialisation, dialling, media,\n * controls and optional AI transcript — in either inline or modal modes.\n *\n * Composes `sw-ui-call-layout`, `sw-call-media`, `sw-local-camera`,\n * `sw-call-controls`, and `sw-ui-transcript-view` under the hood.\n * All child components are wired via Lit context — no manual plumbing needed.\n *\n * @prop {string} token - SignalWire SAT or embed token\n * @prop {string} host - Optional server host\n * @prop {string} destination - Call destination (address or resource)\n * @prop {boolean} modal - Render in a `<sw-ui-modal>` overlay\n * @prop {boolean} transcription - Show AI transcript panel\n *\n * @slot background - Background element (e.g. `<sw-ui-background default>`)\n * @slot (default) - Trigger element (click to dial, shown when idle)\n *\n * @fires sw-dial - When `dial()` is invoked. Detail: `{ destination }`.\n * @fires sw-call-ended - When the call reaches a terminal state (user hangup, remote disconnect, or failure). Detail: `{ status }`.\n * @fires sw-display-content - From `display_content` user event. Detail: `DisplayContentPayload`.\n * @fires signalwire-address:event - Forwarded SignalWire custom user events.\n *\n * All inner events bubble.\n *\n * @method dial() - Initiate call\n * @method hangup() - End active call\n */\n@customElement('sw-call-widget')\nexport class SwCallWidget extends LitElement {\n static styles = widgetStyles;\n\n // ── Public properties ──────────────────────────────────────────────\n\n @property({ type: String }) token = '';\n @property({ type: String }) host = '';\n @property({ type: String }) destination = '';\n @property({ type: Boolean, reflect: true }) modal = false;\n @property({ type: Boolean, reflect: true }) transcription = false;\n @property({ type: Boolean, reflect: true, attribute: 'allow-incoming-calls' }) allowIncomingCalls = false;\n @property({ type: Boolean, reflect: true, attribute: 'audio-only' }) audioOnly = false;\n\n /**\n * Custom variables sent with the Verto invite as a JSON object.\n *\n * The widget always advertises `capabilities.display_content` and\n * `metadata.widget.opened_at` so the agent can detect that the caller\n * supports the content drawer; user-supplied keys are merged in and win\n * on shallow conflict.\n *\n * Invalid JSON is logged and ignored — the call still dials.\n *\n * @example\n * <sw-call-widget user-variables='{\"customer_id\": \"abc-123\"}'></sw-call-widget>\n */\n @property({ type: String, attribute: 'user-variables' }) userVariables = '';\n\n /**\n * Skip auto-injecting the SignalWire `theme.css` design-token stylesheet.\n * Set this when the host page already loads `@signalwire/web-components/theme.css`\n * or a custom theme written against the same DTCG token names.\n */\n @property({ type: Boolean, reflect: true, attribute: 'disable-auto-theme' }) disableAutoTheme = false;\n\n /**\n * Skip auto-loading the SignalWire brand fonts (Lexend, Instrument Sans,\n * JetBrains Mono) from Google Fonts. Set this when fonts are self-hosted\n * or loaded elsewhere.\n */\n @property({ type: Boolean, reflect: true, attribute: 'disable-auto-fonts' }) disableAutoFonts = false;\n\n // ── Internal state ─────────────────────────────────────────────────\n\n @state() private _call: Call | null = null;\n @state() private _connecting = false;\n @state() private _hasLayoutLayers = false;\n @state() private _drawer: DisplayContentPayload | null = null;\n\n // ── Context providers ──────────────────────────────────────────────\n\n private _callState = new CallStateContextController(this);\n private _devices = new DevicesContextController(this);\n private _transcript: TranscriptController = new TranscriptController(this);\n private _userEventCtrl = new UserEventController(this);\n private _incomingCalls = new IncomingCallController(this);\n\n // ── Internals ──────────────────────────────────────────────────────\n\n private _client: SignalWire | null = null;\n private _subs: Subscription[] = [];\n private _pendingIncoming = false;\n\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n connectedCallback(): void {\n super.connectedCallback();\n if (!this.disableAutoTheme) ensureSignalWireTheme();\n if (!this.disableAutoFonts) ensureSignalWireFonts();\n }\n\n protected updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n if (changed.has('token') || changed.has('host')) {\n if (this.token) {\n this._refreshClient();\n } else if (changed.has('host')) {\n // Host changed but no token configured yet — defer client init until\n // the consumer sets `.token`. Surface this so misconfigurations\n // (e.g. forgetting to bind token) don't fail silently.\n logger.debug(\n '[SwCallWidget] host changed but token is empty; skipping client refresh until token is set',\n );\n }\n } else if (changed.has('allowIncomingCalls') && this._client) {\n if (this.allowIncomingCalls) {\n this._connectIncomingCalls();\n } else {\n this._incomingCalls.disconnect();\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this._destroyClient();\n }\n\n // ── Client lifecycle ───────────────────────────────────────────────\n\n private _destroyClient(): void {\n this._subs.forEach((s) => s.unsubscribe());\n this._subs = [];\n\n this._incomingCalls.disconnect();\n this._devices.disconnectCall();\n this._devices.disconnect();\n this._callState.disconnect();\n this._transcript.setCall(undefined);\n\n\n if (this._client) {\n try {\n this._client.destroy();\n } catch (e) {\n logger.error('[SwCallWidget] Error destroying client:', e);\n }\n this._client = null;\n }\n\n this._call = null;\n this._connecting = false;\n }\n\n private _refreshClient(): void {\n this._destroyClient();\n try {\n this._client = new SignalWire(\n buildCredentialProvider(this.token, this.host),\n );\n this._devices.connectDevices(this._client as unknown as import('../../types/index.js').DeviceController);\n\n if (this.allowIncomingCalls) {\n this._connectIncomingCalls();\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Failed to initialise client';\n logger.error('[SwCallWidget] Failed to initialise client:', e);\n void showPrompt({ title: 'Client Error', description: message, type: 'alert' });\n }\n }\n\n // ── Public methods ─────────────────────────────────────────────────\n\n async dial(): Promise<void> {\n if (!this._client || this._connecting || this._call) return;\n if (!this.destination) {\n void showPrompt({ title: 'Call Error', description: 'No destination configured.', type: 'alert' });\n return;\n }\n\n this._connecting = true;\n\n this.dispatchEvent(new CustomEvent('sw-dial', {\n detail: { destination: this.destination },\n bubbles: true,\n composed: true,\n }));\n\n const wantsVideo = !this.audioOnly;\n\n try {\n const call = await new Promise<Call>((resolve, reject) => {\n const sub = this._client!.isConnected$\n .pipe(filter((c) => c), first())\n .subscribe({\n next: () => {\n const userVariables = withWidgetCapabilities(\n parseUserVariablesAttribute(this.userVariables)\n );\n this._client!\n .dial(this.destination, {\n audio: true,\n video: wantsVideo,\n receiveAudio: true,\n receiveVideo: wantsVideo,\n userVariables,\n })\n .then(resolve)\n .catch(reject);\n },\n error: reject,\n });\n this._subs.push(sub);\n });\n\n this._wireCall(call);\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Failed to connect call';\n logger.error('[SwCallWidget] Dial failed:', e);\n void showPrompt({ title: 'Call Failed', description: message, type: 'alert' });\n } finally {\n this._connecting = false;\n }\n }\n\n async hangup(): Promise<void> {\n if (this._call) {\n await this._call.hangup();\n }\n }\n\n // ── Incoming calls ──────────────────────────────────────────────────\n\n private _connectIncomingCalls(): void {\n if (!this._client) return;\n this._incomingCalls.onIncomingCall = this._handleIncomingCall;\n this._subs.push(\n this._client.isConnected$\n .pipe(filter(Boolean), first())\n .subscribe(() => {\n if (this._client) {\n this._incomingCalls.connect(this._client.session.incomingCalls$);\n }\n })\n );\n }\n\n private _handleIncomingCall = async (info: IncomingCallInfo): Promise<void> => {\n if (this._call || this._connecting || this._pendingIncoming) return;\n this._pendingIncoming = true;\n\n try {\n const callerDisplay = info.callerName || info.callerNumber || 'Unknown Caller';\n // TODO(ringing-ux): the confirm dialog is a placeholder, not a real\n // ringing UI. Missing: caller avatar, audible ringtone, distinction\n // between \"ignore\" (let it keep ringing) and \"reject\" (decline now),\n // and a timeout. Replace with a dedicated `<sw-ui-incoming-call>`.\n const accepted = await showPrompt({\n title: 'Incoming Call',\n description: `${callerDisplay} is calling`,\n type: 'confirm',\n });\n\n if (accepted) {\n this._wireCall(info.call);\n info.call.answer();\n } else {\n info.call.reject();\n }\n } finally {\n this._pendingIncoming = false;\n }\n };\n\n // ── Call wiring ────────────────────────────────────────────────────\n\n private _wireCall(call: Call): void {\n this._call = call;\n\n // Wire contexts\n this._callState.connect(call);\n this._devices.connectCall(call);\n this._transcript.setCall(call);\n\n // Always subscribe to user_event for display_content and pass-through\n this._userEventCtrl.setCall(call);\n this.addEventListener('sw-display-content', this._onDisplayContent as EventListener);\n\n // Re-enumerate devices now that getUserMedia has granted permission\n this._devices.refreshDevices();\n\n // Track layout layers to know when MCU composites local camera\n this._subs.push(\n call.layoutLayers$.subscribe((layers) => {\n this._hasLayoutLayers = layers.length > 0;\n })\n );\n\n // Watch for call end\n this._subs.push(\n call.status$.subscribe((status) => {\n if (\n status === 'disconnected' ||\n status === 'destroyed' ||\n status === 'failed'\n ) {\n this._unwireCall();\n }\n })\n );\n }\n\n private _onDisplayContent = (e: CustomEvent<DisplayContentPayload>): void => {\n this._drawer = e.detail;\n this._transcript.injectEntry({\n id: crypto.randomUUID(),\n type: 'system',\n state: 'complete',\n text: e.detail.title ?? 'Agent shared content',\n meta: { displayContent: e.detail },\n });\n };\n\n private _onDrawerClose = (): void => {\n this._drawer = null;\n };\n\n private _unwireCall(): void {\n const endedCall = this._call;\n const endedStatus = endedCall?.status;\n\n this._callState.disconnect();\n this._devices.disconnectCall();\n this._transcript.setCall(undefined);\n this._userEventCtrl.setCall(undefined);\n this.removeEventListener('sw-display-content', this._onDisplayContent as EventListener);\n\n this._call = null;\n this._connecting = false;\n this._hasLayoutLayers = false;\n this._drawer = null;\n\n if (endedCall) {\n // Fires for any terminal transition — user hangup, remote disconnect,\n // or failure. Distinct from `sw-call-hangup` which only fires when the\n // user clicks the hangup button.\n this.dispatchEvent(new CustomEvent('sw-call-ended', {\n detail: { status: endedStatus },\n bubbles: true,\n composed: true,\n }));\n }\n }\n\n // ── Slot trigger ───────────────────────────────────────────────────\n\n private _onSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n el.addEventListener('click', () => this.dial());\n }\n });\n }\n\n // ── Event handlers ─────────────────────────────────────────────────\n\n private _onHangUp(): void {\n this.hangup();\n }\n\n private _onModalClose = (e: Event): void => {\n if (this._call || this._connecting) {\n // Active call → hang up. Modal will close automatically once the\n // call reaches a terminal state and `_unwireCall` clears `_call`.\n this.hangup();\n return;\n }\n if (!this.destination) {\n // Pre-call dialpad state — no destination entered yet. Keep the\n // modal open so the user doesn't lose their in-progress dialing.\n e.preventDefault();\n }\n };\n\n private _onFullscreenToggle(): void {\n const layout = this.shadowRoot?.querySelector('sw-ui-call-layout');\n if (layout) {\n (layout as import('../UI/layout/sw-ui-call-layout.js').SwUiCallLayout).toggleFullscreen();\n }\n }\n\n private _onTranscriptToggle(): void {\n this.transcription = !this.transcription;\n }\n\n // ── Render ─────────────────────────────────────────────────────────\n\n render() {\n const isActive = !!(this._call || this._connecting);\n const body = this._call\n ? renderCallView({\n transcription: this.transcription,\n hasLayoutLayers: this._hasLayoutLayers,\n drawer: this._drawer,\n transcriptEntries: this._transcript.state.entries,\n onHangUp: this._onHangUp,\n onFullscreenToggle: this._onFullscreenToggle,\n onTranscriptToggle: this._onTranscriptToggle,\n onDrawerClose: this._onDrawerClose,\n })\n : this._connecting\n ? renderConnecting()\n : nothing;\n\n if (this.modal) {\n return html`\n <slot @slotchange=${this._onSlotChange}></slot>\n <sw-ui-modal ?open=${isActive} @sw-modal-close=${this._onModalClose}>\n <sw-ui-responsive-container>\n ${body !== nothing ? body : nothing}\n </sw-ui-responsive-container>\n </sw-ui-modal>\n `;\n }\n\n if (body !== nothing) return body;\n\n return html`<slot @slotchange=${this._onSlotChange}></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-call-widget': SwCallWidget;\n }\n}\n"],"names":["logger","getLogger","SwCallWidget","LitElement","CallStateContextController","DevicesContextController","TranscriptController","UserEventController","IncomingCallController","info","callerDisplay","showPrompt","e","ensureSignalWireTheme","ensureSignalWireFonts","changed","s","SignalWire","buildCredentialProvider","message","wantsVideo","call","resolve","reject","sub","filter","c","first","userVariables","withWidgetCapabilities","parseUserVariablesAttribute","layers","status","endedCall","endedStatus","el","layout","_a","isActive","body","renderCallView","renderConnecting","nothing","html","widgetStyles","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sw-call-widget.js","sources":["../../../src/components/sw-call-widget/sw-call-widget.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { SignalWire, getLogger } from '@signalwire/js';\nimport type { Call } from '../../types/index.js';\nimport { Subscription } from 'rxjs';\nimport { first, filter } from 'rxjs/operators';\n\nimport { CallStateContextController } from '../../context/CallStateContextController.js';\nimport { IncomingCallController } from '../../context/call-state-context.js';\nimport type { IncomingCallInfo } from '../../context/call-state-context.js';\nimport { DevicesContextController } from '../../context/DevicesContextController.js';\nimport { TranscriptController } from '../../context/TranscriptController.js';\nimport { UserEventController } from '../../context/UserEventController.js';\n\nimport '../sw-call-media.js';\nimport '../sw-local-camera.js';\nimport '../sw-call-controls.js';\nimport '../UI/layout/sw-ui-call-layout.js';\nimport '../UI/layout/sw-ui-responsive-container.js';\nimport '../UI/layout/sw-ui-modal.js';\nimport '../UI/layout/sw-ui-background.js';\nimport '../UI/layout/sw-ui-content-drawer.js';\nimport '../UI/sw-ui-transcript-view.js';\nimport { showPrompt } from '../UI/sw-ui-alert.js';\nimport type { DisplayContentPayload } from '../UI/layout/sw-ui-content-drawer.js';\nimport { ensureSignalWireTheme, ensureSignalWireFonts } from '../../utils/theme-loader.js';\nimport {\n parseUserVariablesAttribute,\n withWidgetCapabilities,\n} from '../../utils/user-variables.js';\nimport { hostReset } from '../UI/host-reset.js';\nimport { buildCredentialProvider } from './client-factory.js';\nimport {\n widgetStyles,\n renderCallView,\n renderConnecting,\n} from './sw-call-widget.templates.js';\n\nconst logger = getLogger();\n\n/**\n * All-in-one call widget. Handles client initialisation, dialling, media,\n * controls and optional AI transcript — in either inline or modal modes.\n *\n * Composes `sw-ui-call-layout`, `sw-call-media`, `sw-local-camera`,\n * `sw-call-controls`, and `sw-ui-transcript-view` under the hood.\n * All child components are wired via Lit context — no manual plumbing needed.\n *\n * @prop {string} token - SignalWire SAT or embed token\n * @prop {string} host - Optional server host\n * @prop {string} destination - Call destination (address or resource)\n * @prop {boolean} modal - Render in a `<sw-ui-modal>` overlay\n * @prop {boolean} transcription - Show AI transcript panel\n *\n * @slot background - Background element (e.g. `<sw-ui-background default>`)\n * @slot (default) - Trigger element (click to dial, shown when idle)\n *\n * @fires sw-dial - When `dial()` is invoked. Detail: `{ destination }`.\n * @fires sw-call-ended - When the call reaches a terminal state (user hangup, remote disconnect, or failure). Detail: `{ status }`.\n * @fires sw-display-content - From `display_content` user event. Detail: `DisplayContentPayload`.\n * @fires signalwire-address:event - Forwarded SignalWire custom user events.\n *\n * All inner events bubble.\n *\n * @method dial() - Initiate call\n * @method hangup() - End active call\n */\n@customElement('sw-call-widget')\nexport class SwCallWidget extends LitElement {\n static styles = [hostReset, widgetStyles];\n\n // ── Public properties ──────────────────────────────────────────────\n\n @property({ type: String }) token = '';\n @property({ type: String }) host = '';\n @property({ type: String }) destination = '';\n @property({ type: Boolean, reflect: true }) modal = false;\n @property({ type: Boolean, reflect: true }) transcription = false;\n @property({ type: Boolean, reflect: true, attribute: 'allow-incoming-calls' }) allowIncomingCalls = false;\n @property({ type: Boolean, reflect: true, attribute: 'audio-only' }) audioOnly = false;\n\n /**\n * Custom variables sent with the Verto invite as a JSON object.\n *\n * The widget always advertises `capabilities.display_content` and\n * `metadata.widget.opened_at` so the agent can detect that the caller\n * supports the content drawer; user-supplied keys are merged in and win\n * on shallow conflict.\n *\n * Invalid JSON is logged and ignored — the call still dials.\n *\n * @example\n * <sw-call-widget user-variables='{\"customer_id\": \"abc-123\"}'></sw-call-widget>\n */\n @property({ type: String, attribute: 'user-variables' }) userVariables = '';\n\n /**\n * Skip auto-injecting the SignalWire `theme.css` design-token stylesheet.\n * Set this when the host page already loads `@signalwire/web-components/theme.css`\n * or a custom theme written against the same DTCG token names.\n */\n @property({ type: Boolean, reflect: true, attribute: 'disable-auto-theme' }) disableAutoTheme = false;\n\n /**\n * Skip auto-loading the SignalWire brand fonts (Lexend, Instrument Sans,\n * JetBrains Mono) from Google Fonts. Set this when fonts are self-hosted\n * or loaded elsewhere.\n */\n @property({ type: Boolean, reflect: true, attribute: 'disable-auto-fonts' }) disableAutoFonts = false;\n\n // ── Internal state ─────────────────────────────────────────────────\n\n @state() private _call: Call | null = null;\n @state() private _connecting = false;\n @state() private _hasLayoutLayers = false;\n @state() private _drawer: DisplayContentPayload | null = null;\n\n // ── Context providers ──────────────────────────────────────────────\n\n private _callState = new CallStateContextController(this);\n private _devices = new DevicesContextController(this);\n private _transcript: TranscriptController = new TranscriptController(this);\n private _userEventCtrl = new UserEventController(this);\n private _incomingCalls = new IncomingCallController(this);\n\n // ── Internals ──────────────────────────────────────────────────────\n\n private _client: SignalWire | null = null;\n private _subs: Subscription[] = [];\n private _pendingIncoming = false;\n\n // ── Lifecycle ──────────────────────────────────────────────────────\n\n connectedCallback(): void {\n super.connectedCallback();\n if (!this.disableAutoTheme) ensureSignalWireTheme();\n if (!this.disableAutoFonts) ensureSignalWireFonts();\n }\n\n protected updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n if (changed.has('token') || changed.has('host')) {\n if (this.token) {\n this._refreshClient();\n } else if (changed.has('host')) {\n // Host changed but no token configured yet — defer client init until\n // the consumer sets `.token`. Surface this so misconfigurations\n // (e.g. forgetting to bind token) don't fail silently.\n logger.debug(\n '[SwCallWidget] host changed but token is empty; skipping client refresh until token is set',\n );\n }\n } else if (changed.has('allowIncomingCalls') && this._client) {\n if (this.allowIncomingCalls) {\n this._connectIncomingCalls();\n } else {\n this._incomingCalls.disconnect();\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this._destroyClient();\n }\n\n // ── Client lifecycle ───────────────────────────────────────────────\n\n private _destroyClient(): void {\n this._subs.forEach((s) => s.unsubscribe());\n this._subs = [];\n\n this._incomingCalls.disconnect();\n this._devices.disconnectCall();\n this._devices.disconnect();\n this._callState.disconnect();\n this._transcript.setCall(undefined);\n\n\n if (this._client) {\n try {\n this._client.destroy();\n } catch (e) {\n logger.error('[SwCallWidget] Error destroying client:', e);\n }\n this._client = null;\n }\n\n this._call = null;\n this._connecting = false;\n }\n\n private _refreshClient(): void {\n this._destroyClient();\n try {\n this._client = new SignalWire(\n buildCredentialProvider(this.token, this.host),\n );\n this._devices.connectDevices(this._client as unknown as import('../../types/index.js').DeviceController);\n\n if (this.allowIncomingCalls) {\n this._connectIncomingCalls();\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Failed to initialise client';\n logger.error('[SwCallWidget] Failed to initialise client:', e);\n void showPrompt({ title: 'Client Error', description: message, type: 'alert' });\n }\n }\n\n // ── Public methods ─────────────────────────────────────────────────\n\n async dial(): Promise<void> {\n if (!this._client || this._connecting || this._call) return;\n if (!this.destination) {\n void showPrompt({ title: 'Call Error', description: 'No destination configured.', type: 'alert' });\n return;\n }\n\n this._connecting = true;\n\n this.dispatchEvent(new CustomEvent('sw-dial', {\n detail: { destination: this.destination },\n bubbles: true,\n composed: true,\n }));\n\n const wantsVideo = !this.audioOnly;\n\n try {\n const call = await new Promise<Call>((resolve, reject) => {\n const sub = this._client!.isConnected$\n .pipe(filter((c) => c), first())\n .subscribe({\n next: () => {\n const userVariables = withWidgetCapabilities(\n parseUserVariablesAttribute(this.userVariables)\n );\n this._client!\n .dial(this.destination, {\n audio: true,\n video: wantsVideo,\n receiveAudio: true,\n receiveVideo: wantsVideo,\n userVariables,\n })\n .then(resolve)\n .catch(reject);\n },\n error: reject,\n });\n this._subs.push(sub);\n });\n\n this._wireCall(call);\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Failed to connect call';\n logger.error('[SwCallWidget] Dial failed:', e);\n void showPrompt({ title: 'Call Failed', description: message, type: 'alert' });\n } finally {\n this._connecting = false;\n }\n }\n\n async hangup(): Promise<void> {\n if (this._call) {\n await this._call.hangup();\n }\n }\n\n // ── Incoming calls ──────────────────────────────────────────────────\n\n private _connectIncomingCalls(): void {\n if (!this._client) return;\n this._incomingCalls.onIncomingCall = this._handleIncomingCall;\n this._subs.push(\n this._client.isConnected$\n .pipe(filter(Boolean), first())\n .subscribe(() => {\n if (this._client) {\n this._incomingCalls.connect(this._client.session.incomingCalls$);\n }\n })\n );\n }\n\n private _handleIncomingCall = async (info: IncomingCallInfo): Promise<void> => {\n if (this._call || this._connecting || this._pendingIncoming) return;\n this._pendingIncoming = true;\n\n try {\n const callerDisplay = info.callerName || info.callerNumber || 'Unknown Caller';\n // TODO(ringing-ux): the confirm dialog is a placeholder, not a real\n // ringing UI. Missing: caller avatar, audible ringtone, distinction\n // between \"ignore\" (let it keep ringing) and \"reject\" (decline now),\n // and a timeout. Replace with a dedicated `<sw-ui-incoming-call>`.\n const accepted = await showPrompt({\n title: 'Incoming Call',\n description: `${callerDisplay} is calling`,\n type: 'confirm',\n });\n\n if (accepted) {\n this._wireCall(info.call);\n info.call.answer();\n } else {\n info.call.reject();\n }\n } finally {\n this._pendingIncoming = false;\n }\n };\n\n // ── Call wiring ────────────────────────────────────────────────────\n\n private _wireCall(call: Call): void {\n this._call = call;\n\n // Wire contexts\n this._callState.connect(call);\n this._devices.connectCall(call);\n this._transcript.setCall(call);\n\n // Always subscribe to user_event for display_content and pass-through\n this._userEventCtrl.setCall(call);\n this.addEventListener('sw-display-content', this._onDisplayContent as EventListener);\n\n // Re-enumerate devices now that getUserMedia has granted permission\n this._devices.refreshDevices();\n\n // Track layout layers to know when MCU composites local camera\n this._subs.push(\n call.layoutLayers$.subscribe((layers) => {\n this._hasLayoutLayers = layers.length > 0;\n })\n );\n\n // Watch for call end\n this._subs.push(\n call.status$.subscribe((status) => {\n if (\n status === 'disconnected' ||\n status === 'destroyed' ||\n status === 'failed'\n ) {\n this._unwireCall();\n }\n })\n );\n }\n\n private _onDisplayContent = (e: CustomEvent<DisplayContentPayload>): void => {\n this._drawer = e.detail;\n this._transcript.injectEntry({\n id: crypto.randomUUID(),\n type: 'system',\n state: 'complete',\n text: e.detail.title ?? 'Agent shared content',\n meta: { displayContent: e.detail },\n });\n };\n\n private _onDrawerClose = (): void => {\n this._drawer = null;\n };\n\n private _unwireCall(): void {\n const endedCall = this._call;\n const endedStatus = endedCall?.status;\n\n this._callState.disconnect();\n this._devices.disconnectCall();\n this._transcript.setCall(undefined);\n this._userEventCtrl.setCall(undefined);\n this.removeEventListener('sw-display-content', this._onDisplayContent as EventListener);\n\n this._call = null;\n this._connecting = false;\n this._hasLayoutLayers = false;\n this._drawer = null;\n\n if (endedCall) {\n // Fires for any terminal transition — user hangup, remote disconnect,\n // or failure. Distinct from `sw-call-hangup` which only fires when the\n // user clicks the hangup button.\n this.dispatchEvent(new CustomEvent('sw-call-ended', {\n detail: { status: endedStatus },\n bubbles: true,\n composed: true,\n }));\n }\n }\n\n // ── Slot trigger ───────────────────────────────────────────────────\n\n private _onSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n el.addEventListener('click', () => this.dial());\n }\n });\n }\n\n // ── Event handlers ─────────────────────────────────────────────────\n\n private _onHangUp(): void {\n this.hangup();\n }\n\n private _onModalClose = (e: Event): void => {\n if (this._call || this._connecting) {\n // Active call → hang up. Modal will close automatically once the\n // call reaches a terminal state and `_unwireCall` clears `_call`.\n this.hangup();\n return;\n }\n if (!this.destination) {\n // Pre-call dialpad state — no destination entered yet. Keep the\n // modal open so the user doesn't lose their in-progress dialing.\n e.preventDefault();\n }\n };\n\n private _onFullscreenToggle(): void {\n const layout = this.shadowRoot?.querySelector('sw-ui-call-layout');\n if (layout) {\n (layout as import('../UI/layout/sw-ui-call-layout.js').SwUiCallLayout).toggleFullscreen();\n }\n }\n\n private _onTranscriptToggle(): void {\n this.transcription = !this.transcription;\n }\n\n // ── Render ─────────────────────────────────────────────────────────\n\n render() {\n const isActive = !!(this._call || this._connecting);\n const body = this._call\n ? renderCallView({\n transcription: this.transcription,\n hasLayoutLayers: this._hasLayoutLayers,\n drawer: this._drawer,\n transcriptEntries: this._transcript.state.entries,\n onHangUp: this._onHangUp,\n onFullscreenToggle: this._onFullscreenToggle,\n onTranscriptToggle: this._onTranscriptToggle,\n onDrawerClose: this._onDrawerClose,\n })\n : this._connecting\n ? renderConnecting()\n : nothing;\n\n if (this.modal) {\n return html`\n <slot @slotchange=${this._onSlotChange}></slot>\n <sw-ui-modal ?open=${isActive} @sw-modal-close=${this._onModalClose}>\n <sw-ui-responsive-container>\n ${body !== nothing ? body : nothing}\n </sw-ui-responsive-container>\n </sw-ui-modal>\n `;\n }\n\n if (body !== nothing) return body;\n\n return html`<slot @slotchange=${this._onSlotChange}></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-call-widget': SwCallWidget;\n }\n}\n"],"names":["logger","getLogger","SwCallWidget","LitElement","CallStateContextController","DevicesContextController","TranscriptController","UserEventController","IncomingCallController","info","callerDisplay","showPrompt","e","ensureSignalWireTheme","ensureSignalWireFonts","changed","s","SignalWire","buildCredentialProvider","message","wantsVideo","call","resolve","reject","sub","filter","c","first","userVariables","withWidgetCapabilities","parseUserVariablesAttribute","layers","status","endedCall","endedStatus","el","layout","_a","isActive","body","renderCallView","renderConnecting","nothing","html","hostReset","widgetStyles","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -23,7 +23,7 @@ import './UI/icons/sw-ui-icon.js';
|
|
|
23
23
|
* `--type-family-body`, `--type-size-body`, `--radius-md`, `--transition-fast`).
|
|
24
24
|
*/
|
|
25
25
|
export declare class SwClickToCall extends LitElement {
|
|
26
|
-
static styles: import("lit").CSSResult;
|
|
26
|
+
static styles: import("lit").CSSResult[];
|
|
27
27
|
token: string;
|
|
28
28
|
host: string;
|
|
29
29
|
destination: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-click-to-call.d.ts","sourceRoot":"","sources":["../../src/components/sw-click-to-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,OAAO,oCAAoC,CAAC;AAC5C,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"sw-click-to-call.d.ts","sourceRoot":"","sources":["../../src/components/sw-click-to-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,OAAO,oCAAoC,CAAC;AAC5C,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC;AAGlC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,MAAM,CAAC,MAAM,4BAkCV;IAEyB,KAAK,SAAM;IACX,IAAI,SAAM;IACV,WAAW,SAAM;IACjB,KAAK,SAAU;IAC0B,SAAS,UAAS;IAEvF,MAAM;CAkBP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,aAAa,CAAC;KACnC;CACF"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { LitElement as
|
|
1
|
+
import { LitElement as c, html as u, css as d } from "lit";
|
|
2
2
|
import { property as n, customElement as f } from "lit/decorators.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { hostReset as y } from "./UI/host-reset.js";
|
|
4
|
+
var b = Object.defineProperty, h = Object.getOwnPropertyDescriptor, o = (p, i, s, r) => {
|
|
5
|
+
for (var e = r > 1 ? void 0 : r ? h(i, s) : i, l = p.length - 1, a; l >= 0; l--)
|
|
6
|
+
(a = p[l]) && (e = (r ? a(i, s, e) : a(e)) || e);
|
|
7
|
+
return r && e && b(i, s, e), e;
|
|
7
8
|
};
|
|
8
|
-
let t = class extends
|
|
9
|
+
let t = class extends c {
|
|
9
10
|
constructor() {
|
|
10
11
|
super(...arguments), this.token = "", this.host = "", this.destination = "", this.label = "Call", this.audioOnly = !1;
|
|
11
12
|
}
|
|
@@ -28,7 +29,7 @@ let t = class extends p {
|
|
|
28
29
|
`;
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
t.styles = d`
|
|
32
|
+
t.styles = [y, d`
|
|
32
33
|
:host {
|
|
33
34
|
display: inline-block;
|
|
34
35
|
font-family: var(--type-family-body);
|
|
@@ -62,7 +63,7 @@ t.styles = d`
|
|
|
62
63
|
.call-button sw-ui-icon {
|
|
63
64
|
pointer-events: none;
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
`];
|
|
66
67
|
o([
|
|
67
68
|
n({ type: String })
|
|
68
69
|
], t.prototype, "token", 2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-click-to-call.js","sources":["../../src/components/sw-click-to-call.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport './sw-call-widget/sw-call-widget.js';\nimport './UI/layout/sw-ui-background.js';\nimport './UI/icons/sw-ui-icon.js';\n\n/**\n * Click-to-call button that opens a full call widget.\n *\n * Thin wrapper around `sw-call-widget` in modal mode. Renders a styled\n * call button; clicking it dials the preconfigured destination and opens\n * the call UI in a modal overlay.\n *\n * @prop {string} token - SignalWire SAT or embed token\n * @prop {string} host - Optional server host\n * @prop {string} destination - Call destination (address or resource)\n * @prop {string} label - Button text (default \"Call\")\n * @prop {boolean} audioOnly - Audio-only mode (no video send/receive)\n *\n * @fires sw-dial - Fired when the call is initiated. Detail: `{ destination }`.\n * @fires sw-call-ended - Fired when the call reaches a terminal state (any reason). Detail: `{ status }`.\n * @fires sw-call-hangup - Fired when the user clicks the hangup button (does not fire on remote disconnect).\n *\n * Themed via the SignalWire DTCG tokens (`--interactive-status-success`,\n * `--type-family-body`, `--type-size-body`, `--radius-md`, `--transition-fast`).\n */\n@customElement('sw-click-to-call')\nexport class SwClickToCall extends LitElement {\n static styles = css`\n :host {\n display: inline-block;\n font-family: var(--type-family-body);\n }\n\n .call-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n background: var(--interactive-status-success);\n color: #fff;\n border: none;\n border-radius: var(--radius-md);\n font-family: inherit;\n font-size: var(--type-size-body);\n font-weight: 600;\n cursor: pointer;\n transition: filter var(--transition-fast), transform 0.1s ease;\n }\n\n .call-button:hover {\n filter: brightness(0.9);\n }\n\n .call-button:active {\n transform: scale(0.98);\n }\n\n .call-button sw-ui-icon {\n pointer-events: none;\n }\n
|
|
1
|
+
{"version":3,"file":"sw-click-to-call.js","sources":["../../src/components/sw-click-to-call.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport './sw-call-widget/sw-call-widget.js';\nimport './UI/layout/sw-ui-background.js';\nimport './UI/icons/sw-ui-icon.js';\nimport { hostReset } from './UI/host-reset.js';\n\n/**\n * Click-to-call button that opens a full call widget.\n *\n * Thin wrapper around `sw-call-widget` in modal mode. Renders a styled\n * call button; clicking it dials the preconfigured destination and opens\n * the call UI in a modal overlay.\n *\n * @prop {string} token - SignalWire SAT or embed token\n * @prop {string} host - Optional server host\n * @prop {string} destination - Call destination (address or resource)\n * @prop {string} label - Button text (default \"Call\")\n * @prop {boolean} audioOnly - Audio-only mode (no video send/receive)\n *\n * @fires sw-dial - Fired when the call is initiated. Detail: `{ destination }`.\n * @fires sw-call-ended - Fired when the call reaches a terminal state (any reason). Detail: `{ status }`.\n * @fires sw-call-hangup - Fired when the user clicks the hangup button (does not fire on remote disconnect).\n *\n * Themed via the SignalWire DTCG tokens (`--interactive-status-success`,\n * `--type-family-body`, `--type-size-body`, `--radius-md`, `--transition-fast`).\n */\n@customElement('sw-click-to-call')\nexport class SwClickToCall extends LitElement {\n static styles = [hostReset, css`\n :host {\n display: inline-block;\n font-family: var(--type-family-body);\n }\n\n .call-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n background: var(--interactive-status-success);\n color: #fff;\n border: none;\n border-radius: var(--radius-md);\n font-family: inherit;\n font-size: var(--type-size-body);\n font-weight: 600;\n cursor: pointer;\n transition: filter var(--transition-fast), transform 0.1s ease;\n }\n\n .call-button:hover {\n filter: brightness(0.9);\n }\n\n .call-button:active {\n transform: scale(0.98);\n }\n\n .call-button sw-ui-icon {\n pointer-events: none;\n }\n `];\n\n @property({ type: String }) token = '';\n @property({ type: String }) host = '';\n @property({ type: String }) destination = '';\n @property({ type: String }) label = 'Call';\n @property({ type: Boolean, reflect: true, attribute: 'audio-only' }) audioOnly = false;\n\n render() {\n return html`\n <sw-call-widget\n modal\n transcription\n ?audio-only=${this.audioOnly}\n .token=${this.token}\n .host=${this.host}\n .destination=${this.destination}\n >\n <sw-ui-background slot=\"background\" default></sw-ui-background>\n <button class=\"call-button\" part=\"button\">\n <sw-ui-icon name=\"phone-call\" size=\"20\"></sw-ui-icon>\n ${this.label}\n </button>\n </sw-call-widget>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-click-to-call': SwClickToCall;\n }\n}\n"],"names":["SwClickToCall","LitElement","html","hostReset","css","__decorateClass","property","customElement"],"mappings":";;;;;;;;AA4BO,IAAMA,IAAN,cAA4BC,EAAW;AAAA,EAAvC,cAAA;AAAA,UAAA,GAAA,SAAA,GAqCuB,KAAA,QAAQ,IACR,KAAA,OAAO,IACP,KAAA,cAAc,IACd,KAAA,QAAQ,QACiC,KAAA,YAAY;AAAA,EAAA;AAAA,EAEjF,SAAS;AACP,WAAOC;AAAA;AAAA;AAAA;AAAA,sBAIW,KAAK,SAAS;AAAA,iBACnB,KAAK,KAAK;AAAA,gBACX,KAAK,IAAI;AAAA,uBACF,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,YAK3B,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,EAIpB;AACF;AA7DaF,EACJ,SAAS,CAACG,GAAWC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAkC3B;AAE2BC,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GArCfN,EAqCiB,WAAA,SAAA,CAAA;AACAK,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAtCfN,EAsCiB,WAAA,QAAA,CAAA;AACAK,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAvCfN,EAuCiB,WAAA,eAAA,CAAA;AACAK,EAAA;AAAA,EAA3BC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAxCfN,EAwCiB,WAAA,SAAA,CAAA;AACyCK,EAAA;AAAA,EAApEC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM,WAAW,cAAc;AAAA,GAzCxDN,EAyC0D,WAAA,aAAA,CAAA;AAzC1DA,IAANK,EAAA;AAAA,EADNE,EAAc,kBAAkB;AAAA,GACpBP,CAAA;"}
|
|
@@ -16,7 +16,7 @@ import '../sw-audio-level.js';
|
|
|
16
16
|
* @cssprop --ctrl-* - all primitive ctrl tokens
|
|
17
17
|
*/
|
|
18
18
|
export declare class SwDeviceSelector extends LitElement {
|
|
19
|
-
static styles: import("lit").CSSResult;
|
|
19
|
+
static styles: import("lit").CSSResult[];
|
|
20
20
|
deviceController?: DeviceController;
|
|
21
21
|
/**
|
|
22
22
|
* Render inline previews (camera video, mic level, speaker test) inside
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-device-selector.d.ts","sourceRoot":"","sources":["../../../src/components/sw-device-selector/sw-device-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,KAAK,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sw-device-selector.d.ts","sourceRoot":"","sources":["../../../src/components/sw-device-selector/sw-device-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,KAAK,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKvD,OAAO,2BAA2B,CAAC;AACnC,OAAO,uBAAuB,CAAC;AAC/B,OAAO,sBAAsB,CAAC;AAQ9B;;;;;;;;;;;GAWG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IAC9C,MAAM,CAAC,MAAM,4BAAqC;IAEtB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEhE;;;;OAIG;IAEH,WAAW,UAAS;IAEX,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,KAAK,CAAS;IAE/B,OAAO,CAAC,KAAK,CAAsB;IAEnC,OAAO,CAAC,gBAAgB,CAEtB;IAEF,iBAAiB;IAMjB,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAQtD,oBAAoB;IASpB,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IA+BzD,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;YASR,kBAAkB;IAYhC,OAAO,CAAC,iBAAiB;YAKX,kBAAkB;IAYhC,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CACwqC;IAEntC,OAAO,CAAC,UAAU,CAAC,CAAyB;YAE9B,YAAY;IA2B1B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,cAAc;IAmCtB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,qBAAqB;IAmB7B,MAAM;CA8BP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
|
|
@@ -2,10 +2,11 @@ import { LitElement as v, nothing as l, html as n } from "lit";
|
|
|
2
2
|
import { property as p, state as c, customElement as m } from "lit/decorators.js";
|
|
3
3
|
import { getLogger as b } from "@signalwire/js";
|
|
4
4
|
import { deviceSelectorStyles as w } from "./sw-device-selector.styles.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { hostReset as k } from "../UI/host-reset.js";
|
|
6
|
+
var I = Object.defineProperty, f = Object.getOwnPropertyDescriptor, a = (e, i, t, s) => {
|
|
7
|
+
for (var o = s > 1 ? void 0 : s ? f(i, t) : i, h = e.length - 1, d; h >= 0; h--)
|
|
7
8
|
(d = e[h]) && (o = (s ? d(i, t, o) : d(o)) || o);
|
|
8
|
-
return s && o &&
|
|
9
|
+
return s && o && I(i, t, o), o;
|
|
9
10
|
};
|
|
10
11
|
const u = b();
|
|
11
12
|
let r = class extends v {
|
|
@@ -230,7 +231,7 @@ let r = class extends v {
|
|
|
230
231
|
`;
|
|
231
232
|
}
|
|
232
233
|
};
|
|
233
|
-
r.styles = w;
|
|
234
|
+
r.styles = [k, w];
|
|
234
235
|
r._TEST_TONE_DATA_URI = "data:audio/wav;base64,UklGRrQEAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YZAEAACAh46Sl5qcm5mWko2HgXp1cGxqaWlsb3R5gIaNk5icnp2bl5OOiIJ8dnFtamhoam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamlo";
|
|
235
236
|
a([
|
|
236
237
|
p({ type: Object })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-device-selector.js","sources":["../../../src/components/sw-device-selector/sw-device-selector.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { Subscription } from 'rxjs';\nimport type { DeviceController } from '@signalwire/js';\nimport { getLogger } from '@signalwire/js';\nimport type { IconName } from '../UI/icons/icons.js';\nimport { deviceSelectorStyles } from './sw-device-selector.styles.js';\nimport '../UI/icons/sw-ui-icon.js';\nimport '../sw-local-camera.js';\nimport '../sw-audio-level.js';\n\nconst logger = getLogger();\n\ntype AudioElementWithSinkId = HTMLAudioElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n};\n\n/**\n * Single-button device settings popover. Opens a panel above the button\n * with sections for Microphone, Camera, and Speaker selection.\n *\n * When `show-preview` is enabled, the open panel also renders a live\n * camera preview, a microphone level meter for the currently selected\n * input devices, and a \"Test speaker\" button that plays a short tone\n * through the selected output.\n *\n * @fires sw-device-change - User picked a device. Detail: `{ type: 'microphone'|'camera'|'speaker', device: MediaDeviceInfo }`.\n * @cssprop --ctrl-* - all primitive ctrl tokens\n */\n@customElement('sw-device-selector')\nexport class SwDeviceSelector extends LitElement {\n static styles = deviceSelectorStyles;\n\n @property({ type: Object }) deviceController?: DeviceController;\n\n /**\n * Render inline previews (camera video, mic level, speaker test) inside\n * each section while the panel is open. Streams are acquired only while\n * the panel is open and stopped when it closes.\n */\n @property({ type: Boolean, reflect: true, attribute: 'show-preview' })\n showPreview = false;\n\n @state() private _videoStream: MediaStream | null = null;\n @state() private _audioStream: MediaStream | null = null;\n @state() private _testingSpeaker = false;\n\n @state() private _audioIn: MediaDeviceInfo[] = [];\n @state() private _videoIn: MediaDeviceInfo[] = [];\n @state() private _audioOut: MediaDeviceInfo[] = [];\n @state() private _selAudioIn: MediaDeviceInfo | null = null;\n @state() private _selVideoIn: MediaDeviceInfo | null = null;\n @state() private _selAudioOut: MediaDeviceInfo | null = null;\n @state() private _open = false;\n\n private _subs: Subscription[] = [];\n\n private _onDocumentClick = (e: MouseEvent) => {\n if (!e.composedPath().includes(this)) this._open = false;\n };\n\n connectedCallback() {\n super.connectedCallback();\n document.addEventListener('click', this._onDocumentClick);\n this._subscribe();\n }\n\n protected updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n if (changed.has('deviceController')) {\n this._unsubscribe();\n this._subscribe();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('click', this._onDocumentClick);\n this._unsubscribe();\n this._stopVideoPreview();\n this._stopAudioPreview();\n this._stopTestTone();\n }\n\n protected willUpdate(changed: Map<string, unknown>): void {\n if (!this.showPreview) {\n if (changed.has('showPreview') || changed.has('_open')) {\n this._stopVideoPreview();\n this._stopAudioPreview();\n }\n return;\n }\n\n const opened = changed.has('_open') && this._open;\n const closed = changed.has('_open') && !this._open;\n const cameraChanged = changed.has('_selVideoIn');\n const micChanged = changed.has('_selAudioIn');\n\n if (closed) {\n this._stopVideoPreview();\n this._stopAudioPreview();\n this._stopTestTone();\n return;\n }\n\n if (this._open && (opened || cameraChanged) && this._selVideoIn) {\n this._startVideoPreview(this._selVideoIn.deviceId);\n }\n if (this._open && (opened || micChanged) && this._selAudioIn) {\n this._startAudioPreview(this._selAudioIn.deviceId);\n }\n }\n\n // ── subscriptions ──────────────────────────────────────────────────\n\n private _subscribe(): void {\n const dc = this.deviceController;\n if (!dc) return;\n\n this._subs.push(dc.audioInputDevices$.subscribe((d) => { this._audioIn = d; }));\n this._subs.push(dc.videoInputDevices$.subscribe((d) => { this._videoIn = d; }));\n this._subs.push(dc.audioOutputDevices$.subscribe((d) => { this._audioOut = d; }));\n\n if (dc.selectedAudioInputDevice$)\n this._subs.push(dc.selectedAudioInputDevice$.subscribe((d) => { this._selAudioIn = d; }));\n if (dc.selectedVideoInputDevice$)\n this._subs.push(dc.selectedVideoInputDevice$.subscribe((d) => { this._selVideoIn = d; }));\n if (dc.selectedAudioOutputDevice$)\n this._subs.push(dc.selectedAudioOutputDevice$.subscribe((d) => { this._selAudioOut = d; }));\n }\n\n private _unsubscribe(): void {\n this._subs.forEach((s) => s.unsubscribe());\n this._subs = [];\n }\n\n // ── handlers ──────────────────────────────────────────────────────\n\n private _toggle(e: Event) {\n e.stopPropagation();\n this._open = !this._open;\n }\n\n private _selectMic(deviceId: string) {\n const device = this._audioIn.find((d) => d.deviceId === deviceId) ?? null;\n this._selAudioIn = device;\n this.deviceController?.selectAudioInputDevice?.(device);\n if (device) this._emitChange('microphone', device);\n }\n\n private _selectCamera(deviceId: string) {\n const device = this._videoIn.find((d) => d.deviceId === deviceId) ?? null;\n this._selVideoIn = device;\n this.deviceController?.selectVideoInputDevice?.(device);\n if (device) this._emitChange('camera', device);\n }\n\n private _selectSpeaker(deviceId: string) {\n const device = this._audioOut.find((d) => d.deviceId === deviceId) ?? null;\n this._selAudioOut = device;\n this.deviceController?.selectAudioOutputDevice?.(device);\n if (device) this._emitChange('speaker', device);\n }\n\n // ── preview streams ───────────────────────────────────────────────\n\n private async _startVideoPreview(deviceId: string): Promise<void> {\n this._stopVideoPreview();\n try {\n this._videoStream = await navigator.mediaDevices.getUserMedia({\n video: { deviceId: { exact: deviceId } }\n });\n } catch (error) {\n logger.error('sw-device-selector: failed to start camera preview', error);\n this._videoStream = null;\n }\n }\n\n private _stopVideoPreview(): void {\n this._videoStream?.getTracks().forEach((t) => t.stop());\n this._videoStream = null;\n }\n\n private async _startAudioPreview(deviceId: string): Promise<void> {\n this._stopAudioPreview();\n try {\n this._audioStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: { exact: deviceId } }\n });\n } catch (error) {\n logger.error('sw-device-selector: failed to start microphone preview', error);\n this._audioStream = null;\n }\n }\n\n private _stopAudioPreview(): void {\n this._audioStream?.getTracks().forEach((t) => t.stop());\n this._audioStream = null;\n }\n\n // ── speaker test ──────────────────────────────────────────────────\n\n private static readonly _TEST_TONE_DATA_URI =\n 'data:audio/wav;base64,UklGRrQEAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YZAEAACAh46Sl5qcm5mWko2HgXp1cGxqaWlsb3R5gIaNk5icnp2bl5OOiIJ8dnFtamhoam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamlo';\n\n private _testAudio?: AudioElementWithSinkId;\n\n private async _testSpeaker(): Promise<void> {\n if (this._testingSpeaker) {\n this._stopTestTone();\n return;\n }\n const audio = new Audio(SwDeviceSelector._TEST_TONE_DATA_URI) as AudioElementWithSinkId;\n audio.loop = true;\n this._testAudio = audio;\n\n const sinkId = this._selAudioOut?.deviceId;\n if (sinkId && typeof audio.setSinkId === 'function') {\n try {\n await audio.setSinkId(sinkId);\n } catch (error) {\n logger.error('sw-device-selector: setSinkId failed', error);\n }\n }\n audio.addEventListener('ended', () => this._stopTestTone());\n try {\n await audio.play();\n this._testingSpeaker = true;\n } catch (error) {\n logger.error('sw-device-selector: failed to play test tone', error);\n this._stopTestTone();\n }\n }\n\n private _stopTestTone(): void {\n if (this._testAudio) {\n this._testAudio.pause();\n this._testAudio.src = '';\n this._testAudio = undefined;\n }\n this._testingSpeaker = false;\n }\n\n private _emitChange(type: 'microphone' | 'camera' | 'speaker', device: MediaDeviceInfo) {\n this.dispatchEvent(new CustomEvent('sw-device-change', {\n detail: { type, device },\n bubbles: true,\n composed: true\n }));\n }\n\n // ── render helpers ────────────────────────────────────────────────\n\n private _renderSection(\n iconName: IconName,\n title: string,\n devices: MediaDeviceInfo[],\n selectedId: string | undefined,\n onSelect: (id: string) => void,\n preview?: unknown\n ) {\n return html`\n <div class=\"section\">\n <div class=\"section-header\">\n <sw-ui-icon name=${iconName} size=\"13\"></sw-ui-icon>\n <span>${title}</span>\n </div>\n ${devices.length === 0\n ? html`<div class=\"no-devices\">No devices found</div>`\n : devices.map((d, i) => html`\n <div\n class=\"device-item ${d.deviceId === selectedId ? 'selected' : ''}\"\n role=\"option\"\n aria-selected=${d.deviceId === selectedId}\n @click=${() => onSelect(d.deviceId)}\n >\n <svg class=\"check\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M6.5 12L2 7.5l1.4-1.4 3.1 3.1 5.6-5.6 1.4 1.4z\" />\n </svg>\n <span class=\"device-label\">${d.label || `Device ${i + 1}`}</span>\n </div>\n `)\n }\n ${preview ?? nothing}\n </div>\n `;\n }\n\n private _renderCameraPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-camera\" part=\"preview-camera\">\n ${this._videoStream\n ? html`<sw-local-camera .stream=${this._videoStream} mirror></sw-local-camera>`\n : html`<div class=\"preview-empty\">Starting camera…</div>`}\n </div>\n `;\n }\n\n private _renderMicPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-mic\" part=\"preview-mic\">\n ${this._audioStream\n ? html`<sw-audio-level\n .stream=${this._audioStream}\n bars=\"9\"\n orientation=\"horizontal\"\n maxSize=\"22\"\n ></sw-audio-level>`\n : html`<div class=\"preview-empty\">Starting microphone…</div>`}\n </div>\n `;\n }\n\n private _renderSpeakerPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-speaker\" part=\"preview-speaker\">\n <button\n class=\"test-speaker\"\n part=\"test-speaker-button\"\n ?disabled=${!this._selAudioOut}\n @click=${(e: Event) => { e.stopPropagation(); this._testSpeaker(); }}\n >\n <sw-ui-icon name=${this._testingSpeaker ? 'speaker-off' : 'speaker-on'} size=\"14\"></sw-ui-icon>\n <span>${this._testingSpeaker ? 'Stop test' : 'Test speaker'}</span>\n </button>\n </div>\n `;\n }\n\n // ── render ─────────────────────────────────────────────────────────\n\n render() {\n const hasDevices = this._audioIn.length > 0 || this._videoIn.length > 0 || this._audioOut.length > 0;\n\n return html`\n ${this._open ? html`\n <div\n class=\"panel\"\n role=\"listbox\"\n @keydown=${(e: KeyboardEvent) => { if (e.key === 'Escape') this._open = false; }}\n >\n ${this._renderSection('mic-on', 'Microphone', this._audioIn, this._selAudioIn?.deviceId, (id) => this._selectMic(id), this._renderMicPreview())}\n ${this._renderSection('camera-on', 'Camera', this._videoIn, this._selVideoIn?.deviceId, (id) => this._selectCamera(id), this._renderCameraPreview())}\n ${this._renderSection('speaker-on', 'Speaker', this._audioOut, this._selAudioOut?.deviceId, (id) => this._selectSpeaker(id), this._renderSpeakerPreview())}\n </div>\n ` : nothing}\n\n <button\n class=\"trigger\"\n aria-label=\"Device settings\"\n aria-expanded=${this._open}\n aria-haspopup=\"listbox\"\n ?disabled=${!hasDevices}\n @click=${this._toggle}\n part=\"button\"\n >\n <sw-ui-icon name=\"settings\" size=\"22\"></sw-ui-icon>\n </button>\n <span class=\"label\">Devices</span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-device-selector': SwDeviceSelector;\n }\n}\n"],"names":["logger","getLogger","SwDeviceSelector","LitElement","changed","opened","closed","cameraChanged","micChanged","dc","d","s","deviceId","device","_b","_a","error","t","audio","sinkId","type","iconName","title","devices","selectedId","onSelect","preview","html","i","nothing","hasDevices","e","id","_c","deviceSelectorStyles","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sw-device-selector.js","sources":["../../../src/components/sw-device-selector/sw-device-selector.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { Subscription } from 'rxjs';\nimport type { DeviceController } from '@signalwire/js';\nimport { getLogger } from '@signalwire/js';\nimport type { IconName } from '../UI/icons/icons.js';\nimport { deviceSelectorStyles } from './sw-device-selector.styles.js';\nimport { hostReset } from '../UI/host-reset.js';\nimport '../UI/icons/sw-ui-icon.js';\nimport '../sw-local-camera.js';\nimport '../sw-audio-level.js';\n\nconst logger = getLogger();\n\ntype AudioElementWithSinkId = HTMLAudioElement & {\n setSinkId?: (sinkId: string) => Promise<void>;\n};\n\n/**\n * Single-button device settings popover. Opens a panel above the button\n * with sections for Microphone, Camera, and Speaker selection.\n *\n * When `show-preview` is enabled, the open panel also renders a live\n * camera preview, a microphone level meter for the currently selected\n * input devices, and a \"Test speaker\" button that plays a short tone\n * through the selected output.\n *\n * @fires sw-device-change - User picked a device. Detail: `{ type: 'microphone'|'camera'|'speaker', device: MediaDeviceInfo }`.\n * @cssprop --ctrl-* - all primitive ctrl tokens\n */\n@customElement('sw-device-selector')\nexport class SwDeviceSelector extends LitElement {\n static styles = [hostReset, deviceSelectorStyles];\n\n @property({ type: Object }) deviceController?: DeviceController;\n\n /**\n * Render inline previews (camera video, mic level, speaker test) inside\n * each section while the panel is open. Streams are acquired only while\n * the panel is open and stopped when it closes.\n */\n @property({ type: Boolean, reflect: true, attribute: 'show-preview' })\n showPreview = false;\n\n @state() private _videoStream: MediaStream | null = null;\n @state() private _audioStream: MediaStream | null = null;\n @state() private _testingSpeaker = false;\n\n @state() private _audioIn: MediaDeviceInfo[] = [];\n @state() private _videoIn: MediaDeviceInfo[] = [];\n @state() private _audioOut: MediaDeviceInfo[] = [];\n @state() private _selAudioIn: MediaDeviceInfo | null = null;\n @state() private _selVideoIn: MediaDeviceInfo | null = null;\n @state() private _selAudioOut: MediaDeviceInfo | null = null;\n @state() private _open = false;\n\n private _subs: Subscription[] = [];\n\n private _onDocumentClick = (e: MouseEvent) => {\n if (!e.composedPath().includes(this)) this._open = false;\n };\n\n connectedCallback() {\n super.connectedCallback();\n document.addEventListener('click', this._onDocumentClick);\n this._subscribe();\n }\n\n protected updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n if (changed.has('deviceController')) {\n this._unsubscribe();\n this._subscribe();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('click', this._onDocumentClick);\n this._unsubscribe();\n this._stopVideoPreview();\n this._stopAudioPreview();\n this._stopTestTone();\n }\n\n protected willUpdate(changed: Map<string, unknown>): void {\n if (!this.showPreview) {\n if (changed.has('showPreview') || changed.has('_open')) {\n this._stopVideoPreview();\n this._stopAudioPreview();\n }\n return;\n }\n\n const opened = changed.has('_open') && this._open;\n const closed = changed.has('_open') && !this._open;\n const cameraChanged = changed.has('_selVideoIn');\n const micChanged = changed.has('_selAudioIn');\n\n if (closed) {\n this._stopVideoPreview();\n this._stopAudioPreview();\n this._stopTestTone();\n return;\n }\n\n if (this._open && (opened || cameraChanged) && this._selVideoIn) {\n this._startVideoPreview(this._selVideoIn.deviceId);\n }\n if (this._open && (opened || micChanged) && this._selAudioIn) {\n this._startAudioPreview(this._selAudioIn.deviceId);\n }\n }\n\n // ── subscriptions ──────────────────────────────────────────────────\n\n private _subscribe(): void {\n const dc = this.deviceController;\n if (!dc) return;\n\n this._subs.push(dc.audioInputDevices$.subscribe((d) => { this._audioIn = d; }));\n this._subs.push(dc.videoInputDevices$.subscribe((d) => { this._videoIn = d; }));\n this._subs.push(dc.audioOutputDevices$.subscribe((d) => { this._audioOut = d; }));\n\n if (dc.selectedAudioInputDevice$)\n this._subs.push(dc.selectedAudioInputDevice$.subscribe((d) => { this._selAudioIn = d; }));\n if (dc.selectedVideoInputDevice$)\n this._subs.push(dc.selectedVideoInputDevice$.subscribe((d) => { this._selVideoIn = d; }));\n if (dc.selectedAudioOutputDevice$)\n this._subs.push(dc.selectedAudioOutputDevice$.subscribe((d) => { this._selAudioOut = d; }));\n }\n\n private _unsubscribe(): void {\n this._subs.forEach((s) => s.unsubscribe());\n this._subs = [];\n }\n\n // ── handlers ──────────────────────────────────────────────────────\n\n private _toggle(e: Event) {\n e.stopPropagation();\n this._open = !this._open;\n }\n\n private _selectMic(deviceId: string) {\n const device = this._audioIn.find((d) => d.deviceId === deviceId) ?? null;\n this._selAudioIn = device;\n this.deviceController?.selectAudioInputDevice?.(device);\n if (device) this._emitChange('microphone', device);\n }\n\n private _selectCamera(deviceId: string) {\n const device = this._videoIn.find((d) => d.deviceId === deviceId) ?? null;\n this._selVideoIn = device;\n this.deviceController?.selectVideoInputDevice?.(device);\n if (device) this._emitChange('camera', device);\n }\n\n private _selectSpeaker(deviceId: string) {\n const device = this._audioOut.find((d) => d.deviceId === deviceId) ?? null;\n this._selAudioOut = device;\n this.deviceController?.selectAudioOutputDevice?.(device);\n if (device) this._emitChange('speaker', device);\n }\n\n // ── preview streams ───────────────────────────────────────────────\n\n private async _startVideoPreview(deviceId: string): Promise<void> {\n this._stopVideoPreview();\n try {\n this._videoStream = await navigator.mediaDevices.getUserMedia({\n video: { deviceId: { exact: deviceId } }\n });\n } catch (error) {\n logger.error('sw-device-selector: failed to start camera preview', error);\n this._videoStream = null;\n }\n }\n\n private _stopVideoPreview(): void {\n this._videoStream?.getTracks().forEach((t) => t.stop());\n this._videoStream = null;\n }\n\n private async _startAudioPreview(deviceId: string): Promise<void> {\n this._stopAudioPreview();\n try {\n this._audioStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: { exact: deviceId } }\n });\n } catch (error) {\n logger.error('sw-device-selector: failed to start microphone preview', error);\n this._audioStream = null;\n }\n }\n\n private _stopAudioPreview(): void {\n this._audioStream?.getTracks().forEach((t) => t.stop());\n this._audioStream = null;\n }\n\n // ── speaker test ──────────────────────────────────────────────────\n\n private static readonly _TEST_TONE_DATA_URI =\n 'data:audio/wav;base64,UklGRrQEAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YZAEAACAh46Sl5qcm5mWko2HgXp1cGxqaWlsb3R5gIaNk5icnp2bl5OOiIJ8dnFtamhoam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamloam1xdnyChI+VmZ2enZqXkoyGgHt1cG1qaGhrbnJ4foSLkZianp6cmZWQioR+eHJuamlo';\n\n private _testAudio?: AudioElementWithSinkId;\n\n private async _testSpeaker(): Promise<void> {\n if (this._testingSpeaker) {\n this._stopTestTone();\n return;\n }\n const audio = new Audio(SwDeviceSelector._TEST_TONE_DATA_URI) as AudioElementWithSinkId;\n audio.loop = true;\n this._testAudio = audio;\n\n const sinkId = this._selAudioOut?.deviceId;\n if (sinkId && typeof audio.setSinkId === 'function') {\n try {\n await audio.setSinkId(sinkId);\n } catch (error) {\n logger.error('sw-device-selector: setSinkId failed', error);\n }\n }\n audio.addEventListener('ended', () => this._stopTestTone());\n try {\n await audio.play();\n this._testingSpeaker = true;\n } catch (error) {\n logger.error('sw-device-selector: failed to play test tone', error);\n this._stopTestTone();\n }\n }\n\n private _stopTestTone(): void {\n if (this._testAudio) {\n this._testAudio.pause();\n this._testAudio.src = '';\n this._testAudio = undefined;\n }\n this._testingSpeaker = false;\n }\n\n private _emitChange(type: 'microphone' | 'camera' | 'speaker', device: MediaDeviceInfo) {\n this.dispatchEvent(new CustomEvent('sw-device-change', {\n detail: { type, device },\n bubbles: true,\n composed: true\n }));\n }\n\n // ── render helpers ────────────────────────────────────────────────\n\n private _renderSection(\n iconName: IconName,\n title: string,\n devices: MediaDeviceInfo[],\n selectedId: string | undefined,\n onSelect: (id: string) => void,\n preview?: unknown\n ) {\n return html`\n <div class=\"section\">\n <div class=\"section-header\">\n <sw-ui-icon name=${iconName} size=\"13\"></sw-ui-icon>\n <span>${title}</span>\n </div>\n ${devices.length === 0\n ? html`<div class=\"no-devices\">No devices found</div>`\n : devices.map((d, i) => html`\n <div\n class=\"device-item ${d.deviceId === selectedId ? 'selected' : ''}\"\n role=\"option\"\n aria-selected=${d.deviceId === selectedId}\n @click=${() => onSelect(d.deviceId)}\n >\n <svg class=\"check\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M6.5 12L2 7.5l1.4-1.4 3.1 3.1 5.6-5.6 1.4 1.4z\" />\n </svg>\n <span class=\"device-label\">${d.label || `Device ${i + 1}`}</span>\n </div>\n `)\n }\n ${preview ?? nothing}\n </div>\n `;\n }\n\n private _renderCameraPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-camera\" part=\"preview-camera\">\n ${this._videoStream\n ? html`<sw-local-camera .stream=${this._videoStream} mirror></sw-local-camera>`\n : html`<div class=\"preview-empty\">Starting camera…</div>`}\n </div>\n `;\n }\n\n private _renderMicPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-mic\" part=\"preview-mic\">\n ${this._audioStream\n ? html`<sw-audio-level\n .stream=${this._audioStream}\n bars=\"9\"\n orientation=\"horizontal\"\n maxSize=\"22\"\n ></sw-audio-level>`\n : html`<div class=\"preview-empty\">Starting microphone…</div>`}\n </div>\n `;\n }\n\n private _renderSpeakerPreview() {\n if (!this.showPreview) return null;\n return html`\n <div class=\"preview preview-speaker\" part=\"preview-speaker\">\n <button\n class=\"test-speaker\"\n part=\"test-speaker-button\"\n ?disabled=${!this._selAudioOut}\n @click=${(e: Event) => { e.stopPropagation(); this._testSpeaker(); }}\n >\n <sw-ui-icon name=${this._testingSpeaker ? 'speaker-off' : 'speaker-on'} size=\"14\"></sw-ui-icon>\n <span>${this._testingSpeaker ? 'Stop test' : 'Test speaker'}</span>\n </button>\n </div>\n `;\n }\n\n // ── render ─────────────────────────────────────────────────────────\n\n render() {\n const hasDevices = this._audioIn.length > 0 || this._videoIn.length > 0 || this._audioOut.length > 0;\n\n return html`\n ${this._open ? html`\n <div\n class=\"panel\"\n role=\"listbox\"\n @keydown=${(e: KeyboardEvent) => { if (e.key === 'Escape') this._open = false; }}\n >\n ${this._renderSection('mic-on', 'Microphone', this._audioIn, this._selAudioIn?.deviceId, (id) => this._selectMic(id), this._renderMicPreview())}\n ${this._renderSection('camera-on', 'Camera', this._videoIn, this._selVideoIn?.deviceId, (id) => this._selectCamera(id), this._renderCameraPreview())}\n ${this._renderSection('speaker-on', 'Speaker', this._audioOut, this._selAudioOut?.deviceId, (id) => this._selectSpeaker(id), this._renderSpeakerPreview())}\n </div>\n ` : nothing}\n\n <button\n class=\"trigger\"\n aria-label=\"Device settings\"\n aria-expanded=${this._open}\n aria-haspopup=\"listbox\"\n ?disabled=${!hasDevices}\n @click=${this._toggle}\n part=\"button\"\n >\n <sw-ui-icon name=\"settings\" size=\"22\"></sw-ui-icon>\n </button>\n <span class=\"label\">Devices</span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-device-selector': SwDeviceSelector;\n }\n}\n"],"names":["logger","getLogger","SwDeviceSelector","LitElement","changed","opened","closed","cameraChanged","micChanged","dc","d","s","deviceId","device","_b","_a","error","t","audio","sinkId","type","iconName","title","devices","selectedId","onSelect","preview","html","i","nothing","hasDevices","e","id","_c","hostReset","deviceSelectorStyles","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -49,7 +49,7 @@ export interface DirectoryService {
|
|
|
49
49
|
loadMore?(): Promise<void>;
|
|
50
50
|
}
|
|
51
51
|
export declare class SwDirectory extends LitElement {
|
|
52
|
-
static styles: import("lit").CSSResult;
|
|
52
|
+
static styles: import("lit").CSSResult[];
|
|
53
53
|
/**
|
|
54
54
|
* Directory service with addresses$ observable
|
|
55
55
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-directory.d.ts","sourceRoot":"","sources":["../../src/components/sw-directory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAG5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"sw-directory.d.ts","sourceRoot":"","sources":["../../src/components/sw-directory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAG5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,0BAA0B,CAAC;AAGlC;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,qBACa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,4BA+MV;IAEH;;OAEG;IAEH,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAE1C;;OAEG;IAEH,OAAO,CAAC,eAAe,CAAwB;IAE/C;;OAEG;IAEH,OAAO,CAAC,WAAW,CAAc;IAEjC;;OAEG;IAEH,OAAO,CAAC,SAAS,CAAiB;IAElC;;OAEG;IAEH,OAAO,CAAC,OAAO,CAAkB;IAEjC;;OAEG;IAEH,OAAO,CAAC,OAAO,CAAkB;IAEjC;;OAEG;IACH,OAAO,CAAC,aAAa,CAAsB;IAE3C;;OAEG;IACH,OAAO,CAAC,mBAAmB,CAAuB;IAElD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAqC;IAEjE;;OAEG;IAEH,OAAO,CAAC,sBAAsB,CAAkB;IAEhD,iBAAiB;IAKjB,oBAAoB;IAKpB,OAAO,CAAC,oBAAoB;IAiC5B,OAAO,CAAC,OAAO;IAYf,SAAS,CAAC,YAAY;IAItB,OAAO,CAAC,mBAAmB;IAqB3B,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;YAyB3C,sBAAsB;IAiBpC,OAAO,KAAK,iBAAiB,GAU5B;IAED,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,UAAU;YAUJ,cAAc;IAM5B,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,sBAAsB;IAS9B,MAAM;CAuEP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,WAAW,CAAC;KAC7B;CACF"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { LitElement as u, html as a, css as p } from "lit";
|
|
2
2
|
import { property as m, state as l, customElement as b } from "lit/decorators.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { hostReset as v } from "./UI/host-reset.js";
|
|
4
|
+
var f = Object.defineProperty, g = Object.getOwnPropertyDescriptor, n = (e, i, o, t) => {
|
|
5
|
+
for (var s = t > 1 ? void 0 : t ? g(i, o) : i, c = e.length - 1, d; c >= 0; c--)
|
|
5
6
|
(d = e[c]) && (s = (t ? d(i, o, s) : d(s)) || s);
|
|
6
|
-
return t && s &&
|
|
7
|
+
return t && s && f(i, o, s), s;
|
|
7
8
|
};
|
|
8
9
|
let r = class extends u {
|
|
9
10
|
constructor() {
|
|
@@ -196,7 +197,7 @@ let r = class extends u {
|
|
|
196
197
|
`;
|
|
197
198
|
}
|
|
198
199
|
};
|
|
199
|
-
r.styles = p`
|
|
200
|
+
r.styles = [v, p`
|
|
200
201
|
:host {
|
|
201
202
|
display: block;
|
|
202
203
|
font-family: var(--type-family-body);
|
|
@@ -403,7 +404,7 @@ r.styles = p`
|
|
|
403
404
|
.dial-button sw-ui-icon {
|
|
404
405
|
pointer-events: none;
|
|
405
406
|
}
|
|
406
|
-
|
|
407
|
+
`];
|
|
407
408
|
n([
|
|
408
409
|
m({ type: Object })
|
|
409
410
|
], r.prototype, "directory", 2);
|