@ghchinoy/lit-audio-ui 0.1.0

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.
@@ -0,0 +1,2121 @@
1
+ import { LitElement as e, css as t, html as n } from "lit";
2
+ import { customElement as r, property as i, query as a, state as o } from "lit/decorators.js";
3
+ import "@material/web/button/filled-button.js";
4
+ import "@material/web/icon/icon.js";
5
+ import { classMap as s } from "lit/directives/class-map.js";
6
+ import "@material/web/button/outlined-button.js";
7
+ import "@material/web/iconbutton/filled-icon-button.js";
8
+ import "@material/web/progress/circular-progress.js";
9
+ import "@material/web/slider/slider.js";
10
+ import "@material/web/menu/menu.js";
11
+ import "@material/web/menu/menu-item.js";
12
+ import "@material/web/divider/divider.js";
13
+ import "@material/web/button/text-button.js";
14
+ import "@material/web/button/filled-tonal-button.js";
15
+ import "@material/web/textfield/outlined-text-field.js";
16
+ import * as c from "three";
17
+ import "@material/web/iconbutton/icon-button.js";
18
+ function l(e, t, n, r) {
19
+ var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
20
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
21
+ else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
22
+ return i > 3 && a && Object.defineProperty(t, n, a), a;
23
+ }
24
+ /**
25
+ * Copyright 2026 Google LLC
26
+ *
27
+ * Licensed under the Apache License, Version 2.0 (the "License");
28
+ * you may not use this file except in compliance with the License.
29
+ * You may obtain a copy of the License at
30
+ *
31
+ * http://www.apache.org/licenses/LICENSE-2.0
32
+ *
33
+ * Unless required by applicable law or agreed to in writing, software
34
+ * distributed under the License is distributed on an "AS IS" BASIS,
35
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36
+ * See the License for the specific language governing permissions and
37
+ * limitations under the License.
38
+ */
39
+ var u = class extends e {
40
+ constructor(...e) {
41
+ super(...e), this.state = "idle";
42
+ }
43
+ static {
44
+ this.styles = t`
45
+ :host {
46
+ display: inline-block;
47
+ }
48
+
49
+ md-filled-button {
50
+ --md-filled-button-container-shape: 999px;
51
+ }
52
+
53
+ md-filled-button.recording {
54
+ --md-filled-button-container-color: var(--md-sys-color-error, #ba1a1a);
55
+ --md-filled-button-label-text-color: var(
56
+ --md-sys-color-on-error,
57
+ #ffffff
58
+ );
59
+ }
60
+ `;
61
+ }
62
+ render() {
63
+ return n`
64
+ <md-filled-button class="${this.state}" @click="${this._handleClick}">
65
+ <md-icon slot="icon">
66
+ ${this.state === "recording" ? "stop" : "mic"}
67
+ </md-icon>
68
+
69
+ ${this.state === "recording" ? "Recording..." : "Speak"}
70
+ </md-filled-button>
71
+ `;
72
+ }
73
+ _handleClick() {
74
+ this.state = this.state === "idle" ? "recording" : "idle", this.dispatchEvent(new CustomEvent("voice-toggle", {
75
+ bubbles: !0,
76
+ composed: !0,
77
+ detail: { state: this.state }
78
+ }));
79
+ }
80
+ };
81
+ l([i({ type: String })], u.prototype, "state", void 0), u = l([r("scream-voice-button")], u);
82
+ /**
83
+ * Normalizes raw frequency data from the AnalyserNode into an array of values between 0.0 and 1.0.
84
+ *
85
+ * @param analyser The AnalyserNode to read from
86
+ * @param dataArray A pre-allocated Uint8Array to hold the raw byte data
87
+ * @returns An array of normalized numbers (0.0 to 1.0)
88
+ */
89
+ function d(e, t) {
90
+ e.getByteFrequencyData(t);
91
+ let n = [];
92
+ for (let e = 0; e < t.length; e++) n.push(t[e] / 255);
93
+ return n;
94
+ }
95
+ /**
96
+ * Creates an edge-fade gradient over a canvas to smoothly blend the left and right edges.
97
+ *
98
+ * @param ctx The canvas 2D rendering context
99
+ * @param width The logical width of the canvas
100
+ * @param height The logical height of the canvas
101
+ * @param fadeWidth The physical width in pixels of the fade effect
102
+ */
103
+ function f(e, t, n, r) {
104
+ if (r <= 0 || t <= 0) return;
105
+ let i = e.createLinearGradient(0, 0, t, 0), a = Math.min(.2, r / t);
106
+ i.addColorStop(0, "rgba(0,0,0,0)"), i.addColorStop(a, "rgba(0,0,0,1)"), i.addColorStop(1 - a, "rgba(0,0,0,1)"), i.addColorStop(1, "rgba(0,0,0,0)"), e.globalCompositeOperation = "destination-in", e.fillStyle = i, e.fillRect(0, 0, t, n), e.globalCompositeOperation = "source-over";
107
+ }
108
+ /**
109
+ * Copyright 2026 Google LLC
110
+ *
111
+ * Licensed under the Apache License, Version 2.0 (the "License");
112
+ * you may not use this file except in compliance with the License.
113
+ * You may obtain a copy of the License at
114
+ *
115
+ * http://www.apache.org/licenses/LICENSE-2.0
116
+ *
117
+ * Unless required by applicable law or agreed to in writing, software
118
+ * distributed under the License is distributed on an "AS IS" BASIS,
119
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120
+ * See the License for the specific language governing permissions and
121
+ * limitations under the License.
122
+ */
123
+ var p = class extends e {
124
+ constructor(...e) {
125
+ super(...e), this.active = !1, this.processing = !1, this.barWidth = 3, this.barHeight = 4, this.barGap = 1, this.barRadius = 1.5, this.fadeEdges = !0, this.fadeWidth = 24, this.height = 64, this.sensitivity = 1, this.updateRate = 30, this._animationFrameId = 0, this._lastUpdateTime = 0, this._currentBars = [], this._processingTime = 0, this._transitionProgress = 0, this._lastActiveData = [];
126
+ }
127
+ static {
128
+ this.styles = t`
129
+ :host {
130
+ display: block;
131
+ width: 100%;
132
+ }
133
+ .container {
134
+ position: relative;
135
+ width: 100%;
136
+ }
137
+ canvas {
138
+ position: absolute;
139
+ top: 0;
140
+ left: 0;
141
+ display: block;
142
+ height: 100%;
143
+ width: 100%;
144
+ }
145
+ `;
146
+ }
147
+ render() {
148
+ return n`
149
+ <div class="container" style="height: ${this.height}px;">
150
+ <canvas></canvas>
151
+ </div>
152
+ `;
153
+ }
154
+ firstUpdated() {
155
+ this._resizeObserver = new ResizeObserver(() => {
156
+ this._handleResize();
157
+ }), this._resizeObserver.observe(this._container), this._startAnimationLoop();
158
+ }
159
+ updated(e) {
160
+ super.updated(e), e.has("analyserNode") && this.analyserNode && (this._dataArray = new Uint8Array(this.analyserNode.frequencyBinCount)), e.has("processing") && this.processing && !this.active && (this._processingTime = 0, this._transitionProgress = 0);
161
+ }
162
+ disconnectedCallback() {
163
+ super.disconnectedCallback(), this._resizeObserver && this._resizeObserver.disconnect(), this._animationFrameId && cancelAnimationFrame(this._animationFrameId);
164
+ }
165
+ _handleResize() {
166
+ if (!this._canvas || !this._container) return;
167
+ let e = this._container.getBoundingClientRect(), t = window.devicePixelRatio || 1;
168
+ this._canvas.width = e.width * t, this._canvas.height = e.height * t, this._canvas.style.width = `${e.width}px`, this._canvas.style.height = `${e.height}px`;
169
+ let n = this._canvas.getContext("2d");
170
+ n && n.scale(t, t), this._renderFrame();
171
+ }
172
+ _startAnimationLoop() {
173
+ let e = (t) => {
174
+ this._updateData(t), this._renderFrame(), this._animationFrameId = requestAnimationFrame(e);
175
+ };
176
+ this._animationFrameId = requestAnimationFrame(e);
177
+ }
178
+ _updateData(e) {
179
+ if (!this._canvas) return;
180
+ let t = this._canvas.getBoundingClientRect(), n = Math.floor(t.width / (this.barWidth + this.barGap));
181
+ if (this.active && this.analyserNode && this._dataArray) {
182
+ if (e - this._lastUpdateTime > this.updateRate) {
183
+ this._lastUpdateTime = e;
184
+ let t = d(this.analyserNode, this._dataArray), r = Math.floor(t.length * .05), i = Math.floor(t.length * .4), a = t.slice(r, i), o = Math.floor(n / 2), s = Array(n).fill(.05), c = a.length - 1;
185
+ for (let e = 0; e <= o; e++) {
186
+ let t = e / o, r = a[Math.floor(t * c)] || 0;
187
+ t > .8 && (r *= 1 - (t - .8) * 5);
188
+ let i = Math.max(.05, Math.min(1, r * this.sensitivity)), l = o + e, u = o - e;
189
+ l < n && (s[l] = i), u >= 0 && (s[u] = i);
190
+ }
191
+ this._currentBars = s, this._lastActiveData = [...s];
192
+ }
193
+ } else if (this.processing && !this.active) {
194
+ this._processingTime += .03, this._transitionProgress = Math.min(1, this._transitionProgress + .02);
195
+ let e = Array(n).fill(.05), t = Math.floor(n / 2);
196
+ for (let r = 0; r < n; r++) {
197
+ let n = (r - t) / t, i = 1 - Math.abs(n) * .4, a = Math.sin(this._processingTime * 1.5 + n * 3) * .25, o = Math.sin(this._processingTime * .8 - n * 2) * .2, s = Math.cos(this._processingTime * 2 + n) * .15, c = (.2 + (a + o + s)) * i, l = c;
198
+ if (this._lastActiveData.length > 0 && this._transitionProgress < 1) {
199
+ let e = Math.min(r, this._lastActiveData.length - 1);
200
+ l = (this._lastActiveData[e] || 0) * (1 - this._transitionProgress) + c * this._transitionProgress;
201
+ }
202
+ e[r] = Math.max(.05, Math.min(1, l));
203
+ }
204
+ this._currentBars = e;
205
+ } else if (this._currentBars.length > 0) {
206
+ let e = !0;
207
+ for (let t = 0; t < this._currentBars.length; t++) this._currentBars[t] = Math.max(.05, this._currentBars[t] * .85), this._currentBars[t] > .06 && (e = !1);
208
+ e && (this._currentBars = []);
209
+ }
210
+ }
211
+ _renderFrame() {
212
+ if (!this._canvas) return;
213
+ let e = this._canvas.getContext("2d");
214
+ if (!e) return;
215
+ let t = this._canvas.getBoundingClientRect();
216
+ e.clearRect(0, 0, t.width, t.height);
217
+ let n = getComputedStyle(this), r = this.barColor;
218
+ if (!r) {
219
+ let e = n.getPropertyValue("--md-sys-color-primary").trim(), t = n.getPropertyValue("color").trim();
220
+ r = e || t || "#0066cc";
221
+ }
222
+ let i = this.barWidth + this.barGap, a = Math.floor(t.width / i), o = t.height / 2;
223
+ for (let n = 0; n < a && n < this._currentBars.length; n++) {
224
+ let a = this._currentBars[n] || .05, s = n * i, c = Math.max(this.barHeight, a * t.height * .8), l = o - c / 2;
225
+ e.fillStyle = r, e.globalAlpha = .4 + a * .6, this.barRadius > 0 ? (e.beginPath(), e.roundRect(s, l, this.barWidth, c, this.barRadius), e.fill()) : e.fillRect(s, l, this.barWidth, c);
226
+ }
227
+ this.fadeEdges && f(e, t.width, t.height, this.fadeWidth), e.globalAlpha = 1;
228
+ }
229
+ };
230
+ l([i({ type: Boolean })], p.prototype, "active", void 0), l([i({ type: Boolean })], p.prototype, "processing", void 0), l([i({ attribute: !1 })], p.prototype, "analyserNode", void 0), l([i({ type: Number })], p.prototype, "barWidth", void 0), l([i({ type: Number })], p.prototype, "barHeight", void 0), l([i({ type: Number })], p.prototype, "barGap", void 0), l([i({ type: Number })], p.prototype, "barRadius", void 0), l([i({ type: String })], p.prototype, "barColor", void 0), l([i({ type: Boolean })], p.prototype, "fadeEdges", void 0), l([i({ type: Number })], p.prototype, "fadeWidth", void 0), l([i({ type: Number })], p.prototype, "height", void 0), l([i({ type: Number })], p.prototype, "sensitivity", void 0), l([i({ type: Number })], p.prototype, "updateRate", void 0), l([a("canvas")], p.prototype, "_canvas", void 0), l([a(".container")], p.prototype, "_container", void 0), p = l([r("ui-live-waveform")], p);
231
+ /**
232
+ * Copyright 2026 Google LLC
233
+ *
234
+ * Licensed under the Apache License, Version 2.0 (the "License");
235
+ * you may not use this file except in compliance with the License.
236
+ * You may obtain a copy of the License at
237
+ *
238
+ * http://www.apache.org/licenses/LICENSE-2.0
239
+ *
240
+ * Unless required by applicable law or agreed to in writing, software
241
+ * distributed under the License is distributed on an "AS IS" BASIS,
242
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
243
+ * See the License for the specific language governing permissions and
244
+ * limitations under the License.
245
+ */
246
+ var m = class extends e {
247
+ constructor(...e) {
248
+ super(...e), this.state = "idle", this.disabled = !1, this._showFeedback = !1;
249
+ }
250
+ static {
251
+ this.styles = t`
252
+ :host {
253
+ display: inline-block;
254
+ --ui-waveform-height: 24px;
255
+ --ui-waveform-width: 96px;
256
+ }
257
+
258
+ .wrapper {
259
+ display: flex;
260
+ align-items: center;
261
+ gap: 12px;
262
+ }
263
+
264
+ md-filled-button,
265
+ md-outlined-button {
266
+ transition: all 0.2s ease-in-out;
267
+ }
268
+
269
+ /* Customize the button depending on the state */
270
+ md-filled-button.recording {
271
+ --md-filled-button-container-color: var(
272
+ --md-sys-color-error-container,
273
+ #ffdad6
274
+ );
275
+ --md-filled-button-label-text-color: var(
276
+ --md-sys-color-on-error-container,
277
+ #410002
278
+ );
279
+ }
280
+
281
+ md-filled-button.processing {
282
+ --md-filled-button-container-color: var(
283
+ --md-sys-color-secondary-container,
284
+ #cce5ff
285
+ );
286
+ --md-filled-button-label-text-color: var(
287
+ --md-sys-color-on-secondary-container,
288
+ #001d36
289
+ );
290
+ }
291
+
292
+ md-filled-button.success {
293
+ --md-filled-button-container-color: var(
294
+ --md-sys-color-primary-container,
295
+ #d1e4ff
296
+ );
297
+ --md-filled-button-label-text-color: var(
298
+ --md-sys-color-on-primary-container,
299
+ #001d36
300
+ );
301
+ }
302
+
303
+ .waveform-slot {
304
+ position: relative;
305
+ width: var(--ui-waveform-width);
306
+ height: var(--ui-waveform-height);
307
+ border-radius: 4px;
308
+ overflow: hidden;
309
+ display: flex;
310
+ align-items: center;
311
+ justify-content: center;
312
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
313
+ border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
314
+ transition: background-color 0.3s ease;
315
+ }
316
+
317
+ .waveform-slot.recording {
318
+ background: var(--md-sys-color-error-container, #ffdad6);
319
+ border-color: transparent;
320
+ }
321
+
322
+ .waveform-slot.processing {
323
+ background: var(--md-sys-color-secondary-container, #cce5ff);
324
+ border-color: transparent;
325
+ }
326
+
327
+ .trailing-text {
328
+ font-family: monospace;
329
+ font-size: 11px;
330
+ color: var(--md-sys-color-on-surface-variant, #444);
331
+ font-weight: 500;
332
+ user-select: none;
333
+ }
334
+
335
+ .feedback-overlay {
336
+ position: absolute;
337
+ inset: 0;
338
+ display: flex;
339
+ align-items: center;
340
+ justify-content: center;
341
+ background: var(--md-sys-color-surface, #fff);
342
+ animation: fadeIn 0.3s ease forwards;
343
+ }
344
+
345
+ .feedback-icon {
346
+ font-size: 16px;
347
+ }
348
+ .feedback-icon.success {
349
+ color: var(--md-sys-color-primary, #0066cc);
350
+ }
351
+ .feedback-icon.error {
352
+ color: var(--md-sys-color-error, #ba1a1a);
353
+ }
354
+
355
+ @keyframes fadeIn {
356
+ from {
357
+ opacity: 0;
358
+ }
359
+ to {
360
+ opacity: 0.9;
361
+ }
362
+ }
363
+ `;
364
+ }
365
+ updated(e) {
366
+ super.updated(e), e.has("state") && (this.state === "success" || this.state === "error" ? (this._showFeedback = !0, this._feedbackTimeout && clearTimeout(this._feedbackTimeout), this._feedbackTimeout = setTimeout(() => {
367
+ this._showFeedback = !1, (this.state === "success" || this.state === "error") && (this.state = "idle");
368
+ }, 1500)) : this._showFeedback = !1);
369
+ }
370
+ render() {
371
+ let e = this.state === "recording", t = this.state === "processing", r = this.state === "success", i = this.state === "error", a = this.disabled || t, o = e || t, c = !o && !this._showFeedback && this.trailing, l = {
372
+ recording: e,
373
+ processing: t,
374
+ success: r && this._showFeedback,
375
+ error: i && this._showFeedback
376
+ }, u = {
377
+ "waveform-slot": !0,
378
+ recording: e,
379
+ processing: t
380
+ };
381
+ return n`
382
+ <md-filled-button
383
+ class=${s(l)}
384
+ ?disabled=${a}
385
+ @click=${this._handleClick}
386
+ >
387
+ <div class="wrapper">
388
+ ${this.label ? n`<span>${this.label}</span>` : ""}
389
+
390
+ <div class=${s(u)}>
391
+ ${o ? n`
392
+ <ui-live-waveform
393
+ .active=${e}
394
+ .processing=${t}
395
+ .analyserNode=${this.analyserNode}
396
+ .barWidth=${2}
397
+ .barGap=${1}
398
+ .barRadius=${4}
399
+ .fadeEdges=${!1}
400
+ .sensitivity=${1.8}
401
+ height="20"
402
+ style="position: absolute; inset: 0;"
403
+ ></ui-live-waveform>
404
+ ` : ""}
405
+ ${c ? n` <span class="trailing-text">${this.trailing}</span> ` : ""}
406
+ ${this._showFeedback && r ? n`
407
+ <div class="feedback-overlay">
408
+ <md-icon class="feedback-icon success">check</md-icon>
409
+ </div>
410
+ ` : ""}
411
+ ${this._showFeedback && i ? n`
412
+ <div class="feedback-overlay">
413
+ <md-icon class="feedback-icon error">close</md-icon>
414
+ </div>
415
+ ` : ""}
416
+ </div>
417
+ </div>
418
+ </md-filled-button>
419
+ `;
420
+ }
421
+ _handleClick(e) {
422
+ this.dispatchEvent(new CustomEvent("voice-button-click", {
423
+ bubbles: !0,
424
+ composed: !0,
425
+ detail: { state: this.state }
426
+ }));
427
+ }
428
+ };
429
+ l([i({ type: String })], m.prototype, "state", void 0), l([i({ type: String })], m.prototype, "label", void 0), l([i({ type: String })], m.prototype, "trailing", void 0), l([i({ type: Boolean })], m.prototype, "disabled", void 0), l([i({ attribute: !1 })], m.prototype, "analyserNode", void 0), l([o()], m.prototype, "_showFeedback", void 0), m = l([r("ui-voice-button")], m);
430
+ /**
431
+ * Copyright 2026 Google LLC
432
+ *
433
+ * Licensed under the Apache License, Version 2.0 (the "License");
434
+ * you may not use this file except in compliance with the License.
435
+ * You may obtain a copy of the License at
436
+ *
437
+ * http://www.apache.org/licenses/LICENSE-2.0
438
+ *
439
+ * Unless required by applicable law or agreed to in writing, software
440
+ * distributed under the License is distributed on an "AS IS" BASIS,
441
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
442
+ * See the License for the specific language governing permissions and
443
+ * limitations under the License.
444
+ */
445
+ var h = class extends e {
446
+ constructor(...e) {
447
+ super(...e), this.data = [], this.barWidth = 4, this.barHeight = 4, this.barGap = 2, this.barRadius = 2, this.fadeEdges = !0, this.fadeWidth = 24, this.height = 128;
448
+ }
449
+ static {
450
+ this.styles = t`
451
+ :host {
452
+ display: block;
453
+ width: 100%;
454
+ }
455
+ .container {
456
+ position: relative;
457
+ width: 100%;
458
+ }
459
+ canvas {
460
+ position: absolute;
461
+ top: 0;
462
+ left: 0;
463
+ display: block;
464
+ height: 100%;
465
+ width: 100%;
466
+ }
467
+ `;
468
+ }
469
+ render() {
470
+ return n`
471
+ <div class="container" style="height: ${this.height}px;">
472
+ <canvas></canvas>
473
+ </div>
474
+ `;
475
+ }
476
+ firstUpdated() {
477
+ this._resizeObserver = new ResizeObserver(() => {
478
+ this._handleResize();
479
+ }), this._resizeObserver.observe(this._container);
480
+ }
481
+ updated(e) {
482
+ super.updated(e), (e.has("data") || e.has("barColor")) && this._renderWaveform();
483
+ }
484
+ disconnectedCallback() {
485
+ super.disconnectedCallback(), this._resizeObserver && this._resizeObserver.disconnect();
486
+ }
487
+ _handleResize() {
488
+ if (!this._canvas || !this._container) return;
489
+ let e = this._container.getBoundingClientRect(), t = window.devicePixelRatio || 1;
490
+ this._canvas.width = e.width * t, this._canvas.height = e.height * t, this._canvas.style.width = `${e.width}px`, this._canvas.style.height = `${e.height}px`;
491
+ let n = this._canvas.getContext("2d");
492
+ n && (n.scale(t, t), this._renderWaveform());
493
+ }
494
+ _renderWaveform() {
495
+ if (!this._canvas) return;
496
+ let e = this._canvas.getContext("2d");
497
+ if (!e) return;
498
+ let t = this._canvas.getBoundingClientRect();
499
+ e.clearRect(0, 0, t.width, t.height);
500
+ let n = getComputedStyle(this), r = this.barColor;
501
+ if (!r) {
502
+ let e = n.getPropertyValue("--md-sys-color-primary").trim(), t = n.getPropertyValue("color").trim();
503
+ r = e || t || "#0066cc";
504
+ }
505
+ let i = Math.floor(t.width / (this.barWidth + this.barGap)), a = t.height / 2;
506
+ for (let n = 0; n < i; n++) {
507
+ let o = Math.floor(n / i * this.data.length), s = this.data[o] || 0, c = Math.max(this.barHeight, s * t.height * .8), l = n * (this.barWidth + this.barGap), u = a - c / 2;
508
+ e.fillStyle = r, e.globalAlpha = .3 + s * .7, this.barRadius > 0 ? (e.beginPath(), e.roundRect(l, u, this.barWidth, c, this.barRadius), e.fill()) : e.fillRect(l, u, this.barWidth, c);
509
+ }
510
+ this.fadeEdges && f(e, t.width, t.height, this.fadeWidth), e.globalAlpha = 1;
511
+ }
512
+ };
513
+ l([i({ type: Array })], h.prototype, "data", void 0), l([i({ type: Number })], h.prototype, "barWidth", void 0), l([i({ type: Number })], h.prototype, "barHeight", void 0), l([i({ type: Number })], h.prototype, "barGap", void 0), l([i({ type: Number })], h.prototype, "barRadius", void 0), l([i({ type: String })], h.prototype, "barColor", void 0), l([i({ type: Boolean })], h.prototype, "fadeEdges", void 0), l([i({ type: Number })], h.prototype, "fadeWidth", void 0), l([i({ type: Number })], h.prototype, "height", void 0), l([a("canvas")], h.prototype, "_canvas", void 0), l([a(".container")], h.prototype, "_container", void 0), h = l([r("ui-waveform")], h);
514
+ /**
515
+ * @license
516
+ * Copyright 2021 Google LLC
517
+ * SPDX-License-Identifier: BSD-3-Clause
518
+ */
519
+ var g = class extends Event {
520
+ constructor(e, t, n, r) {
521
+ super("context-request", {
522
+ bubbles: !0,
523
+ composed: !0
524
+ }), this.context = e, this.contextTarget = t, this.callback = n, this.subscribe = r ?? !1;
525
+ }
526
+ };
527
+ /**
528
+ * @license
529
+ * Copyright 2021 Google LLC
530
+ * SPDX-License-Identifier: BSD-3-Clause
531
+ */
532
+ function _(e) {
533
+ return e;
534
+ }
535
+ /**
536
+ * @license
537
+ * Copyright 2021 Google LLC
538
+ * SPDX-License-Identifier: BSD-3-Clause
539
+ */ var v = class {
540
+ constructor(e, t, n, r) {
541
+ if (this.subscribe = !1, this.provided = !1, this.value = void 0, this.t = (e, t) => {
542
+ this.unsubscribe && (this.unsubscribe !== t && (this.provided = !1, this.unsubscribe()), this.subscribe || this.unsubscribe()), this.value = e, this.host.requestUpdate(), this.provided && !this.subscribe || (this.provided = !0, this.callback && this.callback(e, t)), this.unsubscribe = t;
543
+ }, this.host = e, t.context !== void 0) {
544
+ let e = t;
545
+ this.context = e.context, this.callback = e.callback, this.subscribe = e.subscribe ?? !1;
546
+ } else this.context = t, this.callback = n, this.subscribe = r ?? !1;
547
+ this.host.addController(this);
548
+ }
549
+ hostConnected() {
550
+ this.dispatchRequest();
551
+ }
552
+ hostDisconnected() {
553
+ this.unsubscribe &&= (this.unsubscribe(), void 0);
554
+ }
555
+ dispatchRequest() {
556
+ this.host.dispatchEvent(new g(this.context, this.host, this.t, this.subscribe));
557
+ }
558
+ }, y = class {
559
+ get value() {
560
+ return this.o;
561
+ }
562
+ set value(e) {
563
+ this.setValue(e);
564
+ }
565
+ setValue(e, t = !1) {
566
+ let n = t || !Object.is(e, this.o);
567
+ this.o = e, n && this.updateObservers();
568
+ }
569
+ constructor(e) {
570
+ this.subscriptions = /* @__PURE__ */ new Map(), this.updateObservers = () => {
571
+ for (let [e, { disposer: t }] of this.subscriptions) e(this.o, t);
572
+ }, e !== void 0 && (this.value = e);
573
+ }
574
+ addCallback(e, t, n) {
575
+ if (!n) return void e(this.value);
576
+ this.subscriptions.has(e) || this.subscriptions.set(e, {
577
+ disposer: () => {
578
+ this.subscriptions.delete(e);
579
+ },
580
+ consumerHost: t
581
+ });
582
+ let { disposer: r } = this.subscriptions.get(e);
583
+ e(this.value, r);
584
+ }
585
+ clearCallbacks() {
586
+ this.subscriptions.clear();
587
+ }
588
+ }, b = class extends Event {
589
+ constructor(e, t) {
590
+ super("context-provider", {
591
+ bubbles: !0,
592
+ composed: !0
593
+ }), this.context = e, this.contextTarget = t;
594
+ }
595
+ }, x = class extends y {
596
+ constructor(e, t, n) {
597
+ super(t.context === void 0 ? n : t.initialValue), this.onContextRequest = (e) => {
598
+ if (e.context !== this.context) return;
599
+ let t = e.contextTarget ?? e.composedPath()[0];
600
+ t !== this.host && (e.stopPropagation(), this.addCallback(e.callback, t, e.subscribe));
601
+ }, this.onProviderRequest = (e) => {
602
+ if (e.context !== this.context || (e.contextTarget ?? e.composedPath()[0]) === this.host) return;
603
+ let t = /* @__PURE__ */ new Set();
604
+ for (let [e, { consumerHost: n }] of this.subscriptions) t.has(e) || (t.add(e), n.dispatchEvent(new g(this.context, n, e, !0)));
605
+ e.stopPropagation();
606
+ }, this.host = e, t.context === void 0 ? this.context = t : this.context = t.context, this.attachListeners(), this.host.addController?.(this);
607
+ }
608
+ attachListeners() {
609
+ this.host.addEventListener("context-request", this.onContextRequest), this.host.addEventListener("context-provider", this.onProviderRequest);
610
+ }
611
+ hostConnected() {
612
+ this.host.dispatchEvent(new b(this.context, this.host));
613
+ }
614
+ };
615
+ /**
616
+ * @license
617
+ * Copyright 2017 Google LLC
618
+ * SPDX-License-Identifier: BSD-3-Clause
619
+ */ function S({ context: e }) {
620
+ return (t, n) => {
621
+ let r = /* @__PURE__ */ new WeakMap();
622
+ if (typeof n == "object") return {
623
+ get() {
624
+ return t.get.call(this);
625
+ },
626
+ set(e) {
627
+ return r.get(this).setValue(e), t.set.call(this, e);
628
+ },
629
+ init(t) {
630
+ return r.set(this, new x(this, {
631
+ context: e,
632
+ initialValue: t
633
+ })), t;
634
+ }
635
+ };
636
+ {
637
+ t.constructor.addInitializer(((t) => {
638
+ r.set(t, new x(t, { context: e }));
639
+ }));
640
+ let i = Object.getOwnPropertyDescriptor(t, n), a;
641
+ if (i === void 0) {
642
+ let e = /* @__PURE__ */ new WeakMap();
643
+ a = {
644
+ get() {
645
+ return e.get(this);
646
+ },
647
+ set(t) {
648
+ r.get(this).setValue(t), e.set(this, t);
649
+ },
650
+ configurable: !0,
651
+ enumerable: !0
652
+ };
653
+ } else {
654
+ let e = i.set;
655
+ a = {
656
+ ...i,
657
+ set(t) {
658
+ r.get(this).setValue(t), e?.call(this, t);
659
+ }
660
+ };
661
+ }
662
+ Object.defineProperty(t, n, a);
663
+ return;
664
+ }
665
+ };
666
+ }
667
+ /**
668
+ * @license
669
+ * Copyright 2022 Google LLC
670
+ * SPDX-License-Identifier: BSD-3-Clause
671
+ */ function C({ context: e, subscribe: t }) {
672
+ return (n, r) => {
673
+ typeof r == "object" ? r.addInitializer((function() {
674
+ new v(this, {
675
+ context: e,
676
+ callback: (e) => {
677
+ n.set.call(this, e);
678
+ },
679
+ subscribe: t
680
+ });
681
+ })) : n.constructor.addInitializer(((n) => {
682
+ new v(n, {
683
+ context: e,
684
+ callback: (e) => {
685
+ n[r] = e;
686
+ },
687
+ subscribe: t
688
+ });
689
+ }));
690
+ };
691
+ }
692
+ /**
693
+ * A unique token to identify our context.
694
+ * Any component that uses @consume({context: audioPlayerContext})
695
+ * will automatically receive updates when the nearest <ui-audio-provider> changes its state.
696
+ */
697
+ const w = _("ui-audio-player-context");
698
+ var T = class extends e {
699
+ constructor(...e) {
700
+ super(...e), this.src = "", this._animationFrameId = 0, this.state = {
701
+ src: "",
702
+ isPlaying: !1,
703
+ isBuffering: !1,
704
+ currentTime: 0,
705
+ duration: 0,
706
+ volume: 1,
707
+ muted: !1,
708
+ analyserNode: void 0,
709
+ play: () => this.play(),
710
+ pause: () => this.pause(),
711
+ togglePlay: () => this._togglePlay(),
712
+ seek: (e) => this._seek(e),
713
+ setVolume: (e) => this._setVolume(e),
714
+ toggleMute: () => this._toggleMute()
715
+ };
716
+ }
717
+ static {
718
+ this.styles = t`
719
+ :host {
720
+ display: contents; /* We are completely invisible, just wrapping children */
721
+ }
722
+ audio {
723
+ display: none;
724
+ }
725
+ `;
726
+ }
727
+ render() {
728
+ return n`
729
+ <audio
730
+ crossorigin="anonymous"
731
+ src="${this.src}"
732
+ preload="metadata"
733
+ @loadedmetadata="${this._handleLoadedMetadata}"
734
+ @ended="${this._handleEnded}"
735
+ @playing="${this._handlePlaying}"
736
+ @pause="${this._handlePause}"
737
+ @waiting="${() => this._updateState({ isBuffering: !0 })}"
738
+ @canplay="${() => this._updateState({ isBuffering: !1 })}"
739
+ @error="${this._handleError}"
740
+ ></audio>
741
+ <slot></slot>
742
+ `;
743
+ }
744
+ willUpdate(e) {
745
+ e.has("src") && this._updateState({
746
+ src: this.src,
747
+ isPlaying: !1,
748
+ currentTime: 0,
749
+ error: void 0
750
+ });
751
+ }
752
+ updated(e) {
753
+ e.has("src") && this._audioEl && this._audioEl.load();
754
+ }
755
+ disconnectedCallback() {
756
+ super.disconnectedCallback(), this._animationFrameId && cancelAnimationFrame(this._animationFrameId), this._audioContext && this._audioContext.state !== "closed" && this._audioContext.close();
757
+ }
758
+ _updateState(e) {
759
+ this.state = {
760
+ ...this.state,
761
+ ...e
762
+ }, this.dispatchEvent(new CustomEvent("state-change", {
763
+ detail: this.state,
764
+ bubbles: !0,
765
+ composed: !0
766
+ }));
767
+ }
768
+ _setupAudioContext() {
769
+ if (!(this._audioContext || !this._audioEl)) try {
770
+ this._audioContext = new (window.AudioContext || window.webkitAudioContext)(), this._analyserNode = this._audioContext.createAnalyser(), this._analyserNode.fftSize = 256, this._analyserNode.smoothingTimeConstant = .8, this._mediaSource = this._audioContext.createMediaElementSource(this._audioEl), this._mediaSource.connect(this._analyserNode), this._analyserNode.connect(this._audioContext.destination), this._updateState({ analyserNode: this._analyserNode });
771
+ } catch (e) {
772
+ console.warn("Failed to set up AudioContext for visualizer:", e);
773
+ }
774
+ }
775
+ play() {
776
+ this._audioEl.src && (this._setupAudioContext(), this._audioContext?.state === "suspended" && this._audioContext.resume(), this._audioEl.play().catch((e) => {
777
+ console.error("Error playing audio", e), this._updateState({ error: "Playback failed" });
778
+ }));
779
+ }
780
+ pause() {
781
+ this._audioEl && this._audioEl.pause();
782
+ }
783
+ _togglePlay() {
784
+ this.state.isPlaying ? this.pause() : this.play();
785
+ }
786
+ _seek(e) {
787
+ this._audioEl && (this._audioEl.currentTime = e, this._updateState({ currentTime: e }));
788
+ }
789
+ _setVolume(e) {
790
+ this._audioEl && (this._audioEl.volume = e, this._updateState({
791
+ volume: e,
792
+ muted: e === 0
793
+ }));
794
+ }
795
+ _toggleMute() {
796
+ this._audioEl && (this._audioEl.muted = !this._audioEl.muted, this._updateState({ muted: this._audioEl.muted }));
797
+ }
798
+ _handleLoadedMetadata() {
799
+ this._updateState({ duration: this._audioEl.duration });
800
+ }
801
+ _handleEnded() {
802
+ this._updateState({
803
+ isPlaying: !1,
804
+ currentTime: 0
805
+ }), this._audioEl.currentTime = 0;
806
+ }
807
+ _handlePlaying() {
808
+ this._updateState({
809
+ isPlaying: !0,
810
+ isBuffering: !1,
811
+ error: void 0
812
+ }), this._startTrackingTime();
813
+ }
814
+ _handlePause() {
815
+ this._updateState({ isPlaying: !1 }), this._animationFrameId && cancelAnimationFrame(this._animationFrameId);
816
+ }
817
+ _handleError() {
818
+ this._updateState({
819
+ error: "Error loading audio",
820
+ isPlaying: !1,
821
+ isBuffering: !1
822
+ });
823
+ }
824
+ _startTrackingTime() {
825
+ let e = () => {
826
+ this._audioEl && this.state.isPlaying && (Math.abs(this.state.currentTime - this._audioEl.currentTime) > .05 && this._updateState({ currentTime: this._audioEl.currentTime }), this._animationFrameId = requestAnimationFrame(e));
827
+ };
828
+ this._animationFrameId = requestAnimationFrame(e);
829
+ }
830
+ };
831
+ l([i({ type: String })], T.prototype, "src", void 0), l([a("audio")], T.prototype, "_audioEl", void 0), l([S({ context: w }), o()], T.prototype, "state", void 0), T = l([r("ui-audio-provider")], T);
832
+ var E = class extends e {
833
+ static {
834
+ this.styles = t`
835
+ :host {
836
+ display: inline-flex;
837
+ position: relative;
838
+ align-items: center;
839
+ justify-content: center;
840
+ font-family: inherit;
841
+ }
842
+
843
+ md-filled-icon-button {
844
+ --md-filled-icon-button-container-color: var(
845
+ --md-sys-color-primary,
846
+ #0066cc
847
+ );
848
+ --md-filled-icon-button-icon-color: var(
849
+ --md-sys-color-on-primary,
850
+ #ffffff
851
+ );
852
+ --md-filled-icon-button-hover-icon-color: var(
853
+ --md-sys-color-on-primary,
854
+ #ffffff
855
+ );
856
+ --md-filled-icon-button-focus-icon-color: var(
857
+ --md-sys-color-on-primary,
858
+ #ffffff
859
+ );
860
+ --md-filled-icon-button-pressed-icon-color: var(
861
+ --md-sys-color-on-primary,
862
+ #ffffff
863
+ );
864
+
865
+ --md-filled-icon-button-toggle-icon-color: var(
866
+ --md-sys-color-on-primary,
867
+ #ffffff
868
+ );
869
+ --md-filled-icon-button-selected-container-color: var(
870
+ --md-sys-color-primary,
871
+ #0066cc
872
+ );
873
+ --md-filled-icon-button-selected-icon-color: var(
874
+ --md-sys-color-on-primary,
875
+ #ffffff
876
+ );
877
+ color: var(--md-sys-color-on-primary, #ffffff);
878
+ }
879
+
880
+ md-circular-progress {
881
+ position: absolute;
882
+ --md-circular-progress-size: 48px;
883
+ }
884
+ `;
885
+ }
886
+ render() {
887
+ let e = this.playerState?.isPlaying ?? !1, t = this.playerState?.isBuffering ?? !1;
888
+ return n`
889
+ <md-filled-icon-button
890
+ part="button"
891
+ @click="${this._handleClick}"
892
+ ?disabled="${!this.playerState?.src}"
893
+ >
894
+ <md-icon>${e ? "pause" : "play_arrow"}</md-icon>
895
+ </md-filled-icon-button>
896
+ ${t && e ? n`<md-circular-progress indeterminate></md-circular-progress>` : ""}
897
+ `;
898
+ }
899
+ _handleClick() {
900
+ this.playerState && this.playerState.togglePlay();
901
+ }
902
+ };
903
+ l([C({
904
+ context: w,
905
+ subscribe: !0
906
+ }), i({ attribute: !1 })], E.prototype, "playerState", void 0), E = l([r("ui-audio-play-button")], E);
907
+ var D = class extends e {
908
+ constructor(...e) {
909
+ super(...e), this._isDragging = !1, this._dragValue = 0;
910
+ }
911
+ static {
912
+ this.styles = t`
913
+ :host {
914
+ display: flex;
915
+ width: 100%;
916
+ align-items: center;
917
+ min-width: 100px;
918
+ }
919
+
920
+ md-slider {
921
+ width: 100%;
922
+ /* Give the slider track better contrast against backgrounds */
923
+ --md-slider-inactive-track-color: var(--md-sys-color-outline, #79747e);
924
+ }
925
+ `;
926
+ }
927
+ render() {
928
+ let e = this.playerState?.duration || 0, t = e === 0 || !this.playerState?.src, r = this._isDragging ? this._dragValue : this.playerState?.currentTime || 0;
929
+ return n`
930
+ <md-slider
931
+ min="0"
932
+ max="${e || 100}"
933
+ value="${r}"
934
+ step="0.1"
935
+ ?disabled="${t}"
936
+ @input="${this._handleInput}"
937
+ @change="${this._handleChange}"
938
+ ></md-slider>
939
+ `;
940
+ }
941
+ _handleInput(e) {
942
+ this._isDragging = !0, this._dragValue = e.target.value;
943
+ }
944
+ _handleChange(e) {
945
+ this._dragValue = e.target.value, this.playerState && this.playerState.seek(this._dragValue), this._isDragging = !1;
946
+ }
947
+ };
948
+ l([C({
949
+ context: w,
950
+ subscribe: !0
951
+ }), i({ attribute: !1 })], D.prototype, "playerState", void 0), D = l([r("ui-audio-progress-slider")], D);
952
+ var O = class extends e {
953
+ constructor(...e) {
954
+ super(...e), this.format = "full";
955
+ }
956
+ static {
957
+ this.styles = t`
958
+ :host {
959
+ display: inline-block;
960
+ font-variant-numeric: tabular-nums;
961
+ font-size: 14px;
962
+ color: var(--md-sys-color-on-surface-variant, #444);
963
+ font-family: inherit;
964
+ }
965
+ `;
966
+ }
967
+ render() {
968
+ let e = this.playerState?.currentTime || 0, t = this.playerState?.duration || 0;
969
+ if (this.format === "elapsed") return n`${this._formatTime(e)}`;
970
+ if (this.format === "remaining") {
971
+ let r = Math.max(0, t - e);
972
+ return n`-${this._formatTime(r)}`;
973
+ } else return n`${this._formatTime(e)} /
974
+ ${t ? this._formatTime(t) : "--:--"}`;
975
+ }
976
+ _formatTime(e) {
977
+ if (!e || isNaN(e)) return "0:00";
978
+ let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60), i = "";
979
+ return t > 0 && (i += "" + t + ":" + (n < 10 ? "0" : "")), i += "" + n + ":" + (r < 10 ? "0" : ""), i += "" + r, i;
980
+ }
981
+ };
982
+ l([C({
983
+ context: w,
984
+ subscribe: !0
985
+ }), i({ attribute: !1 })], O.prototype, "playerState", void 0), l([i({ type: String })], O.prototype, "format", void 0), O = l([r("ui-audio-time-display")], O);
986
+ var k = class extends e {
987
+ static {
988
+ this.styles = t`
989
+ :host {
990
+ display: inline-block;
991
+ width: 100%;
992
+ max-width: 400px;
993
+ }
994
+
995
+ .player-pill {
996
+ display: flex;
997
+ align-items: center;
998
+ gap: 16px;
999
+ padding: 12px 24px;
1000
+ background: var(--md-sys-color-surface-container-high, #e2e2e2);
1001
+ border-radius: 999px; /* Pill shape */
1002
+ width: fit-content;
1003
+ font-family: inherit;
1004
+ }
1005
+
1006
+ .time-container {
1007
+ min-width: 85px; /* prevent jitter when times change */
1008
+ }
1009
+
1010
+ .slider-container {
1011
+ width: 200px;
1012
+ display: flex;
1013
+ align-items: center;
1014
+ }
1015
+ `;
1016
+ }
1017
+ render() {
1018
+ return n`
1019
+ <ui-audio-provider .src="${this.item?.src || ""}">
1020
+ <div class="player-pill" part="container">
1021
+ <!-- Atomic Play/Pause Button -->
1022
+ <ui-audio-play-button></ui-audio-play-button>
1023
+
1024
+ <!-- Atomic Time Display (Full format: 0:00 / 0:00) -->
1025
+ <div class="time-container">
1026
+ <ui-audio-time-display format="full"></ui-audio-time-display>
1027
+ </div>
1028
+
1029
+ <!-- Atomic Slider -->
1030
+ <div class="slider-container">
1031
+ <ui-audio-progress-slider></ui-audio-progress-slider>
1032
+ </div>
1033
+ </div>
1034
+ </ui-audio-provider>
1035
+ `;
1036
+ }
1037
+ };
1038
+ l([i({ type: Object })], k.prototype, "item", void 0), k = l([r("ui-audio-player")], k);
1039
+ /**
1040
+ * Copyright 2026 Google LLC
1041
+ *
1042
+ * Licensed under the Apache License, Version 2.0 (the "License");
1043
+ * you may not use this file except in compliance with the License.
1044
+ * You may obtain a copy of the License at
1045
+ *
1046
+ * http://www.apache.org/licenses/LICENSE-2.0
1047
+ *
1048
+ * Unless required by applicable law or agreed to in writing, software
1049
+ * distributed under the License is distributed on an "AS IS" BASIS,
1050
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1051
+ * See the License for the specific language governing permissions and
1052
+ * limitations under the License.
1053
+ */
1054
+ var A = class extends e {
1055
+ constructor(...e) {
1056
+ super(...e), this.muted = !1, this.disabled = !1, this._devices = [], this._loading = !0, this._error = null, this._hasPermission = !1, this._isMenuOpen = !1, this._handleDeviceChange = () => {
1057
+ this._hasPermission ? this._loadDevicesWithPermission() : this._loadDevicesWithoutPermission();
1058
+ };
1059
+ }
1060
+ static {
1061
+ this.styles = t`
1062
+ :host {
1063
+ display: inline-block;
1064
+ position: relative;
1065
+ font-family: inherit;
1066
+ }
1067
+
1068
+ .anchor-button {
1069
+ display: flex;
1070
+ align-items: center;
1071
+ gap: 8px;
1072
+ padding: 8px 16px;
1073
+ background: var(--md-sys-color-surface-container-high, #e2e2e2);
1074
+ color: var(--md-sys-color-on-surface, #1e1e1e);
1075
+ border-radius: 999px;
1076
+ cursor: pointer;
1077
+ border: none;
1078
+ font-family: inherit;
1079
+ font-size: 14px;
1080
+ font-weight: 500;
1081
+ transition: background-color 0.2s;
1082
+ max-width: 250px;
1083
+ }
1084
+
1085
+ .anchor-button:hover:not(:disabled) {
1086
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
1087
+ }
1088
+
1089
+ .anchor-button:disabled {
1090
+ opacity: 0.5;
1091
+ cursor: not-allowed;
1092
+ }
1093
+
1094
+ .label-text {
1095
+ flex: 1;
1096
+ white-space: nowrap;
1097
+ overflow: hidden;
1098
+ text-overflow: ellipsis;
1099
+ text-align: left;
1100
+ }
1101
+
1102
+ md-menu {
1103
+ --md-menu-container-color: var(
1104
+ --md-sys-color-surface-container,
1105
+ var(--md-sys-color-surface, #ffffff)
1106
+ );
1107
+ --md-menu-container-shape: 12px;
1108
+ min-width: 280px;
1109
+ }
1110
+
1111
+ .menu-footer {
1112
+ display: flex;
1113
+ align-items: center;
1114
+ justify-content: space-between;
1115
+ padding: 8px 12px;
1116
+ gap: 12px;
1117
+ }
1118
+
1119
+ .preview-waveform {
1120
+ flex: 1;
1121
+ height: 24px;
1122
+ background: var(
1123
+ --md-sys-color-surface-variant,
1124
+ var(--md-sys-color-surface-container-highest, #e1e2e1)
1125
+ );
1126
+ border-radius: 6px;
1127
+ overflow: hidden;
1128
+ display: flex;
1129
+ align-items: center;
1130
+ padding: 0 4px;
1131
+ }
1132
+ `;
1133
+ }
1134
+ connectedCallback() {
1135
+ super.connectedCallback(), this._loadDevicesWithoutPermission(), navigator.mediaDevices.addEventListener("devicechange", this._handleDeviceChange);
1136
+ }
1137
+ disconnectedCallback() {
1138
+ super.disconnectedCallback(), navigator.mediaDevices.removeEventListener("devicechange", this._handleDeviceChange), this._stopPreview();
1139
+ }
1140
+ updated(e) {
1141
+ super.updated(e), e.has("_isMenuOpen") && this._isMenuOpen && (!this._hasPermission && !this._loading ? this._loadDevicesWithPermission() : this._hasPermission && !this.muted && this._startPreview()), (e.has("_isMenuOpen") && !this._isMenuOpen || e.has("muted") && this.muted) && this._stopPreview(), e.has("muted") && !this.muted && this._isMenuOpen && this._hasPermission && this._startPreview();
1142
+ }
1143
+ render() {
1144
+ let e = this._devices.find((e) => e.deviceId === this.value) || this._devices[0] || { label: this._loading ? "Loading..." : "No microphone" };
1145
+ return n`
1146
+ <!-- Anchor Button -->
1147
+ <button
1148
+ id="anchor-button"
1149
+ class="anchor-button"
1150
+ ?disabled=${this._loading || this.disabled}
1151
+ @click=${this._toggleMenu}
1152
+ >
1153
+ <md-icon>${this.muted ? "mic_off" : "mic"}</md-icon>
1154
+ <span class="label-text">${e.label}</span>
1155
+ <md-icon style="font-size: 18px;">unfold_more</md-icon>
1156
+ </button>
1157
+
1158
+ <!-- Dropdown Menu -->
1159
+ <md-menu
1160
+ id="device-menu"
1161
+ anchor="anchor-button"
1162
+ positioning="popover"
1163
+ @closed=${() => this._isMenuOpen = !1}
1164
+ @opened=${() => this._isMenuOpen = !0}
1165
+ >
1166
+ ${this._loading ? n`<md-menu-item disabled
1167
+ ><div slot="headline">Loading devices...</div></md-menu-item
1168
+ >` : this._error ? n`<md-menu-item disabled
1169
+ ><div slot="headline" style="color: var(--md-sys-color-error)">
1170
+ ${this._error}
1171
+ </div></md-menu-item
1172
+ >` : this._devices.map((e) => n`
1173
+ <md-menu-item
1174
+ @click=${() => this._selectDevice(e.deviceId)}
1175
+ ?selected=${this.value === e.deviceId || !this.value && this._devices[0]?.deviceId === e.deviceId}
1176
+ >
1177
+ <div slot="headline">${e.label}</div>
1178
+ ${this.value === e.deviceId || !this.value && this._devices[0]?.deviceId === e.deviceId ? n`<md-icon slot="end">check</md-icon>` : ""}
1179
+ </md-menu-item>
1180
+ `)}
1181
+ ${this._devices.length > 0 ? n`
1182
+ <md-divider></md-divider>
1183
+ <div class="menu-footer">
1184
+ <md-text-button @click=${this._toggleMute}>
1185
+ <md-icon slot="icon"
1186
+ >${this.muted ? "mic_off" : "mic"}</md-icon
1187
+ >
1188
+ ${this.muted ? "Unmute" : "Mute"}
1189
+ </md-text-button>
1190
+
1191
+ <div class="preview-waveform">
1192
+ <ui-live-waveform
1193
+ .active=${this._isMenuOpen && !this.muted && this._hasPermission}
1194
+ .processing=${!1}
1195
+ .analyserNode=${this._previewAnalyser}
1196
+ .barWidth=${3}
1197
+ .barGap=${1}
1198
+ .fadeEdges=${!1}
1199
+ height="16"
1200
+ ></ui-live-waveform>
1201
+ </div>
1202
+ </div>
1203
+ ` : ""}
1204
+ </md-menu>
1205
+ `;
1206
+ }
1207
+ _toggleMenu() {
1208
+ this._menuEl && (this._menuEl.open = !this._menuEl.open, this._isMenuOpen = this._menuEl.open);
1209
+ }
1210
+ _selectDevice(e) {
1211
+ this.value = e, this.dispatchEvent(new CustomEvent("device-change", {
1212
+ detail: { deviceId: e },
1213
+ bubbles: !0,
1214
+ composed: !0
1215
+ })), this._isMenuOpen && !this.muted && this._hasPermission && this._startPreview();
1216
+ }
1217
+ _toggleMute(e) {
1218
+ e.stopPropagation(), this.muted = !this.muted, this.dispatchEvent(new CustomEvent("mute-change", {
1219
+ detail: { muted: this.muted },
1220
+ bubbles: !0,
1221
+ composed: !0
1222
+ }));
1223
+ }
1224
+ async _loadDevicesWithoutPermission() {
1225
+ try {
1226
+ this._loading = !0, this._error = null;
1227
+ let e = await navigator.mediaDevices.enumerateDevices();
1228
+ this._parseDeviceList(e);
1229
+ } catch (e) {
1230
+ this._error = e instanceof Error ? e.message : "Failed to get audio devices";
1231
+ } finally {
1232
+ this._loading = !1;
1233
+ }
1234
+ }
1235
+ async _loadDevicesWithPermission() {
1236
+ if (!this._loading) try {
1237
+ this._loading = !0, this._error = null, (await navigator.mediaDevices.getUserMedia({ audio: !0 })).getTracks().forEach((e) => e.stop());
1238
+ let e = await navigator.mediaDevices.enumerateDevices();
1239
+ this._parseDeviceList(e), this._hasPermission = !0, this._isMenuOpen && !this.muted && this._startPreview();
1240
+ } catch (e) {
1241
+ this._error = e instanceof Error ? e.message : "Permission denied";
1242
+ } finally {
1243
+ this._loading = !1;
1244
+ }
1245
+ }
1246
+ _parseDeviceList(e) {
1247
+ let t = e.filter((e) => e.kind === "audioinput").map((e) => {
1248
+ let t = e.label || "Microphone ${device.deviceId.slice(0, 8)}";
1249
+ return t = t.replace(/\s*\([^)]*\)/g, "").trim(), {
1250
+ deviceId: e.deviceId,
1251
+ label: t,
1252
+ groupId: e.groupId
1253
+ };
1254
+ });
1255
+ this._devices = t, !this.value && t.length > 0 && (this.value = t[0].deviceId, this.dispatchEvent(new CustomEvent("device-change", {
1256
+ detail: { deviceId: this.value },
1257
+ bubbles: !0,
1258
+ composed: !0
1259
+ })));
1260
+ }
1261
+ async _startPreview() {
1262
+ if (this._stopPreview(), this.value) try {
1263
+ this._previewStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: this.value } } }), this._previewAudioContext = new (window.AudioContext || window.webkitAudioContext)(), this._previewAnalyser = this._previewAudioContext.createAnalyser(), this._previewAnalyser.fftSize = 256, this._previewAnalyser.smoothingTimeConstant = .8, this._previewAudioContext.createMediaStreamSource(this._previewStream).connect(this._previewAnalyser);
1264
+ } catch (e) {
1265
+ console.warn("Failed to start preview stream", e);
1266
+ }
1267
+ }
1268
+ _stopPreview() {
1269
+ this._previewStream &&= (this._previewStream.getTracks().forEach((e) => e.stop()), void 0), this._previewAudioContext && this._previewAudioContext.state !== "closed" && (this._previewAudioContext.close(), this._previewAudioContext = void 0), this._previewAnalyser = void 0;
1270
+ }
1271
+ };
1272
+ l([i({ type: String })], A.prototype, "value", void 0), l([i({ type: Boolean })], A.prototype, "muted", void 0), l([i({ type: Boolean })], A.prototype, "disabled", void 0), l([o()], A.prototype, "_devices", void 0), l([o()], A.prototype, "_loading", void 0), l([o()], A.prototype, "_error", void 0), l([o()], A.prototype, "_hasPermission", void 0), l([o()], A.prototype, "_isMenuOpen", void 0), l([o()], A.prototype, "_previewAnalyser", void 0), l([a("md-menu")], A.prototype, "_menuEl", void 0), A = l([r("ui-mic-selector")], A);
1273
+ /**
1274
+ * Copyright 2026 Google LLC
1275
+ *
1276
+ * Licensed under the Apache License, Version 2.0 (the "License");
1277
+ * you may not use this file except in compliance with the License.
1278
+ * You may obtain a copy of the License at
1279
+ *
1280
+ * http://www.apache.org/licenses/LICENSE-2.0
1281
+ *
1282
+ * Unless required by applicable law or agreed to in writing, software
1283
+ * distributed under the License is distributed on an "AS IS" BASIS,
1284
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1285
+ * See the License for the specific language governing permissions and
1286
+ * limitations under the License.
1287
+ */
1288
+ var j = class extends e {
1289
+ constructor(...e) {
1290
+ super(...e), this.voices = [], this.placeholder = "Select a voice...", this.idKey = "voiceId", this.titleKey = "name", this.subtitleKey = "category", this.previewUrlKey = "previewUrl", this.useOrbs = !1, this.colorKey = "colors", this._searchQuery = "";
1291
+ }
1292
+ static {
1293
+ this.styles = t`
1294
+ :host {
1295
+ display: inline-block;
1296
+ width: 100%;
1297
+ font-family: inherit;
1298
+ }
1299
+
1300
+ .anchor-button {
1301
+ display: flex;
1302
+ align-items: center;
1303
+ justify-content: space-between;
1304
+ width: 100%;
1305
+ padding: 8px 16px;
1306
+ background: transparent;
1307
+ border: 1px solid var(--md-sys-color-outline, #79747e);
1308
+ border-radius: 8px;
1309
+ color: var(--md-sys-color-on-surface, #1e1e1e);
1310
+ cursor: pointer;
1311
+ font-family: inherit;
1312
+ font-size: 14px;
1313
+ min-height: 48px;
1314
+ transition:
1315
+ background-color 0.2s,
1316
+ border-color 0.2s;
1317
+ }
1318
+
1319
+ .anchor-button:hover {
1320
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
1321
+ }
1322
+
1323
+ .anchor-button:focus-visible {
1324
+ outline: none;
1325
+ border-color: var(--md-sys-color-primary, #0066cc);
1326
+ box-shadow: 0 0 0 1px var(--md-sys-color-primary, #0066cc);
1327
+ }
1328
+
1329
+ .trigger-content {
1330
+ display: flex;
1331
+ align-items: center;
1332
+ justify-content: space-between;
1333
+ width: 100%;
1334
+ min-width: 100%;
1335
+ padding: 4px 0;
1336
+ }
1337
+
1338
+ .trigger-left {
1339
+ display: flex;
1340
+ align-items: center;
1341
+ gap: 12px;
1342
+ overflow: hidden;
1343
+ }
1344
+
1345
+ .trigger-icon {
1346
+ width: 24px;
1347
+ height: 24px;
1348
+ border-radius: 50%;
1349
+ background: var(--md-sys-color-primary-container);
1350
+ color: var(--md-sys-color-on-primary-container);
1351
+ display: flex;
1352
+ align-items: center;
1353
+ justify-content: center;
1354
+ flex-shrink: 0;
1355
+ }
1356
+
1357
+ .trigger-text {
1358
+ white-space: nowrap;
1359
+ overflow: hidden;
1360
+ text-overflow: ellipsis;
1361
+ color: var(--md-sys-color-on-surface);
1362
+ }
1363
+
1364
+ md-menu {
1365
+ --md-menu-container-shape: 12px;
1366
+ --md-menu-container-color: var(--md-sys-color-surface-container, #f3f3f3);
1367
+ max-width: 400px;
1368
+ }
1369
+
1370
+ .search-container {
1371
+ padding: 8px 12px;
1372
+ background: var(--md-sys-color-surface-container, #f3f3f3);
1373
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
1374
+ }
1375
+
1376
+ md-outlined-text-field {
1377
+ width: 100%;
1378
+ --md-outlined-text-field-container-shape: 8px;
1379
+ }
1380
+
1381
+ md-menu-item {
1382
+ --md-menu-item-hover-state-layer-color: var(
1383
+ --md-sys-color-on-surface-variant
1384
+ );
1385
+ --md-menu-item-focus-state-layer-color: var(
1386
+ --md-sys-color-on-surface-variant
1387
+ );
1388
+ }
1389
+
1390
+ .voice-item-content {
1391
+ display: flex;
1392
+ align-items: center;
1393
+ gap: 16px;
1394
+ width: 100%;
1395
+ padding: 8px 0;
1396
+ }
1397
+
1398
+ .voice-avatar {
1399
+ position: relative;
1400
+ width: 32px;
1401
+ height: 32px;
1402
+ border-radius: 50%;
1403
+ background: var(--md-sys-color-surface-variant);
1404
+ display: flex;
1405
+ align-items: center;
1406
+ justify-content: center;
1407
+ flex-shrink: 0;
1408
+ cursor: pointer;
1409
+ overflow: hidden;
1410
+ color: var(--md-sys-color-on-surface-variant);
1411
+ z-index: 2; /* Keep above the menu item ripple */
1412
+ }
1413
+
1414
+ .voice-avatar:hover .play-overlay {
1415
+ opacity: 1;
1416
+ }
1417
+
1418
+ .play-overlay {
1419
+ position: absolute;
1420
+ inset: 0;
1421
+ background: rgba(0, 0, 0, 0.4);
1422
+ display: flex;
1423
+ align-items: center;
1424
+ justify-content: center;
1425
+ color: white;
1426
+ opacity: 0;
1427
+ transition: opacity 0.2s;
1428
+ border-radius: 50%;
1429
+ }
1430
+
1431
+ .play-overlay.active {
1432
+ opacity: 1;
1433
+ background: rgba(0, 0, 0, 0.6);
1434
+ }
1435
+
1436
+ .voice-info {
1437
+ display: flex;
1438
+ flex-direction: column;
1439
+ gap: 2px;
1440
+ flex: 1;
1441
+ overflow: hidden;
1442
+ }
1443
+
1444
+ .voice-name {
1445
+ font-weight: 500;
1446
+ font-size: 14px;
1447
+ white-space: nowrap;
1448
+ overflow: hidden;
1449
+ text-overflow: ellipsis;
1450
+ color: var(--md-sys-color-on-surface);
1451
+ }
1452
+
1453
+ .voice-labels {
1454
+ display: flex;
1455
+ align-items: center;
1456
+ gap: 6px;
1457
+ font-size: 12px;
1458
+ color: var(--md-sys-color-on-surface-variant);
1459
+ white-space: nowrap;
1460
+ overflow: hidden;
1461
+ text-overflow: ellipsis;
1462
+ }
1463
+
1464
+ .label-dot {
1465
+ font-size: 8px;
1466
+ }
1467
+
1468
+ .empty-state {
1469
+ padding: 24px;
1470
+ text-align: center;
1471
+ color: var(--md-sys-color-on-surface-variant);
1472
+ font-size: 14px;
1473
+ }
1474
+ `;
1475
+ }
1476
+ render() {
1477
+ let e = this.voices.find((e) => e[this.idKey] === this.value), t = this.voices.filter((e) => {
1478
+ if (!this._searchQuery) return !0;
1479
+ let t = this._searchQuery.toLowerCase();
1480
+ return e[this.titleKey].toLowerCase().includes(t) || e.labels?.accent?.toLowerCase().includes(t) || e.labels?.gender?.toLowerCase().includes(t) || e.labels?.age?.toLowerCase().includes(t);
1481
+ });
1482
+ return n`
1483
+ <!-- Hidden audio player for previews -->
1484
+ <audio
1485
+ crossorigin="anonymous"
1486
+ @ended=${() => this._previewingVoiceId = void 0}
1487
+ @pause=${() => this._previewingVoiceId = void 0}
1488
+ ></audio>
1489
+
1490
+ <!-- Anchor Button -->
1491
+ <button
1492
+ class="anchor-button"
1493
+ part="button"
1494
+ id="voice-anchor"
1495
+ @click=${this._toggleMenu}
1496
+ >
1497
+ <div class="trigger-content">
1498
+ <div class="trigger-left">
1499
+ ${e ? n`
1500
+ <div
1501
+ class="trigger-icon"
1502
+ style="${this.useOrbs ? "overflow: hidden;" : ""}"
1503
+ >
1504
+ ${this.useOrbs ? n`<ui-orb
1505
+ agentState="listening"
1506
+ .colors="${e[this.colorKey] || ["#CADCFC", "#A0B9D1"]}"
1507
+ ></ui-orb>` : n`<md-icon style="font-size: 16px;"
1508
+ >record_voice_over</md-icon
1509
+ >`}
1510
+ </div>
1511
+ <span class="trigger-text"
1512
+ >${e[this.titleKey] || e.name}</span
1513
+ >
1514
+ ` : n`
1515
+ <span
1516
+ class="trigger-text"
1517
+ style="color: var(--md-sys-color-on-surface-variant)"
1518
+ >${this.placeholder}</span
1519
+ >
1520
+ `}
1521
+ </div>
1522
+ <md-icon style="color: var(--md-sys-color-on-surface-variant);"
1523
+ >unfold_more</md-icon
1524
+ >
1525
+ </div>
1526
+ </button>
1527
+
1528
+ <!-- Dropdown Menu -->
1529
+ <md-menu
1530
+ id="voice-menu"
1531
+ anchor="voice-anchor"
1532
+ positioning="popover"
1533
+ @closed=${this._handleMenuClosed}
1534
+ >
1535
+ <!-- The click.stop modifier stops the menu from closing when searching -->
1536
+ <div
1537
+ class="search-container"
1538
+ @click=${(e) => e.stopPropagation()}
1539
+ >
1540
+ <md-outlined-text-field
1541
+ placeholder="Search voices..."
1542
+ .value=${this._searchQuery}
1543
+ @input=${(e) => this._searchQuery = e.target.value}
1544
+ >
1545
+ <md-icon slot="leading-icon">search</md-icon>
1546
+ </md-outlined-text-field>
1547
+ </div>
1548
+
1549
+ ${t.length === 0 ? n` <div class="empty-state">No voice found.</div> ` : t.map((e) => n`
1550
+ <md-menu-item
1551
+ @click=${() => this._selectVoice(e[this.idKey])}
1552
+ ?selected=${this.value === e[this.idKey]}
1553
+ >
1554
+ <div slot="headline" class="voice-item-content">
1555
+ <!-- Avatar / Preview Button -->
1556
+ <div
1557
+ class="voice-avatar"
1558
+ @click=${(t) => this._togglePreview(t, e)}
1559
+ >
1560
+ ${this.useOrbs ? n`<ui-orb
1561
+ agentState="${this._previewingVoiceId === e[this.idKey] ? "talking" : "listening"}"
1562
+ .colors="${e[this.colorKey] || ["#CADCFC", "#A0B9D1"]}"
1563
+ ></ui-orb>` : n`<md-icon style="font-size: 18px;"
1564
+ >face</md-icon
1565
+ >`}
1566
+ ${e[this.previewUrlKey] ? n`
1567
+ <div
1568
+ class="play-overlay ${this._previewingVoiceId === e[this.idKey] ? "active" : ""}"
1569
+ >
1570
+ <md-icon style="font-size: 16px;">
1571
+ ${this._previewingVoiceId === e[this.idKey] ? "pause" : "play_arrow"}
1572
+ </md-icon>
1573
+ </div>
1574
+ ` : ""}
1575
+ </div>
1576
+
1577
+ <!-- Voice Info -->
1578
+ <div class="voice-info">
1579
+ <span class="voice-name">${e[this.titleKey]}</span>
1580
+ ${e[this.subtitleKey] || e.labels ? n`
1581
+ <div class="voice-labels">
1582
+ ${e[this.subtitleKey] ? n`<span class="voice-badge"
1583
+ >${e[this.subtitleKey]}</span
1584
+ >` : Object.values(e.labels || {}).filter(Boolean).map((e) => n`<span class="voice-badge"
1585
+ >${e}</span
1586
+ >`)}
1587
+ </div>
1588
+ ` : ""}
1589
+ </div>
1590
+ </div>
1591
+
1592
+ ${this.value === e[this.idKey] ? n`<md-icon slot="end">check</md-icon>` : ""}
1593
+ </md-menu-item>
1594
+ `)}
1595
+ </md-menu>
1596
+ `;
1597
+ }
1598
+ _toggleMenu() {
1599
+ this._menuEl && (this._menuEl.open = !this._menuEl.open);
1600
+ }
1601
+ _handleMenuClosed() {
1602
+ this._stopPreview();
1603
+ }
1604
+ _selectVoice(e) {
1605
+ this.value = e, this.dispatchEvent(new CustomEvent("voice-change", {
1606
+ detail: { voiceId: e },
1607
+ bubbles: !0,
1608
+ composed: !0
1609
+ }));
1610
+ }
1611
+ _togglePreview(e, t) {
1612
+ e.stopPropagation(), e.preventDefault(), !(!t[this.previewUrlKey] || !this._audioEl) && (this._previewingVoiceId === t[this.idKey] ? this._stopPreview() : (this._audioEl.src = t[this.previewUrlKey], this._audioEl.play().catch(console.error), this._previewingVoiceId = t[this.idKey]));
1613
+ }
1614
+ _stopPreview() {
1615
+ this._audioEl && (this._audioEl.pause(), this._audioEl.currentTime = 0), this._previewingVoiceId = void 0;
1616
+ }
1617
+ };
1618
+ l([i({ type: Array })], j.prototype, "voices", void 0), l([i({ type: String })], j.prototype, "value", void 0), l([i({ type: String })], j.prototype, "placeholder", void 0), l([i({ type: String })], j.prototype, "idKey", void 0), l([i({ type: String })], j.prototype, "titleKey", void 0), l([i({ type: String })], j.prototype, "subtitleKey", void 0), l([i({ type: String })], j.prototype, "previewUrlKey", void 0), l([i({ type: Boolean })], j.prototype, "useOrbs", void 0), l([i({ type: String })], j.prototype, "colorKey", void 0), l([o()], j.prototype, "_searchQuery", void 0), l([o()], j.prototype, "_previewingVoiceId", void 0), l([a("md-menu")], j.prototype, "_menuEl", void 0), l([a("audio")], j.prototype, "_audioEl", void 0), j = l([r("ui-voice-picker")], j);
1619
+ var M = class extends e {
1620
+ constructor(...e) {
1621
+ super(...e), this.speed = 50, this.barCount = 60, this.barWidth = 4, this.barHeight = 4, this.barGap = 2, this.barRadius = 2, this.fadeEdges = !0, this.fadeWidth = 24, this.height = 128, this.active = !0, this._animationFrameId = 0, this._lastTime = 0, this._bars = [], this._seed = Math.random(), this._dataIndex = 0;
1622
+ }
1623
+ static {
1624
+ this.styles = t`
1625
+ :host {
1626
+ display: block;
1627
+ width: 100%;
1628
+ }
1629
+ .container {
1630
+ position: relative;
1631
+ width: 100%;
1632
+ overflow: hidden;
1633
+ }
1634
+ canvas {
1635
+ position: absolute;
1636
+ top: 0;
1637
+ left: 0;
1638
+ display: block;
1639
+ height: 100%;
1640
+ width: 100%;
1641
+ }
1642
+ `;
1643
+ }
1644
+ render() {
1645
+ return n`
1646
+ <div class="container" style="height: ${this.height}px;">
1647
+ <canvas></canvas>
1648
+ </div>
1649
+ `;
1650
+ }
1651
+ firstUpdated() {
1652
+ this._resizeObserver = new ResizeObserver(() => {
1653
+ this._handleResize();
1654
+ }), this._resizeObserver.observe(this._container), this._canvas && this._container && this._populateInitialBars(), this._startAnimation();
1655
+ }
1656
+ disconnectedCallback() {
1657
+ super.disconnectedCallback(), this._resizeObserver && this._resizeObserver.disconnect(), this._animationFrameId && cancelAnimationFrame(this._animationFrameId);
1658
+ }
1659
+ _handleResize() {
1660
+ if (!this._canvas || !this._container) return;
1661
+ let e = this._container.getBoundingClientRect(), t = window.devicePixelRatio || 1;
1662
+ this._canvas.width = e.width * t, this._canvas.height = e.height * t, this._canvas.style.width = `${e.width}px`, this._canvas.style.height = `${e.height}px`;
1663
+ let n = this._canvas.getContext("2d");
1664
+ n && n.scale(t, t);
1665
+ }
1666
+ _seededRandom(e) {
1667
+ let t = Math.sin(this._seed * 1e4 + e * 137.5) * 1e4;
1668
+ return t - Math.floor(t);
1669
+ }
1670
+ _populateInitialBars() {
1671
+ let e = this._container.getBoundingClientRect(), t = this.barWidth + this.barGap, n = e.width, r = 0;
1672
+ for (this._bars = []; n > -t;) this._bars.push({
1673
+ x: n,
1674
+ height: .2 + this._seededRandom(r++) * .6
1675
+ }), n -= t;
1676
+ this._bars.reverse();
1677
+ }
1678
+ _startAnimation() {
1679
+ this._lastTime = performance.now();
1680
+ let e = (t) => {
1681
+ if (!this._canvas) return;
1682
+ let n = this._canvas.getContext("2d");
1683
+ if (!n) return;
1684
+ let r = this._lastTime ? (t - this._lastTime) / 1e3 : 0;
1685
+ this._lastTime = t;
1686
+ let i = this._canvas.getBoundingClientRect();
1687
+ n.clearRect(0, 0, i.width, i.height);
1688
+ let a = this.barColor;
1689
+ a ||= getComputedStyle(this).getPropertyValue("--md-sys-color-primary").trim() || "#0066cc";
1690
+ let o = this.barWidth + this.barGap, s = this.active ? this.speed : 0;
1691
+ for (let e = 0; e < this._bars.length; e++) this._bars[e].x -= s * r, this.active || (this._bars[e].height += (.05 - this._bars[e].height) * .15);
1692
+ for (this._bars = this._bars.filter((e) => e.x + this.barWidth > -o); this._bars.length === 0 || this._bars[this._bars.length - 1].x < i.width;) {
1693
+ let e = this._bars[this._bars.length - 1], t = e ? e.x + o : i.width, n;
1694
+ if (this.data && this.data.length > 0) n = this.data[this._dataIndex % this.data.length] || .1, this._dataIndex = (this._dataIndex + 1) % this.data.length;
1695
+ else if (this.analyserNode) {
1696
+ (!this._dataArray || this._dataArray.length !== this.analyserNode.frequencyBinCount) && (this._dataArray = new Uint8Array(this.analyserNode.frequencyBinCount)), this.analyserNode.getByteFrequencyData(this._dataArray);
1697
+ let e = 0, t = Math.min(this._dataArray.length, 50);
1698
+ for (let n = 0; n < t; n++) e += this._dataArray[n];
1699
+ let r = e / t / 255;
1700
+ n = Math.max(.1, r ** 1.5 * 1.5);
1701
+ } else {
1702
+ let e = Date.now() / 1e3, t = this._bars.length + e * .01, r = Math.sin(t * .1) * .2, i = Math.cos(t * .05) * .15, a = this._seededRandom(t) * .4;
1703
+ n = Math.max(.1, Math.min(.9, .3 + r + i + a));
1704
+ }
1705
+ if (this._bars.push({
1706
+ x: t,
1707
+ height: n
1708
+ }), this._bars.length > this.barCount * 2) break;
1709
+ }
1710
+ let c = i.height / 2;
1711
+ for (let e of this._bars) if (e.x < i.width && e.x + this.barWidth > 0) {
1712
+ let t = Math.max(this.barHeight, e.height * i.height * .8), r = c - t / 2;
1713
+ n.fillStyle = a, n.globalAlpha = .3 + e.height * .7, this.barRadius > 0 ? (n.beginPath(), n.roundRect(e.x, r, this.barWidth, t, this.barRadius), n.fill()) : n.fillRect(e.x, r, this.barWidth, t);
1714
+ }
1715
+ n.globalAlpha = 1, this.fadeEdges && this.fadeWidth > 0 && f(n, i.width, i.height, this.fadeWidth), this._animationFrameId = requestAnimationFrame(e);
1716
+ };
1717
+ this._animationFrameId = requestAnimationFrame(e);
1718
+ }
1719
+ };
1720
+ l([i({ type: Number })], M.prototype, "speed", void 0), l([i({ type: Number })], M.prototype, "barCount", void 0), l([i({ type: Number })], M.prototype, "barWidth", void 0), l([i({ type: Number })], M.prototype, "barHeight", void 0), l([i({ type: Number })], M.prototype, "barGap", void 0), l([i({ type: Number })], M.prototype, "barRadius", void 0), l([i({ type: String })], M.prototype, "barColor", void 0), l([i({ type: Boolean })], M.prototype, "fadeEdges", void 0), l([i({ type: Number })], M.prototype, "fadeWidth", void 0), l([i({ type: Number })], M.prototype, "height", void 0), l([i({ type: Array })], M.prototype, "data", void 0), l([i({ attribute: !1 })], M.prototype, "analyserNode", void 0), l([i({ type: Boolean })], M.prototype, "active", void 0), l([a("canvas")], M.prototype, "_canvas", void 0), l([a(".container")], M.prototype, "_container", void 0), M = l([r("ui-scrolling-waveform")], M);
1721
+ var N = class extends e {
1722
+ constructor(...e) {
1723
+ super(...e), this.title = "Component", this.description = "", this.mode = "preview";
1724
+ }
1725
+ static {
1726
+ this.styles = t`
1727
+ :host {
1728
+ display: block;
1729
+ background: var(--md-sys-color-surface, #ffffff);
1730
+ color: var(--md-sys-color-on-surface, #1e1e1e);
1731
+ border-radius: 12px;
1732
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1733
+ transition:
1734
+ background-color 0.3s,
1735
+ color 0.3s;
1736
+ overflow: hidden;
1737
+ font-family: inherit;
1738
+ border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
1739
+ }
1740
+
1741
+ .header {
1742
+ padding: 1.5rem 2rem 1rem 2rem;
1743
+ }
1744
+
1745
+ .title {
1746
+ margin-top: 0;
1747
+ margin-bottom: 0.5rem;
1748
+ font-size: 1.4rem;
1749
+ font-weight: 600;
1750
+ }
1751
+
1752
+ .description {
1753
+ margin: 0;
1754
+ font-size: 0.95rem;
1755
+ color: var(--md-sys-color-on-surface-variant, #444444);
1756
+ line-height: 1.5;
1757
+ }
1758
+
1759
+ .tabs {
1760
+ display: flex;
1761
+ gap: 8px;
1762
+ padding: 0 2rem;
1763
+ border-bottom: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
1764
+ }
1765
+
1766
+ .tab-btn {
1767
+ padding: 8px 16px;
1768
+ background: transparent;
1769
+ border: none;
1770
+ border-bottom: 2px solid transparent;
1771
+ color: var(--md-sys-color-on-surface-variant, #444444);
1772
+ font-family: inherit;
1773
+ font-weight: 600;
1774
+ font-size: 0.9rem;
1775
+ cursor: pointer;
1776
+ transition: all 0.2s;
1777
+ }
1778
+
1779
+ .tab-btn:hover {
1780
+ color: var(--md-sys-color-primary, #0066cc);
1781
+ background: var(--md-sys-color-surface-container-highest, #e3e3e3);
1782
+ }
1783
+
1784
+ .tab-btn.active {
1785
+ color: var(--md-sys-color-primary, #0066cc);
1786
+ border-bottom-color: var(--md-sys-color-primary, #0066cc);
1787
+ }
1788
+
1789
+ .content-area {
1790
+ padding: 2rem;
1791
+ position: relative;
1792
+ background: var(--md-sys-color-surface, #ffffff);
1793
+ }
1794
+
1795
+ .preview-panel {
1796
+ display: none;
1797
+ }
1798
+
1799
+ .preview-panel.active {
1800
+ display: block;
1801
+ }
1802
+
1803
+ .code-panel {
1804
+ display: none;
1805
+ background: #1e1e1e; /* Standard terminal color */
1806
+ color: #e3e3e3;
1807
+ padding: 1.5rem;
1808
+ border-radius: 8px;
1809
+ overflow-x: auto;
1810
+ font-family: 'Courier New', Courier, monospace;
1811
+ font-size: 0.85rem;
1812
+ line-height: 1.5;
1813
+ margin: 0;
1814
+ }
1815
+
1816
+ .code-panel.active {
1817
+ display: block;
1818
+ }
1819
+ `;
1820
+ }
1821
+ render() {
1822
+ return n`
1823
+ <div class="header">
1824
+ <h2 class="title">${this.title}</h2>
1825
+ ${this.description ? n`<p class="description">${this.description}</p>` : ""}
1826
+ </div>
1827
+
1828
+ <div class="tabs">
1829
+ <button
1830
+ class="tab-btn ${this.mode === "preview" ? "active" : ""}"
1831
+ @click="${() => this.mode = "preview"}"
1832
+ >
1833
+ Preview
1834
+ </button>
1835
+ <button
1836
+ class="tab-btn ${this.mode === "code" ? "active" : ""}"
1837
+ @click="${() => this.mode = "code"}"
1838
+ >
1839
+ Code
1840
+ </button>
1841
+ </div>
1842
+
1843
+ <div class="content-area">
1844
+ <div class="preview-panel ${this.mode === "preview" ? "active" : ""}">
1845
+ <slot></slot>
1846
+ </div>
1847
+
1848
+ <pre
1849
+ class="code-panel ${this.mode === "code" ? "active" : ""}"
1850
+ ><code><slot name="code"></slot></code></pre>
1851
+ </div>
1852
+ `;
1853
+ }
1854
+ };
1855
+ l([i({ type: String })], N.prototype, "title", void 0), l([i({ type: String })], N.prototype, "description", void 0), l([i({ type: String })], N.prototype, "mode", void 0), N = l([r("ui-showcase-card")], N);
1856
+ var P = class extends e {
1857
+ constructor(...e) {
1858
+ super(...e), this.text = "", this.duration = 2, this.delay = 0, this.repeat = !0, this.repeatDelay = .5, this.startOnView = !0, this.once = !1, this.spread = 2, this._isInView = !1;
1859
+ }
1860
+ static {
1861
+ this.styles = t`
1862
+ :host {
1863
+ display: inline-block;
1864
+ font-family: inherit;
1865
+ }
1866
+
1867
+ span {
1868
+ position: relative;
1869
+ display: inline-block;
1870
+
1871
+ /* Default colors fallback to MD3 tokens if available */
1872
+ /* Use a highly transparent base color for maximum contrast against the shimmer */
1873
+ --base-color: color-mix(
1874
+ in srgb,
1875
+ var(--md-sys-color-on-surface, #1e1e1e) 20%,
1876
+ transparent
1877
+ );
1878
+ --shimmer-color: var(--md-sys-color-on-surface, #1e1e1e);
1879
+
1880
+ --shimmer-bg: linear-gradient(
1881
+ 90deg,
1882
+ transparent calc(50% - var(--spread)),
1883
+ var(--shimmer-color) 50%,
1884
+ transparent calc(50% + var(--spread))
1885
+ );
1886
+
1887
+ background-image:
1888
+ var(--shimmer-bg), linear-gradient(var(--base-color), var(--base-color));
1889
+ background-size:
1890
+ 250% 100%,
1891
+ auto; /* Important: this defines the size of the animated gradient */
1892
+ background-position: 100% center;
1893
+ background-repeat: no-repeat;
1894
+ -webkit-background-clip: text;
1895
+ background-clip: text;
1896
+ color: transparent;
1897
+ -webkit-text-fill-color: transparent;
1898
+ opacity: 0;
1899
+ transition: opacity 0.3s ease;
1900
+ }
1901
+
1902
+ /* When active, trigger the keyframe animation */
1903
+ span.active {
1904
+ opacity: 1;
1905
+ }
1906
+
1907
+ @keyframes shimmer {
1908
+ 0% {
1909
+ background-position: 100% center;
1910
+ }
1911
+ 100% {
1912
+ background-position: 0% center;
1913
+ }
1914
+ }
1915
+ `;
1916
+ }
1917
+ firstUpdated() {
1918
+ this.startOnView ? (this._intersectionObserver = new IntersectionObserver((e) => {
1919
+ e.forEach((e) => {
1920
+ e.isIntersecting ? (this._isInView = !0, this.once && this._intersectionObserver && this._intersectionObserver.disconnect()) : this.once || (this._isInView = !1);
1921
+ });
1922
+ }), this._intersectionObserver.observe(this)) : this._isInView = !0;
1923
+ }
1924
+ disconnectedCallback() {
1925
+ super.disconnectedCallback(), this._intersectionObserver && this._intersectionObserver.disconnect();
1926
+ }
1927
+ render() {
1928
+ let e = !this.startOnView || this._isInView, t = `${this.text.length * this.spread}px`, r = this.duration + this.repeatDelay, i = this.repeat ? "infinite" : "1", a = {
1929
+ "--spread": t,
1930
+ ...this.color && { "--base-color": this.color },
1931
+ ...this.shimmerColor && { "--shimmer-color": this.shimmerColor },
1932
+ "animation-name": e ? "shimmer" : "none",
1933
+ "animation-duration": `${r}s`,
1934
+ "animation-timing-function": "linear",
1935
+ "animation-delay": `${this.delay}s`,
1936
+ "animation-iteration-count": i,
1937
+ "background-position": e && !this.repeat ? "0% center" : "100% center"
1938
+ }, o = Object.entries(a).map(([e, t]) => `${e}: ${t}`).join("; ");
1939
+ return n`
1940
+ <span class="${e ? "active" : ""}" style="${o}">
1941
+ ${this.text}
1942
+ </span>
1943
+ `;
1944
+ }
1945
+ };
1946
+ l([i({ type: String })], P.prototype, "text", void 0), l([i({ type: Number })], P.prototype, "duration", void 0), l([i({ type: Number })], P.prototype, "delay", void 0), l([i({ type: Boolean })], P.prototype, "repeat", void 0), l([i({ type: Number })], P.prototype, "repeatDelay", void 0), l([i({ type: Boolean })], P.prototype, "startOnView", void 0), l([i({ type: Boolean })], P.prototype, "once", void 0), l([i({ type: Number })], P.prototype, "spread", void 0), l([i({ type: String })], P.prototype, "color", void 0), l([i({ type: String })], P.prototype, "shimmerColor", void 0), l([o()], P.prototype, "_isInView", void 0), P = l([r("ui-shimmering-text")], P);
1947
+ var F = class extends e {
1948
+ constructor(...e) {
1949
+ super(...e), this.agentState = null, this.inputVolume = 0, this.outputVolume = 0, this.volumeMode = "auto", this.seed = Math.floor(Math.random() * 2 ** 32), this._animationFrameId = 0, this._animSpeed = .1, this._curIn = 0, this._curOut = 0, this._textureLoader = new c.TextureLoader(), this._lastTime = 0, this._vertexShader = "\nuniform float uTime;\nuniform sampler2D uPerlinTexture;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n", this._fragmentShader = "\nuniform float uTime;\nuniform float uAnimation;\nuniform float uInverted;\nuniform float uOffsets[7];\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform float uInputVolume;\nuniform float uOutputVolume;\nuniform float uOpacity;\nuniform sampler2D uPerlinTexture;\nvarying vec2 vUv;\n\nconst float PI = 3.14159265358979323846;\n\nbool drawOval(vec2 polarUv, vec2 polarCenter, float a, float b, bool reverseGradient, float softness, out vec4 color) {\n vec2 p = polarUv - polarCenter;\n float oval = (p.x * p.x) / (a * a) + (p.y * p.y) / (b * b);\n float edge = smoothstep(1.0, 1.0 - softness, oval);\n if (edge > 0.0) {\n float gradient = reverseGradient ? (1.0 - (p.x / a + 1.0) / 2.0) : ((p.x / a + 1.0) / 2.0);\n gradient = mix(0.5, gradient, 0.1);\n color = vec4(vec3(gradient), 0.85 * edge);\n return true;\n }\n return false;\n}\n\nvec3 colorRamp(float grayscale, vec3 color1, vec3 color2, vec3 color3, vec3 color4) {\n if (grayscale < 0.33) {\n return mix(color1, color2, grayscale * 3.0);\n } else if (grayscale < 0.66) {\n return mix(color2, color3, (grayscale - 0.33) * 3.0);\n } else {\n return mix(color3, color4, (grayscale - 0.66) * 3.0);\n }\n}\n\nvec2 hash2(vec2 p) {\n return fract(sin(vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)))) * 43758.5453);\n}\n\nfloat noise2D(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float n = mix(\n mix(dot(hash2(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),\n dot(hash2(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),\n mix(dot(hash2(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),\n dot(hash2(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x),\n u.y\n );\n return 0.5 + 0.5 * n;\n}\n\nfloat sharpRing(vec3 decomposed, float time) {\n float ringStart = 1.0;\n float ringWidth = 0.3;\n float noiseScale = 5.0;\n float noise = mix(\n noise2D(vec2(decomposed.x, time) * noiseScale),\n noise2D(vec2(decomposed.y, time) * noiseScale),\n decomposed.z\n );\n noise = (noise - 0.5) * 2.5;\n return ringStart + noise * ringWidth * 1.5;\n}\n\nfloat smoothRing(vec3 decomposed, float time) {\n float ringStart = 0.9;\n float ringWidth = 0.2;\n float noiseScale = 6.0;\n float noise = mix(\n noise2D(vec2(decomposed.x, time) * noiseScale),\n noise2D(vec2(decomposed.y, time) * noiseScale),\n decomposed.z\n );\n noise = (noise - 0.5) * 5.0;\n return ringStart + noise * ringWidth;\n}\n\nfloat flow(vec3 decomposed, float time) {\n return mix(\n texture(uPerlinTexture, vec2(time, decomposed.x / 2.0)).r,\n texture(uPerlinTexture, vec2(time, decomposed.y / 2.0)).r,\n decomposed.z\n );\n}\n\nvoid main() {\n vec2 uv = vUv * 2.0 - 1.0;\n float radius = length(uv);\n float theta = atan(uv.y, uv.x);\n if (theta < 0.0) theta += 2.0 * PI;\n\n vec3 decomposed = vec3(\n theta / (2.0 * PI),\n mod(theta / (2.0 * PI) + 0.5, 1.0) + 1.0,\n abs(theta / PI - 1.0)\n );\n\n float noise = flow(decomposed, radius * 0.03 - uAnimation * 0.2) - 0.5;\n theta += noise * mix(0.08, 0.25, uOutputVolume);\n\n vec4 color = vec4(1.0, 1.0, 1.0, 1.0);\n float originalCenters[7] = float[7](0.0, 0.5 * PI, 1.0 * PI, 1.5 * PI, 2.0 * PI, 2.5 * PI, 3.0 * PI);\n float centers[7];\n for (int i = 0; i < 7; i++) {\n centers[i] = originalCenters[i] + 0.5 * sin(uTime / 20.0 + uOffsets[i]);\n }\n\n float a, b;\n vec4 ovalColor;\n\n for (int i = 0; i < 7; i++) {\n float noise = texture(uPerlinTexture, vec2(mod(centers[i] + uTime * 0.05, 1.0), 0.5)).r;\n a = 0.5 + noise * 0.3;\n b = noise * mix(3.5, 2.5, uInputVolume);\n bool reverseGradient = (i % 2 == 1);\n float distTheta = min(\n abs(theta - centers[i]),\n min(abs(theta + 2.0 * PI - centers[i]), abs(theta - 2.0 * PI - centers[i]))\n );\n if (drawOval(vec2(distTheta, radius), vec2(0.0, 0.0), a, b, reverseGradient, 0.6, ovalColor)) {\n color.rgb = mix(color.rgb, ovalColor.rgb, ovalColor.a);\n color.a = max(color.a, ovalColor.a);\n }\n }\n \n float ringRadius1 = sharpRing(decomposed, uTime * 0.1);\n float ringRadius2 = smoothRing(decomposed, uTime * 0.1);\n float inputRadius1 = radius + uInputVolume * 0.2;\n float inputRadius2 = radius + uInputVolume * 0.15;\n float opacity1 = mix(0.2, 0.6, uInputVolume);\n float opacity2 = mix(0.15, 0.45, uInputVolume);\n\n float ringAlpha1 = (inputRadius2 >= ringRadius1) ? opacity1 : 0.0;\n float ringAlpha2 = smoothstep(ringRadius2 - 0.05, ringRadius2 + 0.05, inputRadius1) * opacity2;\n float totalRingAlpha = max(ringAlpha1, ringAlpha2);\n \n vec3 ringColor = vec3(1.0);\n color.rgb = 1.0 - (1.0 - color.rgb) * (1.0 - ringColor * totalRingAlpha);\n\n vec3 color1 = vec3(0.0, 0.0, 0.0);\n vec3 color2 = uColor1;\n vec3 color3 = uColor2;\n vec3 color4 = vec3(1.0, 1.0, 1.0);\n\n float luminance = mix(color.r, 1.0 - color.r, uInverted);\n color.rgb = colorRamp(luminance, color1, color2, color3, color4);\n color.a *= uOpacity;\n\n gl_FragColor = color;\n}\n";
1950
+ }
1951
+ static {
1952
+ this.styles = t`
1953
+ :host {
1954
+ display: block;
1955
+ width: 100%;
1956
+ height: 100%;
1957
+ position: relative;
1958
+ }
1959
+ .container {
1960
+ width: 100%;
1961
+ height: 100%;
1962
+ }
1963
+ canvas {
1964
+ display: block;
1965
+ width: 100%;
1966
+ height: 100%;
1967
+ }
1968
+ `;
1969
+ }
1970
+ render() {
1971
+ return n`<div class="container"></div>`;
1972
+ }
1973
+ firstUpdated() {
1974
+ this._initThree();
1975
+ }
1976
+ updated(e) {
1977
+ e.has("colors") && this._updateColors();
1978
+ }
1979
+ _updateColors() {
1980
+ if (!(!this._targetColor1 || !this._targetColor2)) if (this.colors && this.colors.length === 2) this._targetColor1.set(this.colors[0]), this._targetColor2.set(this.colors[1]);
1981
+ else {
1982
+ let e = getComputedStyle(this), t = e.getPropertyValue("--md-sys-color-primary").trim() || "#CADCFC", n = e.getPropertyValue("--md-sys-color-secondary").trim() || "#A0B9D1";
1983
+ this._targetColor1.set(t), this._targetColor2.set(n);
1984
+ }
1985
+ }
1986
+ disconnectedCallback() {
1987
+ super.disconnectedCallback(), this._animationFrameId && cancelAnimationFrame(this._animationFrameId), this._resizeObserver && this._resizeObserver.disconnect(), this._renderer && this._renderer.dispose(), this._mesh && (this._mesh.geometry.dispose(), this._mesh.material.dispose());
1988
+ }
1989
+ async _initThree() {
1990
+ if (!this._container) return;
1991
+ this._targetColor1 = new c.Color(), this._targetColor2 = new c.Color(), this._updateColors();
1992
+ try {
1993
+ this._perlinNoiseTexture = await this._textureLoader.loadAsync("https://storage.googleapis.com/eleven-public-cdn/images/perlin-noise.png"), this._perlinNoiseTexture.wrapS = c.RepeatWrapping, this._perlinNoiseTexture.wrapT = c.RepeatWrapping;
1994
+ } catch (e) {
1995
+ console.warn("Failed to load perlin noise texture for orb.", e);
1996
+ return;
1997
+ }
1998
+ let e = this._container.clientWidth, t = this._container.clientHeight;
1999
+ this._scene = new c.Scene(), this._camera = new c.OrthographicCamera(-5, 5, 5, -5, .1, 10), this._camera.position.z = 1, this._renderer = new c.WebGLRenderer({
2000
+ alpha: !0,
2001
+ antialias: !0,
2002
+ premultipliedAlpha: !0
2003
+ }), this._renderer.setSize(e, t), this._renderer.setPixelRatio(window.devicePixelRatio), this._container.appendChild(this._renderer.domElement);
2004
+ let n = this._splitmix32(this.seed), r = new Float32Array(Array.from({ length: 7 }, () => n() * Math.PI * 2)), i = document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches, a = {
2005
+ uColor1: new c.Uniform(this._targetColor1),
2006
+ uColor2: new c.Uniform(this._targetColor2),
2007
+ uOffsets: { value: r },
2008
+ uPerlinTexture: new c.Uniform(this._perlinNoiseTexture),
2009
+ uTime: new c.Uniform(0),
2010
+ uAnimation: new c.Uniform(.1),
2011
+ uInverted: new c.Uniform(i ? 1 : 0),
2012
+ uInputVolume: new c.Uniform(0),
2013
+ uOutputVolume: new c.Uniform(0),
2014
+ uOpacity: new c.Uniform(0)
2015
+ }, o = new c.CircleGeometry(3.5, 64), s = new c.ShaderMaterial({
2016
+ uniforms: a,
2017
+ vertexShader: this._vertexShader,
2018
+ fragmentShader: this._fragmentShader,
2019
+ transparent: !0
2020
+ });
2021
+ this._mesh = new c.Mesh(o, s), this._scene.add(this._mesh), this._resizeObserver = new ResizeObserver(() => {
2022
+ this._container && this._renderer && this._renderer.setSize(this._container.clientWidth, this._container.clientHeight);
2023
+ }), this._resizeObserver.observe(this._container), new MutationObserver(() => {
2024
+ if (!this._mesh) return;
2025
+ let e = document.documentElement.classList.contains("dark");
2026
+ this._mesh.material.uniforms.uInverted.value = e ? 1 : 0, this._updateColors();
2027
+ }).observe(document.documentElement, {
2028
+ attributes: !0,
2029
+ attributeFilter: ["class"]
2030
+ }), this._lastTime = performance.now(), this._animate();
2031
+ }
2032
+ _animate() {
2033
+ if (this._animationFrameId = requestAnimationFrame(() => this._animate()), !this._mesh || !this._renderer || !this._scene || !this._camera) return;
2034
+ let e = performance.now(), t = (e - this._lastTime) / 1e3;
2035
+ this._lastTime = e;
2036
+ let n = this._mesh.material.uniforms;
2037
+ n.uTime.value += t * .5, n.uOpacity.value < 1 && (n.uOpacity.value = Math.min(1, n.uOpacity.value + t * 2));
2038
+ let r = 0, i = .3;
2039
+ if (this.volumeMode === "manual") r = this._clamp01(this.inputVolume), i = this._clamp01(this.outputVolume);
2040
+ else {
2041
+ let e = n.uTime.value * 2;
2042
+ if (this.agentState === null) r = 0, i = .3;
2043
+ else if (this.agentState === "listening") r = this._clamp01(.55 + Math.sin(e * 3.2) * .35), i = .45;
2044
+ else if (this.agentState === "talking") r = this._clamp01(.65 + Math.sin(e * 4.8) * .22), i = this._clamp01(.75 + Math.sin(e * 3.6) * .22);
2045
+ else {
2046
+ let t = .38 + .07 * Math.sin(e * .7), n = .05 * Math.sin(e * 2.1) * Math.sin(e * .37 + 1.2);
2047
+ r = this._clamp01(t + n), i = this._clamp01(.48 + .12 * Math.sin(e * 1.05 + .6));
2048
+ }
2049
+ }
2050
+ this._curIn += (r - this._curIn) * .2, this._curOut += (i - this._curOut) * .2;
2051
+ let a = .1 + (1 - (this._curOut - 1) ** 2) * .9;
2052
+ this._animSpeed += (a - this._animSpeed) * .12, n.uAnimation.value += t * this._animSpeed, n.uInputVolume.value = this._curIn, n.uOutputVolume.value = this._curOut, n.uColor1.value.lerp(this._targetColor1, .08), n.uColor2.value.lerp(this._targetColor2, .08), this._renderer.render(this._scene, this._camera);
2053
+ }
2054
+ _splitmix32(e) {
2055
+ return function() {
2056
+ e |= 0, e = e + 2654435769 | 0;
2057
+ let t = e ^ e >>> 16;
2058
+ return t = Math.imul(t, 569420461), t ^= t >>> 15, t = Math.imul(t, 1935289751), ((t ^= t >>> 15) >>> 0) / 4294967296;
2059
+ };
2060
+ }
2061
+ _clamp01(e) {
2062
+ return Number.isFinite(e) ? Math.min(1, Math.max(0, e)) : 0;
2063
+ }
2064
+ };
2065
+ l([i({ type: Array })], F.prototype, "colors", void 0), l([i({ type: String })], F.prototype, "agentState", void 0), l([i({ type: Number })], F.prototype, "inputVolume", void 0), l([i({ type: Number })], F.prototype, "outputVolume", void 0), l([i({ type: String })], F.prototype, "volumeMode", void 0), l([i({ type: Number })], F.prototype, "seed", void 0), l([a(".container")], F.prototype, "_container", void 0), F = l([r("ui-orb")], F);
2066
+ var I = class extends e {
2067
+ static {
2068
+ this.styles = t`
2069
+ :host {
2070
+ display: flex;
2071
+ align-items: center;
2072
+ gap: 8px;
2073
+ width: 100%;
2074
+ box-sizing: border-box;
2075
+ }
2076
+
2077
+ md-slider {
2078
+ flex: 1;
2079
+ min-width: 0; /* Prevent flex overflow */
2080
+ width: 100%;
2081
+ --md-slider-inactive-track-color: var(
2082
+ --md-sys-color-outline-variant,
2083
+ #c4c7c5
2084
+ );
2085
+ }
2086
+
2087
+ md-icon-button {
2088
+ color: var(--md-sys-color-on-surface-variant, #444);
2089
+ }
2090
+ `;
2091
+ }
2092
+ render() {
2093
+ let e = this.playerState?.volume ?? 1, t = this.playerState?.muted ?? !1, r = "volume_up";
2094
+ return t || e === 0 ? r = "volume_off" : e < .5 && (r = "volume_down"), n`
2095
+ <md-icon-button @click="${this._toggleMute}" part="button">
2096
+ <md-icon>${r}</md-icon>
2097
+ </md-icon-button>
2098
+ <md-slider
2099
+ part="slider"
2100
+ min="0"
2101
+ max="1"
2102
+ value="${t ? 0 : e}"
2103
+ step="0.01"
2104
+ ?disabled="${!this.playerState?.src}"
2105
+ @input="${this._handleInput}"
2106
+ ></md-slider>
2107
+ `;
2108
+ }
2109
+ _handleInput(e) {
2110
+ let t = e.target;
2111
+ this.playerState && this.playerState.setVolume(t.value);
2112
+ }
2113
+ _toggleMute() {
2114
+ this.playerState && this.playerState.toggleMute();
2115
+ }
2116
+ };
2117
+ l([C({
2118
+ context: w,
2119
+ subscribe: !0
2120
+ }), i({ attribute: !1 })], I.prototype, "playerState", void 0), I = l([r("ui-audio-volume-slider")], I);
2121
+ export { u as ScreamVoiceButton, E as UiAudioPlayButton, k as UiAudioPlayer, D as UiAudioProgressSlider, T as UiAudioProvider, O as UiAudioTimeDisplay, I as UiAudioVolumeSlider, p as UiLiveWaveform, A as UiMicSelector, F as UiOrb, M as UiScrollingWaveform, P as UiShimmeringText, N as UiShowcaseCard, m as UiVoiceButton, j as UiVoicePicker, h as UiWaveform, w as audioPlayerContext };